Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b0139a824f
commit
e7b262a4c5
|
@ -1501,6 +1501,12 @@
|
|||
changes: ["vendor/gems/ipynbdiff/**/*"]
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
||||
.vendor:rules:omniauth-gitlab:
|
||||
rules:
|
||||
- <<: *if-merge-request
|
||||
changes: ["vendor/gems/omniauth-gitlab/**/*"]
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
||||
##################
|
||||
# Releases rules #
|
||||
##################
|
||||
|
|
|
@ -5,6 +5,7 @@ vendor mail-smtp_pool:
|
|||
trigger:
|
||||
include: vendor/gems/mail-smtp_pool/.gitlab-ci.yml
|
||||
strategy: depend
|
||||
|
||||
vendor ipynbdiff:
|
||||
extends:
|
||||
- .vendor:rules:ipynbdiff
|
||||
|
@ -12,3 +13,11 @@ vendor ipynbdiff:
|
|||
trigger:
|
||||
include: vendor/gems/ipynbdiff/.gitlab-ci.yml
|
||||
strategy: depend
|
||||
|
||||
vendor omniauth-gitlab:
|
||||
extends:
|
||||
- .vendor:rules:omniauth-gitlab
|
||||
needs: []
|
||||
trigger:
|
||||
include: vendor/gems/omniauth-gitlab/.gitlab-ci.yml
|
||||
strategy: depend
|
||||
|
|
|
@ -88,7 +88,6 @@ Layout/LineLength:
|
|||
- 'app/controllers/projects/issues_controller.rb'
|
||||
- 'app/controllers/projects/jobs_controller.rb'
|
||||
- 'app/controllers/projects/labels_controller.rb'
|
||||
- 'app/controllers/projects/logs_controller.rb'
|
||||
- 'app/controllers/projects/merge_requests/conflicts_controller.rb'
|
||||
- 'app/controllers/projects/merge_requests/creations_controller.rb'
|
||||
- 'app/controllers/projects/merge_requests/diffs_controller.rb'
|
||||
|
@ -696,8 +695,6 @@ Layout/LineLength:
|
|||
- 'app/services/pages/migrate_legacy_storage_to_deployment_service.rb'
|
||||
- 'app/services/personal_access_tokens/create_service.rb'
|
||||
- 'app/services/personal_access_tokens/revoke_service.rb'
|
||||
- 'app/services/pod_logs/elasticsearch_service.rb'
|
||||
- 'app/services/pod_logs/kubernetes_service.rb'
|
||||
- 'app/services/projects/branches_by_mode_service.rb'
|
||||
- 'app/services/projects/container_repository/cleanup_tags_service.rb'
|
||||
- 'app/services/projects/container_repository/gitlab/delete_tags_service.rb'
|
||||
|
@ -3485,7 +3482,6 @@ Layout/LineLength:
|
|||
- 'lib/gitlab/diff/highlight_cache.rb'
|
||||
- 'lib/gitlab/diff/parser.rb'
|
||||
- 'lib/gitlab/diff/rendered/notebook/diff_file.rb'
|
||||
- 'lib/gitlab/elasticsearch/logs/lines.rb'
|
||||
- 'lib/gitlab/email/failure_handler.rb'
|
||||
- 'lib/gitlab/email/handler/create_issue_handler.rb'
|
||||
- 'lib/gitlab/email/handler/create_merge_request_handler.rb'
|
||||
|
@ -5007,7 +5003,6 @@ Layout/LineLength:
|
|||
- 'spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb'
|
||||
- 'spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb'
|
||||
- 'spec/lib/gitlab/diff/suggestion_spec.rb'
|
||||
- 'spec/lib/gitlab/elasticsearch/logs/lines_spec.rb'
|
||||
- 'spec/lib/gitlab/email/failure_handler_spec.rb'
|
||||
- 'spec/lib/gitlab/email/handler/create_issue_handler_spec.rb'
|
||||
- 'spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb'
|
||||
|
@ -6090,8 +6085,6 @@ Layout/LineLength:
|
|||
- 'spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb'
|
||||
- 'spec/services/personal_access_tokens/create_service_spec.rb'
|
||||
- 'spec/services/personal_access_tokens/revoke_service_spec.rb'
|
||||
- 'spec/services/pod_logs/elasticsearch_service_spec.rb'
|
||||
- 'spec/services/pod_logs/kubernetes_service_spec.rb'
|
||||
- 'spec/services/post_receive_service_spec.rb'
|
||||
- 'spec/services/projects/apple_target_platform_detector_service_spec.rb'
|
||||
- 'spec/services/projects/autocomplete_service_spec.rb'
|
||||
|
|
|
@ -1471,7 +1471,6 @@ RSpec/ContextWording:
|
|||
- 'spec/features/ics/project_issues_spec.rb'
|
||||
- 'spec/features/ide/clientside_preview_csp_spec.rb'
|
||||
- 'spec/features/ide/static_object_external_storage_csp_spec.rb'
|
||||
- 'spec/features/incidents/incident_details_spec.rb'
|
||||
- 'spec/features/incidents/user_creates_new_incident_spec.rb'
|
||||
- 'spec/features/invites_spec.rb'
|
||||
- 'spec/features/issuables/markdown_references/internal_references_spec.rb'
|
||||
|
|
|
@ -23,7 +23,6 @@ RSpec/RepeatedExampleGroupBody:
|
|||
- 'spec/controllers/projects/blob_controller_spec.rb'
|
||||
- 'spec/controllers/projects/graphs_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/repositories_controller_spec.rb'
|
||||
- 'spec/features/incidents/incident_details_spec.rb'
|
||||
- 'spec/features/issues/spam_akismet_issue_creation_spec.rb'
|
||||
- 'spec/features/merge_request/user_sees_closing_issues_message_spec.rb'
|
||||
- 'spec/features/projects/commit/cherry_pick_spec.rb'
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -44,7 +44,7 @@ gem 'omniauth-dingtalk-oauth2', '~> 1.0'
|
|||
gem 'omniauth-alicloud', '~> 1.0.1'
|
||||
gem 'omniauth-facebook', '~> 4.0.0'
|
||||
gem 'omniauth-github', '~> 1.4'
|
||||
gem 'omniauth-gitlab', '~> 1.0.2'
|
||||
gem 'omniauth-gitlab', '~> 4.0.0', path: 'vendor/gems/omniauth-gitlab' # See vendor/gems/omniauth-gitlab/README.md
|
||||
gem 'omniauth-google-oauth2', '~> 0.6.0'
|
||||
gem 'omniauth-oauth2-generic', '~> 0.2.2'
|
||||
gem 'omniauth-saml', '~> 1.10'
|
||||
|
@ -407,7 +407,7 @@ group :development, :test do
|
|||
end
|
||||
|
||||
group :development, :test, :danger do
|
||||
gem 'gitlab-dangerfiles', '~> 3.4.1', require: false
|
||||
gem 'gitlab-dangerfiles', '~> 3.4.2', require: false
|
||||
end
|
||||
|
||||
group :development, :test, :coverage do
|
||||
|
|
16
Gemfile.lock
16
Gemfile.lock
|
@ -12,6 +12,13 @@ PATH
|
|||
connection_pool (~> 2.0)
|
||||
mail (~> 2.7)
|
||||
|
||||
PATH
|
||||
remote: vendor/gems/omniauth-gitlab
|
||||
specs:
|
||||
omniauth-gitlab (4.0.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.7.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
|
@ -482,7 +489,7 @@ GEM
|
|||
terminal-table (~> 1.5, >= 1.5.1)
|
||||
gitlab-chronic (0.10.5)
|
||||
numerizer (~> 0.2)
|
||||
gitlab-dangerfiles (3.4.1)
|
||||
gitlab-dangerfiles (3.4.2)
|
||||
danger (>= 8.4.5)
|
||||
danger-gitlab (>= 8.0.0)
|
||||
rake
|
||||
|
@ -872,9 +879,6 @@ GEM
|
|||
omniauth-github (1.4.0)
|
||||
omniauth (~> 1.5)
|
||||
omniauth-oauth2 (>= 1.4.0, < 2.0)
|
||||
omniauth-gitlab (1.0.3)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.0)
|
||||
omniauth-google-oauth2 (0.6.0)
|
||||
jwt (>= 2.0)
|
||||
omniauth (>= 1.1.1)
|
||||
|
@ -1538,7 +1542,7 @@ DEPENDENCIES
|
|||
gitaly (~> 15.1.0.pre.rc1)
|
||||
github-markup (~> 1.7.0)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-dangerfiles (~> 3.4.1)
|
||||
gitlab-dangerfiles (~> 3.4.2)
|
||||
gitlab-experiment (~> 0.7.1)
|
||||
gitlab-fog-azure-rm (~> 1.3.0)
|
||||
gitlab-labkit (~> 0.23.0)
|
||||
|
@ -1623,7 +1627,7 @@ DEPENDENCIES
|
|||
omniauth-dingtalk-oauth2 (~> 1.0)
|
||||
omniauth-facebook (~> 4.0.0)
|
||||
omniauth-github (~> 1.4)
|
||||
omniauth-gitlab (~> 1.0.2)
|
||||
omniauth-gitlab (~> 4.0.0)!
|
||||
omniauth-google-oauth2 (~> 0.6.0)
|
||||
omniauth-oauth2-generic (~> 0.2.2)
|
||||
omniauth-salesforce (~> 1.0.5)
|
||||
|
|
|
@ -98,9 +98,9 @@ export default class Renderer {
|
|||
requestAnimationFrame(this.renderWrapper);
|
||||
}
|
||||
|
||||
changeObjectMaterials(type) {
|
||||
changeObjectMaterials(material) {
|
||||
this.objects.forEach((obj) => {
|
||||
obj.changeMaterial(type);
|
||||
obj.changeMaterial(material);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export default class MeshObject extends Mesh {
|
|||
}
|
||||
}
|
||||
|
||||
changeMaterial(type) {
|
||||
this.material = materials[type];
|
||||
changeMaterial(materialKey) {
|
||||
this.material = materials[materialKey];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@ export default () => {
|
|||
|
||||
[].slice.call(document.querySelectorAll('.js-material-changer')).forEach((el) => {
|
||||
el.addEventListener('click', (e) => {
|
||||
const { target } = e;
|
||||
const { currentTarget } = e;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
document.querySelector('.js-material-changer.selected').classList.remove('selected');
|
||||
target.classList.add('selected');
|
||||
target.blur();
|
||||
currentTarget.classList.add('selected');
|
||||
currentTarget.blur();
|
||||
|
||||
viewer.changeObjectMaterials(target.dataset.type);
|
||||
viewer.changeObjectMaterials(currentTarget.dataset.material);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
"WorkItemWidget": [
|
||||
"WorkItemWidgetAssignees",
|
||||
"WorkItemWidgetDescription",
|
||||
"WorkItemWidgetHierarchy"
|
||||
"WorkItemWidgetHierarchy",
|
||||
"WorkItemWidgetWeight"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export default () => {
|
|||
deleteAccountModal,
|
||||
},
|
||||
mounted() {
|
||||
deleteAccountButton.classList.remove('disabled');
|
||||
deleteAccountButton.disabled = false;
|
||||
deleteAccountButton.addEventListener('click', () => {
|
||||
this.$root.$emit(BV_SHOW_MODAL, 'delete-account-modal', '#delete-account-button');
|
||||
});
|
||||
|
|
|
@ -18,6 +18,9 @@ module Mutations
|
|||
argument :description_widget, ::Types::WorkItems::Widgets::DescriptionInputType,
|
||||
required: false,
|
||||
description: 'Input for description widget.'
|
||||
argument :weight_widget, ::Types::WorkItems::Widgets::WeightInputType,
|
||||
required: false,
|
||||
description: 'Input for weight widget.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,8 @@ module Types
|
|||
::Types::WorkItems::Widgets::HierarchyType
|
||||
when ::WorkItems::Widgets::Assignees
|
||||
::Types::WorkItems::Widgets::AssigneesType
|
||||
when ::WorkItems::Widgets::Weight
|
||||
::Types::WorkItems::Widgets::WeightType
|
||||
else
|
||||
raise "Unknown GraphQL type for widget #{object}"
|
||||
end
|
||||
|
@ -25,7 +27,8 @@ module Types
|
|||
|
||||
orphan_types ::Types::WorkItems::Widgets::DescriptionType,
|
||||
::Types::WorkItems::Widgets::HierarchyType,
|
||||
::Types::WorkItems::Widgets::AssigneesType
|
||||
::Types::WorkItems::Widgets::AssigneesType,
|
||||
::Types::WorkItems::Widgets::WeightType
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module WorkItems
|
||||
module Widgets
|
||||
class WeightInputType < BaseInputObject
|
||||
graphql_name 'WorkItemWidgetWeightInput'
|
||||
|
||||
argument :weight, GraphQL::Types::Int,
|
||||
required: true,
|
||||
description: 'Weight of the work item.'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module WorkItems
|
||||
module Widgets
|
||||
# Disabling widget level authorization as it might be too granular
|
||||
# and we already authorize the parent work item
|
||||
# rubocop:disable Graphql/AuthorizeTypes
|
||||
class WeightType < BaseObject
|
||||
graphql_name 'WorkItemWidgetWeight'
|
||||
description 'Represents a weight widget'
|
||||
|
||||
implements Types::WorkItems::WidgetInterface
|
||||
|
||||
field :weight, GraphQL::Types::Int, null: true,
|
||||
description: 'Weight of the work item.'
|
||||
end
|
||||
# rubocop:enable Graphql/AuthorizeTypes
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,6 +26,13 @@ class Ability
|
|||
end
|
||||
end
|
||||
|
||||
# A list of users that can read confidential notes in a project
|
||||
def users_that_can_read_internal_notes(users, note_parent)
|
||||
DeclarativePolicy.subject_scope do
|
||||
users.select { |u| allowed?(u, :reporter_access, note_parent) }
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an Array of Issues that can be read by the given user.
|
||||
#
|
||||
# issues - The issues to reduce down to those readable by the user.
|
||||
|
|
|
@ -172,7 +172,7 @@ module CacheMarkdownField
|
|||
refs = all_references(self.author)
|
||||
|
||||
references = {}
|
||||
references[:mentioned_users_ids] = refs.mentioned_user_ids.presence
|
||||
references[:mentioned_users_ids] = mentioned_filtered_user_ids_for(refs)
|
||||
references[:mentioned_groups_ids] = refs.mentioned_group_ids.presence
|
||||
references[:mentioned_projects_ids] = refs.mentioned_project_ids.presence
|
||||
|
||||
|
@ -185,6 +185,13 @@ module CacheMarkdownField
|
|||
true
|
||||
end
|
||||
|
||||
# Overriden on objects that needs to filter
|
||||
# mentioned users that cannot read them, for example,
|
||||
# guest users that are referenced on a confidential note.
|
||||
def mentioned_filtered_user_ids_for(refs)
|
||||
refs.mentioned_user_ids.presence
|
||||
end
|
||||
|
||||
def mentionable_attributes_changed?(changes = saved_changes)
|
||||
return false unless is_a?(Mentionable)
|
||||
|
||||
|
|
|
@ -92,7 +92,13 @@ module Participable
|
|||
end
|
||||
|
||||
def raw_participants(current_user = nil, verify_access: false)
|
||||
ext = Gitlab::ReferenceExtractor.new(project, current_user)
|
||||
extractor = Gitlab::ReferenceExtractor.new(project, current_user)
|
||||
|
||||
# Used to extract references from confidential notes.
|
||||
# Referenced users that cannot read confidential notes are
|
||||
# later removed from participants array.
|
||||
internal_notes_extractor = Gitlab::ReferenceExtractor.new(project, current_user)
|
||||
|
||||
participants = Set.new
|
||||
process = [self]
|
||||
|
||||
|
@ -107,6 +113,8 @@ module Participable
|
|||
|
||||
source.class.participant_attrs.each do |attr|
|
||||
if attr.respond_to?(:call)
|
||||
ext = use_internal_notes_extractor_for?(source) ? internal_notes_extractor : extractor
|
||||
|
||||
source.instance_exec(current_user, ext, &attr)
|
||||
else
|
||||
process << source.__send__(attr) # rubocop:disable GitlabSecurity/PublicSend
|
||||
|
@ -121,7 +129,18 @@ module Participable
|
|||
end
|
||||
end
|
||||
|
||||
participants.merge(ext.users)
|
||||
participants.merge(users_that_can_read_internal_notes(internal_notes_extractor))
|
||||
participants.merge(extractor.users)
|
||||
end
|
||||
|
||||
def use_internal_notes_extractor_for?(source)
|
||||
source.is_a?(Note) && source.confidential?
|
||||
end
|
||||
|
||||
def users_that_can_read_internal_notes(extractor)
|
||||
return [] unless self.is_a?(Noteable) && self.try(:resource_parent)
|
||||
|
||||
Ability.users_that_can_read_internal_notes(extractor.users, self.resource_parent)
|
||||
end
|
||||
|
||||
def source_visible_to_user?(source, user)
|
||||
|
|
|
@ -665,6 +665,25 @@ class Note < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def mentioned_users(current_user = nil)
|
||||
users = super
|
||||
|
||||
return users unless confidential?
|
||||
|
||||
Ability.users_that_can_read_internal_notes(users, resource_parent)
|
||||
end
|
||||
|
||||
def mentioned_filtered_user_ids_for(references)
|
||||
return super unless confidential?
|
||||
|
||||
user_ids = references.mentioned_user_ids.presence
|
||||
|
||||
return [] if user_ids.blank?
|
||||
|
||||
users = User.where(id: user_ids)
|
||||
Ability.users_that_can_read_internal_notes(users, resource_parent).pluck(:id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def system_note_viewable_by?(user)
|
||||
|
|
|
@ -21,11 +21,11 @@ module WorkItems
|
|||
}.freeze
|
||||
|
||||
WIDGETS_FOR_TYPE = {
|
||||
issue: [Widgets::Description, Widgets::Hierarchy, Widgets::Assignees],
|
||||
issue: [Widgets::Assignees, Widgets::Description, Widgets::Hierarchy, Widgets::Weight],
|
||||
incident: [Widgets::Description],
|
||||
test_case: [Widgets::Description],
|
||||
requirement: [Widgets::Description],
|
||||
task: [Widgets::Description, Widgets::Hierarchy, Widgets::Assignees]
|
||||
task: [Widgets::Assignees, Widgets::Description, Widgets::Hierarchy, Widgets::Weight]
|
||||
}.freeze
|
||||
|
||||
cache_markdown_field :description, pipeline: :single_line
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WorkItems
|
||||
module Widgets
|
||||
class Weight < Base
|
||||
delegate :weight, to: :work_item
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WorkItems
|
||||
module Widgets
|
||||
module WeightService
|
||||
class UpdateService < WorkItems::Widgets::BaseService
|
||||
def update(params: {})
|
||||
return unless params.present? && params[:weight]
|
||||
|
||||
widget.work_item.weight = params[:weight]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -68,7 +68,7 @@
|
|||
= render 'users/deletion_guidance', user: current_user
|
||||
|
||||
-# Delete button here
|
||||
%button#delete-account-button.gl-button.btn.btn-danger.disabled{ data: { qa_selector: 'delete_account_button' } }
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'delete-account-button', disabled: true, data: { qa_selector: 'delete_account_button' }}) do
|
||||
= s_('Profiles|Delete account')
|
||||
|
||||
#delete-account-modal{ data: { action_url: user_registration_path,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= gl_loading_icon(size: "md", css_class: "gl-my-4")
|
||||
.text-center.gl-mt-3.gl-mb-3.stl-controls
|
||||
.btn-group
|
||||
%button.gl-button.btn.btn-default.btn-sm.js-material-changer{ data: { type: 'wireframe' } }
|
||||
Wireframe
|
||||
%button.gl-button.btn.btn-default.btn-sm.selected.js-material-changer{ data: { type: 'default' } }
|
||||
Solid
|
||||
= render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-material-changer', data: { material: 'wireframe' } }) do
|
||||
= _('Wireframe')
|
||||
= render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-material-changer selected', data: { material: 'default' } }) do
|
||||
= _('Solid')
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/362246
|
|||
milestone: '15.1'
|
||||
type: development
|
||||
group: group::sharding
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -238,13 +238,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
end
|
||||
end
|
||||
|
||||
resources :logs, only: [:index] do
|
||||
collection do
|
||||
get :k8s
|
||||
get :elasticsearch
|
||||
end
|
||||
end
|
||||
|
||||
resources :starrers, only: [:index]
|
||||
resources :forks, only: [:index, :new, :create]
|
||||
resources :group_links, only: [:update, :destroy], constraints: { id: /\d+|:id/ }
|
||||
|
|
|
@ -996,7 +996,7 @@ You can switch an exiting database cluster to use Patroni instead of repmgr with
|
|||
|
||||
### Upgrading PostgreSQL major version in a Patroni cluster
|
||||
|
||||
As of GitLab 13.3, PostgreSQL 11.7 and 12.3 are both shipped with Omnibus GitLab by default. As of GitLab 13.7, PostgreSQL 12 is the default. If you want to upgrade to PostgreSQL 12 in versions prior to GitLab 13.7, you must ask for it explicitly.
|
||||
As of GitLab 14.1, PostgreSQL 12.6 and 13.3 are both shipped with Omnibus GitLab by default. As of GitLab 15.0, PostgreSQL 13 is the default. If you want to upgrade to PostgreSQL 13 in versions prior to GitLab 15.0, you must ask for it explicitly.
|
||||
|
||||
WARNING:
|
||||
The procedure for upgrading PostgreSQL in a Patroni cluster is different than when upgrading using repmgr.
|
||||
|
@ -1046,7 +1046,7 @@ Considering these, you should carefully plan your PostgreSQL upgrade:
|
|||
1. Upgrade PostgreSQL on **the leader node** and make sure that the upgrade is completed successfully:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl pg-upgrade -V 12
|
||||
sudo gitlab-ctl pg-upgrade -V 13
|
||||
```
|
||||
|
||||
NOTE:
|
||||
|
@ -1073,7 +1073,7 @@ Considering these, you should carefully plan your PostgreSQL upgrade:
|
|||
1. Upgrade PostgreSQL **on replicas** (you can do this in parallel on all of them):
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl pg-upgrade -V 12
|
||||
sudo gitlab-ctl pg-upgrade -V 13
|
||||
```
|
||||
|
||||
NOTE:
|
||||
|
|
|
@ -5655,6 +5655,7 @@ Input type: `WorkItemUpdateInput`
|
|||
| <a id="mutationworkitemupdateid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
|
||||
| <a id="mutationworkitemupdatestateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. |
|
||||
| <a id="mutationworkitemupdatetitle"></a>`title` | [`String`](#string) | Title of the work item. |
|
||||
| <a id="mutationworkitemupdateweightwidget"></a>`weightWidget` | [`WorkItemWidgetWeightInput`](#workitemwidgetweightinput) | Input for weight widget. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -18518,6 +18519,17 @@ Represents a hierarchy widget.
|
|||
| <a id="workitemwidgethierarchyparent"></a>`parent` | [`WorkItem`](#workitem) | Parent work item. |
|
||||
| <a id="workitemwidgethierarchytype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
|
||||
|
||||
### `WorkItemWidgetWeight`
|
||||
|
||||
Represents a weight widget.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="workitemwidgetweighttype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
|
||||
| <a id="workitemwidgetweightweight"></a>`weight` | [`Int`](#int) | Weight of the work item. |
|
||||
|
||||
## Enumeration types
|
||||
|
||||
Also called _Enums_, enumeration types are a special kind of scalar that
|
||||
|
@ -20372,6 +20384,7 @@ Type of a work item widget.
|
|||
| <a id="workitemwidgettypeassignees"></a>`ASSIGNEES` | Assignees widget. |
|
||||
| <a id="workitemwidgettypedescription"></a>`DESCRIPTION` | Description widget. |
|
||||
| <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. |
|
||||
| <a id="workitemwidgettypeweight"></a>`WEIGHT` | Weight widget. |
|
||||
|
||||
## Scalar types
|
||||
|
||||
|
@ -21593,6 +21606,7 @@ Implementations:
|
|||
- [`WorkItemWidgetAssignees`](#workitemwidgetassignees)
|
||||
- [`WorkItemWidgetDescription`](#workitemwidgetdescription)
|
||||
- [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy)
|
||||
- [`WorkItemWidgetWeight`](#workitemwidgetweight)
|
||||
|
||||
##### Fields
|
||||
|
||||
|
@ -22082,6 +22096,7 @@ A time-frame defined as a closed inclusive range of two dates.
|
|||
| <a id="workitemupdatedtaskinputid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
|
||||
| <a id="workitemupdatedtaskinputstateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. |
|
||||
| <a id="workitemupdatedtaskinputtitle"></a>`title` | [`String`](#string) | Title of the work item. |
|
||||
| <a id="workitemupdatedtaskinputweightwidget"></a>`weightWidget` | [`WorkItemWidgetWeightInput`](#workitemwidgetweightinput) | Input for weight widget. |
|
||||
|
||||
### `WorkItemWidgetDescriptionInput`
|
||||
|
||||
|
@ -22090,3 +22105,11 @@ A time-frame defined as a closed inclusive range of two dates.
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="workitemwidgetdescriptioninputdescription"></a>`description` | [`String!`](#string) | Description of the work item. |
|
||||
|
||||
### `WorkItemWidgetWeightInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="workitemwidgetweightinputweight"></a>`weight` | [`Int!`](#int) | Weight of the work item. |
|
||||
|
|
|
@ -248,9 +248,13 @@ set `CI_AWS_ECS_WAIT_FOR_ROLLOUT_COMPLETE_DISABLED` to a non-empty value.
|
|||
|
||||
## Set up Review Apps
|
||||
|
||||
In order to use [Review Apps](../../../development/testing_guide/review_apps.md) with ECS, you should create another
|
||||
[service](#create-an-ecs-service) and specify its name using the `CI_AWS_ECS_SERVICE` variable scoped to `review/*`.
|
||||
Since this service is shared by all review apps, there is a limitation that only one Review App can be deployed at a time.
|
||||
To use [Review Apps](../../../development/testing_guide/review_apps.md) with ECS:
|
||||
|
||||
1. Set up a new [service](#create-an-ecs-service).
|
||||
1. Use the `CI_AWS_ECS_SERVICE` variable to set the name.
|
||||
1. Set the environment scope to `review/*`.
|
||||
|
||||
Only one Review App at a time can be deployed because this service is shared by all review apps.
|
||||
|
||||
## Set up Security Testing
|
||||
|
||||
|
@ -275,6 +279,20 @@ include:
|
|||
- template: Security/DAST.gitlab-ci.yml
|
||||
```
|
||||
|
||||
To use DAST on the default branch:
|
||||
|
||||
1. Set up a new [service](#create-an-ecs-service). This service will be used to deploy a temporary
|
||||
DAST environment.
|
||||
1. Use the `CI_AWS_ECS_SERVICE` variable to set the name.
|
||||
1. Set the scope to the `dast-default` environment.
|
||||
1. Add the following to your `.gitlab-ci.yml` file:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- template: Security/DAST.gitlab-ci.yml
|
||||
- template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
|
||||
```
|
||||
|
||||
For more details and configuration options, see the [DAST documentation](../../../user/application_security/dast/index.md).
|
||||
|
||||
## Further reading
|
||||
|
|
|
@ -451,7 +451,7 @@ The `identifiers` array describes the detected vulnerability. An identifier obje
|
|||
`value` fields are used to tell if two identifiers are the same. The user interface uses the
|
||||
object's `name` and `url` fields to display the identifier.
|
||||
|
||||
It is recommended to reuse the identifiers the GitLab scanners already define:
|
||||
We recommend that you use the identifiers the GitLab scanners already define:
|
||||
|
||||
| Identifier | Type | Example value |
|
||||
|------------|------|---------------|
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
type: reference, howto
|
||||
stage: Secure
|
||||
group: Threat Insights
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Generate test vulnerabilities
|
||||
|
||||
You can generate test vulnerabilities when you work on the [Vulnerability Report](../vulnerability_report/index.md).
|
||||
|
||||
1. Go to `/-/profile/personal_access_tokens` and generate a personal access token with `api` permissions.
|
||||
1. Go to your project page and find the project ID. You can find the project ID below the project title.
|
||||
1. Open a terminal and go to the `gitlab/qa` directory.
|
||||
1. Run the following command:
|
||||
|
||||
```shell
|
||||
GITLAB_QA_ACCESS_TOKEN=<your_personal_access_token> GITLAB_URL="http://localhost:3000" bundle exec rake vulnerabilities:setup\[<your_project_id>,<vulnerability_count>\] --trace
|
||||
```
|
||||
|
||||
Make sure you do the following:
|
||||
|
||||
- Replace `<your_personal_access_token>` with the token you generated in step one.
|
||||
- Double check the `GITLAB_URL`. It should point to the running local instance.
|
||||
- Replace `<your_project_id>` with the ID you obtained in step two.
|
||||
- Replace `<vulnerability_count>` with the number of vulnerabilities you'd like to generate.
|
||||
|
||||
The script creates the specified amount of vulnerabilities in the project.
|
|
@ -4,6 +4,14 @@ variables:
|
|||
.dast-auto-deploy:
|
||||
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
||||
.common_rules: &common_rules
|
||||
- if: $CI_DEFAULT_BRANCH != $CI_COMMIT_REF_NAME
|
||||
when: never
|
||||
- if: $DAST_DISABLED || $DAST_DISABLED_FOR_DEFAULT_BRANCH
|
||||
when: never
|
||||
- if: $DAST_WEBSITE # we don't need to create a review app if a URL is already given
|
||||
when: never
|
||||
|
||||
dast_environment_deploy:
|
||||
extends: .dast-auto-deploy
|
||||
stage: review
|
||||
|
@ -23,12 +31,7 @@ dast_environment_deploy:
|
|||
artifacts:
|
||||
paths: [environment_url.txt]
|
||||
rules:
|
||||
- if: $CI_DEFAULT_BRANCH != $CI_COMMIT_REF_NAME
|
||||
when: never
|
||||
- if: $DAST_DISABLED || $DAST_DISABLED_FOR_DEFAULT_BRANCH
|
||||
when: never
|
||||
- if: $DAST_WEBSITE # we don't need to create a review app if a URL is already given
|
||||
when: never
|
||||
- *common_rules
|
||||
- if: $CI_COMMIT_BRANCH &&
|
||||
($CI_KUBERNETES_ACTIVE || $KUBECONFIG) &&
|
||||
$GITLAB_FEATURES =~ /\bdast\b/
|
||||
|
@ -47,13 +50,53 @@ stop_dast_environment:
|
|||
action: stop
|
||||
needs: ["dast"]
|
||||
rules:
|
||||
- if: $CI_DEFAULT_BRANCH != $CI_COMMIT_REF_NAME
|
||||
when: never
|
||||
- if: $DAST_DISABLED || $DAST_DISABLED_FOR_DEFAULT_BRANCH
|
||||
when: never
|
||||
- if: $DAST_WEBSITE # we don't need to create a review app if a URL is already given
|
||||
when: never
|
||||
- *common_rules
|
||||
- if: $CI_COMMIT_BRANCH &&
|
||||
($CI_KUBERNETES_ACTIVE || $KUBECONFIG) &&
|
||||
$GITLAB_FEATURES =~ /\bdast\b/
|
||||
when: always
|
||||
|
||||
.ecs_image:
|
||||
image: 'registry.gitlab.com/gitlab-org/cloud-deploy/aws-ecs:latest'
|
||||
|
||||
.ecs_rules: &ecs_rules
|
||||
- if: $AUTO_DEVOPS_PLATFORM_TARGET != "ECS"
|
||||
when: never
|
||||
- if: $CI_KUBERNETES_ACTIVE || $KUBECONFIG
|
||||
when: never
|
||||
|
||||
dast_ecs_environment_deploy:
|
||||
extends: .ecs_image
|
||||
stage: review
|
||||
script:
|
||||
- ecs update-task-definition
|
||||
- echo "http://$(ecs get-task-hostname)" > environment_url.txt
|
||||
environment:
|
||||
name: dast-default
|
||||
on_stop: stop_dast_ecs_environment
|
||||
artifacts:
|
||||
paths:
|
||||
- environment_url.txt
|
||||
rules:
|
||||
- *common_rules
|
||||
- *ecs_rules
|
||||
- if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bdast\b/
|
||||
|
||||
stop_dast_ecs_environment:
|
||||
extends: .ecs_image
|
||||
stage: cleanup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- ecs stop-task
|
||||
allow_failure: true
|
||||
environment:
|
||||
name: dast-default
|
||||
action: stop
|
||||
needs:
|
||||
- dast
|
||||
rules:
|
||||
- *common_rules
|
||||
- *ecs_rules
|
||||
- if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bdast\b/
|
||||
when: always
|
||||
|
|
|
@ -9,7 +9,6 @@ module Sidebars
|
|||
return false unless context.project.feature_available?(:operations, context.current_user)
|
||||
|
||||
add_item(metrics_dashboard_menu_item)
|
||||
add_item(logs_menu_item)
|
||||
add_item(error_tracking_menu_item)
|
||||
add_item(alert_management_menu_item)
|
||||
add_item(incidents_menu_item)
|
||||
|
@ -56,21 +55,6 @@ module Sidebars
|
|||
)
|
||||
end
|
||||
|
||||
def logs_menu_item
|
||||
if !Feature.enabled?(:monitor_logging, context.project) ||
|
||||
!can?(context.current_user, :read_environment, context.project) ||
|
||||
!can?(context.current_user, :read_pod_logs, context.project)
|
||||
return ::Sidebars::NilMenuItem.new(item_id: :logs)
|
||||
end
|
||||
|
||||
::Sidebars::MenuItem.new(
|
||||
title: _('Logs'),
|
||||
link: project_logs_path(context.project),
|
||||
active_routes: { path: 'logs#index' },
|
||||
item_id: :logs
|
||||
)
|
||||
end
|
||||
|
||||
def error_tracking_menu_item
|
||||
unless can?(context.current_user, :read_sentry_issue, context.project)
|
||||
return ::Sidebars::NilMenuItem.new(item_id: :error_tracking)
|
||||
|
|
|
@ -6222,12 +6222,6 @@ msgstr ""
|
|||
msgid "Billing|You can begin moving members in %{namespaceName} now. A member loses access to the group when you turn off %{strongStart}In a seat%{strongEnd}. If over 5 members have %{strongStart}In a seat%{strongEnd} enabled after June 22, 2022, we'll select the 5 members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach 5 members. The remaining members will get a status of Over limit and lose access to the group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Billing|Your free group is now limited to %{free_user_limit} members"
|
||||
msgstr ""
|
||||
|
||||
msgid "Billing|Your group recently changed to use the Free plan. Free groups are limited to %{free_user_limit} members and the remaining members will get a status of over-limit and lose access to the group. You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
|
||||
msgstr ""
|
||||
|
||||
msgid "Bitbucket Server Import"
|
||||
msgstr ""
|
||||
|
||||
|
@ -36098,6 +36092,9 @@ msgstr ""
|
|||
msgid "Snowplow"
|
||||
msgstr ""
|
||||
|
||||
msgid "Solid"
|
||||
msgstr ""
|
||||
|
||||
msgid "Solution"
|
||||
msgstr ""
|
||||
|
||||
|
@ -43551,6 +43548,9 @@ msgstr ""
|
|||
msgid "Will deploy to"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wireframe"
|
||||
msgstr ""
|
||||
|
||||
msgid "With requirements, you can set criteria to check your products against."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -52,8 +52,8 @@
|
|||
"@babel/preset-env": "^7.18.2",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "2.21.0",
|
||||
"@gitlab/ui": "42.9.0",
|
||||
"@gitlab/svgs": "2.22.0",
|
||||
"@gitlab/ui": "42.11.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
"@rails/ujs": "6.1.4-7",
|
||||
|
|
|
@ -6,6 +6,7 @@ RSpec.describe 'Incident details', :js do
|
|||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:incident) { create(:incident, project: project, author: developer, description: 'description') }
|
||||
let_it_be(:issue) { create(:issue, project: project, author: developer, description: 'Issue description') }
|
||||
let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, issue: incident) }
|
||||
|
||||
before_all do
|
||||
|
@ -14,23 +15,24 @@ RSpec.describe 'Incident details', :js do
|
|||
|
||||
before do
|
||||
sign_in(developer)
|
||||
|
||||
visit project_issues_incident_path(project, incident)
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
context 'when a developer+ displays the incident' do
|
||||
it 'shows the incident' do
|
||||
before do
|
||||
visit project_issues_incident_path(project, incident)
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'shows correct elements on the page', :aggregate_failures do
|
||||
# shows the incident
|
||||
page.within('.issuable-details') do
|
||||
expect(find('h1')).to have_content(incident.title)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not show design management' do
|
||||
# does not show design management
|
||||
expect(page).not_to have_selector('.js-design-management')
|
||||
end
|
||||
|
||||
it 'shows the incident tabs' do
|
||||
# shows the incident tabs
|
||||
page.within('.issuable-details') do
|
||||
incident_tabs = find('[data-testid="incident-tabs"]')
|
||||
|
||||
|
@ -38,9 +40,8 @@ RSpec.describe 'Incident details', :js do
|
|||
expect(incident_tabs).to have_content('Summary')
|
||||
expect(incident_tabs).to have_content(incident.description)
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows the right sidebar mounted with type issue' do
|
||||
# shows the right sidebar mounted with type issue
|
||||
page.within('.layout-page') do
|
||||
sidebar = find('.right-sidebar')
|
||||
|
||||
|
@ -51,12 +52,12 @@ RSpec.describe 'Incident details', :js do
|
|||
end
|
||||
end
|
||||
|
||||
context 'escalation status' do
|
||||
describe 'escalation status' do
|
||||
let(:sidebar) { page.find('.right-sidebar') }
|
||||
let(:widget) { sidebar.find('[data-testid="escalation_status_container"]') }
|
||||
let(:expected_dropdown_options) { escalation_status.class::STATUSES.keys.take(3).map { |key| key.to_s.titleize } }
|
||||
|
||||
it 'has an interactable escalation status widget' do
|
||||
it 'has an interactable escalation status widget', :aggregate_failures do
|
||||
expect(current_status).to have_text(escalation_status.status_name.to_s.titleize)
|
||||
|
||||
# list the available statuses
|
||||
|
@ -87,41 +88,41 @@ RSpec.describe 'Incident details', :js do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when an incident `issue_type` is edited by a signed in user' do
|
||||
it 'routes the user to the incident details page when the `issue_type` is set to incident' do
|
||||
wait_for_requests
|
||||
project_path = "/#{project.full_path}"
|
||||
click_button 'Edit title and description'
|
||||
it 'routes the user to the incident details page when the `issue_type` is set to incident' do
|
||||
visit project_issue_path(project, issue)
|
||||
wait_for_requests
|
||||
|
||||
project_path = "/#{project.full_path}"
|
||||
click_button 'Edit title and description'
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="issuable-form"]') do
|
||||
click_button 'Issue'
|
||||
click_button 'Incident'
|
||||
click_button 'Save changes'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="issuable-form"]') do
|
||||
click_button 'Incident'
|
||||
click_button 'Issue'
|
||||
click_button 'Save changes'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_current_path("#{project_path}/-/issues/#{incident.iid}")
|
||||
end
|
||||
expect(page).to have_current_path("#{project_path}/-/issues/incident/#{issue.iid}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when incident details are edited by a signed in user' do
|
||||
it 'routes the user to the incident details page when the `issue_type` is set to incident' do
|
||||
wait_for_requests
|
||||
project_path = "/#{project.full_path}"
|
||||
click_button 'Edit title and description'
|
||||
it 'routes the user to the issue details page when the `issue_type` is set to issue' do
|
||||
visit project_issues_incident_path(project, incident)
|
||||
wait_for_requests
|
||||
|
||||
project_path = "/#{project.full_path}"
|
||||
click_button 'Edit title and description'
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="issuable-form"]') do
|
||||
click_button 'Incident'
|
||||
click_button 'Issue'
|
||||
click_button 'Save changes'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within('[data-testid="issuable-form"]') do
|
||||
click_button 'Incident'
|
||||
click_button 'Issue'
|
||||
click_button 'Save changes'
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_current_path("#{project_path}/-/issues/#{incident.iid}")
|
||||
end
|
||||
expect(page).to have_current_path("#{project_path}/-/issues/#{incident.iid}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@ exports[`Alert integration settings form default state should match the default
|
|||
<gl-form-checkbox-stub
|
||||
checked="true"
|
||||
data-qa-selector="create_issue_checkbox"
|
||||
id="2"
|
||||
>
|
||||
<span>
|
||||
Create an incident. Incidents are created for each alert triggered.
|
||||
|
@ -87,7 +88,9 @@ exports[`Alert integration settings form default state should match the default
|
|||
labeldescription=""
|
||||
optionaltext="(optional)"
|
||||
>
|
||||
<gl-form-checkbox-stub>
|
||||
<gl-form-checkbox-stub
|
||||
id="3"
|
||||
>
|
||||
<span>
|
||||
Send a single email notification to Owners and Maintainers for new alerts.
|
||||
</span>
|
||||
|
@ -101,6 +104,7 @@ exports[`Alert integration settings form default state should match the default
|
|||
>
|
||||
<gl-form-checkbox-stub
|
||||
checked="true"
|
||||
id="4"
|
||||
>
|
||||
<span>
|
||||
Automatically close associated incident when a recovery alert notification resolves an alert
|
||||
|
|
|
@ -7,6 +7,7 @@ exports[`Keep latest artifact checkbox when application keep latest artifact set
|
|||
<b-form-checkbox-stub
|
||||
checked="true"
|
||||
class="gl-form-checkbox"
|
||||
id="4"
|
||||
value="true"
|
||||
>
|
||||
<strong
|
||||
|
|
|
@ -151,6 +151,38 @@ RSpec.describe Ability do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.users_that_can_read_internal_note' do
|
||||
shared_examples 'filtering users that can read internal note' do
|
||||
let_it_be(:guest) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
|
||||
let(:users) { [reporter, guest] }
|
||||
|
||||
before do
|
||||
parent.add_guest(guest)
|
||||
parent.add_reporter(reporter)
|
||||
end
|
||||
|
||||
it 'returns users that can read internal notes' do
|
||||
result = described_class.users_that_can_read_internal_notes(users, parent)
|
||||
|
||||
expect(result).to match_array([reporter])
|
||||
end
|
||||
end
|
||||
|
||||
context 'for groups' do
|
||||
it_behaves_like 'filtering users that can read internal note' do
|
||||
let(:parent) { create(:group) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'for projects' do
|
||||
it_behaves_like 'filtering users that can read internal note' do
|
||||
let(:parent) { create(:project) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.merge_requests_readable_by_user' do
|
||||
context 'with an admin when admin mode is enabled', :enable_admin_mode do
|
||||
it 'returns all merge requests' do
|
||||
|
|
|
@ -31,7 +31,7 @@ RSpec.describe Participable do
|
|||
|
||||
expect(instance).to receive(:foo).and_return(user2)
|
||||
expect(instance).to receive(:bar).and_return(user3)
|
||||
expect(instance).to receive(:project).twice.and_return(project)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
participants = instance.participants(user1)
|
||||
|
||||
|
@ -66,7 +66,7 @@ RSpec.describe Participable do
|
|||
|
||||
expect(instance).to receive(:foo).and_return(other)
|
||||
expect(other).to receive(:bar).and_return(user2)
|
||||
expect(instance).to receive(:project).twice.and_return(project)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
expect(instance.participants(user1)).to eq([user2])
|
||||
end
|
||||
|
@ -86,7 +86,7 @@ RSpec.describe Participable do
|
|||
|
||||
instance = model.new
|
||||
|
||||
expect(instance).to receive(:project).twice.and_return(project)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
instance.participants(user1)
|
||||
|
||||
|
@ -138,7 +138,7 @@ RSpec.describe Participable do
|
|||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
expect(instance).to receive(:foo).and_return(user2)
|
||||
expect(instance).to receive(:bar).and_return(user3)
|
||||
expect(instance).to receive(:project).twice.and_return(project)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
participants = instance.visible_participants(user1)
|
||||
|
||||
|
@ -159,7 +159,7 @@ RSpec.describe Participable do
|
|||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
allow(instance).to receive(:bar).and_return(user2)
|
||||
expect(instance).to receive(:project).twice.and_return(project)
|
||||
expect(instance).to receive(:project).thrice.and_return(project)
|
||||
|
||||
expect(instance.visible_participants(user1)).to be_empty
|
||||
end
|
||||
|
|
|
@ -744,25 +744,11 @@ RSpec.describe Issue do
|
|||
end
|
||||
|
||||
describe '#participants' do
|
||||
context 'using a public project' do
|
||||
let_it_be(:public_project) { create(:project, :public) }
|
||||
let_it_be(:issue) { create(:issue, project: public_project) }
|
||||
it_behaves_like 'issuable participants' do
|
||||
let_it_be(:issuable_parent) { create(:project, :public) }
|
||||
let_it_be_with_refind(:issuable) { create(:issue, project: issuable_parent) }
|
||||
|
||||
let!(:note1) do
|
||||
create(:note_on_issue, noteable: issue, project: public_project, note: 'a')
|
||||
end
|
||||
|
||||
let!(:note2) do
|
||||
create(:note_on_issue, noteable: issue, project: public_project, note: 'b')
|
||||
end
|
||||
|
||||
it 'includes the issue author' do
|
||||
expect(issue.participants).to include(issue.author)
|
||||
end
|
||||
|
||||
it 'includes the authors of the notes' do
|
||||
expect(issue.participants).to include(note1.author, note2.author)
|
||||
end
|
||||
let(:params) { { noteable: issuable, project: issuable_parent } }
|
||||
end
|
||||
|
||||
context 'using a private project' do
|
||||
|
|
|
@ -39,7 +39,8 @@ RSpec.describe WorkItem do
|
|||
it 'returns instances of supported widgets' do
|
||||
is_expected.to match_array([instance_of(WorkItems::Widgets::Description),
|
||||
instance_of(WorkItems::Widgets::Hierarchy),
|
||||
instance_of(WorkItems::Widgets::Assignees)])
|
||||
instance_of(WorkItems::Widgets::Assignees),
|
||||
instance_of(WorkItems::Widgets::Weight)])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@ RSpec.describe WorkItems::Type do
|
|||
it 'returns list of all possible widgets' do
|
||||
is_expected.to match_array([::WorkItems::Widgets::Description,
|
||||
::WorkItems::Widgets::Hierarchy,
|
||||
::WorkItems::Widgets::Assignees])
|
||||
::WorkItems::Widgets::Assignees,
|
||||
::WorkItems::Widgets::Weight])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -113,5 +113,29 @@ RSpec.describe 'Update a work item' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with weight widget input' do
|
||||
let(:fields) do
|
||||
<<~FIELDS
|
||||
workItem {
|
||||
widgets {
|
||||
type
|
||||
... on WorkItemWidgetWeight {
|
||||
weight
|
||||
}
|
||||
}
|
||||
}
|
||||
errors
|
||||
FIELDS
|
||||
end
|
||||
|
||||
it_behaves_like 'update work item weight widget' do
|
||||
let(:new_weight) { 2 }
|
||||
|
||||
let(:input) do
|
||||
{ 'weightWidget' => { 'weight' => new_weight } }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ RSpec.describe 'Query.work_item(id)' do
|
|||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:guest) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :private) }
|
||||
let_it_be(:work_item) { create(:work_item, project: project, description: '- List item') }
|
||||
let_it_be(:work_item) { create(:work_item, project: project, description: '- List item', weight: 1) }
|
||||
let_it_be(:child_item1) { create(:work_item, :task, project: project) }
|
||||
let_it_be(:child_item2) { create(:work_item, :task, confidential: true, project: project) }
|
||||
let_it_be(:child_link1) { create(:parent_link, work_item_parent: work_item, work_item: child_item1) }
|
||||
|
@ -163,6 +163,32 @@ RSpec.describe 'Query.work_item(id)' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'weight widget' do
|
||||
let(:work_item_fields) do
|
||||
<<~GRAPHQL
|
||||
id
|
||||
widgets {
|
||||
type
|
||||
... on WorkItemWidgetWeight {
|
||||
weight
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
it 'returns widget information' do
|
||||
expect(work_item_data).to include(
|
||||
'id' => work_item.to_gid.to_s,
|
||||
'widgets' => include(
|
||||
hash_including(
|
||||
'type' => 'WEIGHT',
|
||||
'weight' => work_item.weight
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'assignees widget' do
|
||||
let(:assignees) { create_list(:user, 2) }
|
||||
let(:work_item) { create(:work_item, project: project, assignees: assignees) }
|
||||
|
|
|
@ -147,6 +147,34 @@ RSpec.describe NotificationService, :mailer do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'participating by confidential note notification' do
|
||||
context 'when user is mentioned on confidential note' do
|
||||
let_it_be(:guest_1) { create(:user) }
|
||||
let_it_be(:guest_2) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
|
||||
before do
|
||||
issuable.resource_parent.add_guest(guest_1)
|
||||
issuable.resource_parent.add_guest(guest_2)
|
||||
issuable.resource_parent.add_reporter(reporter)
|
||||
end
|
||||
|
||||
it 'only emails authorized users' do
|
||||
confidential_note_text = "#{guest_1.to_reference} and #{guest_2.to_reference} and #{reporter.to_reference}"
|
||||
note_text = "Mentions #{guest_2.to_reference}"
|
||||
create(:note_on_issue, noteable: issuable, project_id: project.id, note: confidential_note_text, confidential: true)
|
||||
create(:note_on_issue, noteable: issuable, project_id: project.id, note: note_text)
|
||||
reset_delivered_emails!
|
||||
|
||||
notification_trigger
|
||||
|
||||
should_not_email(guest_1)
|
||||
should_email(guest_2)
|
||||
should_email(reporter)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'participating by assignee notification' do
|
||||
it 'emails the participant' do
|
||||
issuable.assignees << participant
|
||||
|
@ -736,6 +764,20 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_target) { note }
|
||||
let(:notification_trigger) { notification.new_note(note) }
|
||||
end
|
||||
|
||||
context 'when note is confidential' do
|
||||
let(:note) { create(:note_on_issue, author: author, noteable: issue, project_id: issue.project_id, note: '@all mentioned', confidential: true) }
|
||||
let(:guest) { create(:user) }
|
||||
|
||||
it 'does not notify users that cannot read note' do
|
||||
project.add_guest(guest)
|
||||
reset_delivered_emails!
|
||||
|
||||
notification.new_note(note)
|
||||
|
||||
should_not_email(guest)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1376,6 +1418,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled, [assignee]) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled, [assignee]) }
|
||||
end
|
||||
|
||||
it_behaves_like 'project emails are disabled' do
|
||||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled, [assignee]) }
|
||||
|
@ -1494,6 +1541,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.removed_milestone_issue(issue, issue.author) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.removed_milestone_issue(issue, issue.author) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'confidential issues' do
|
||||
|
@ -1616,6 +1668,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.close_issue(issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.close_issue(issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it 'adds "subscribed" reason to subscriber emails' do
|
||||
user_1 = create(:user)
|
||||
issue.subscribe(user_1)
|
||||
|
@ -1658,6 +1715,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.reopen_issue(issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.reopen_issue(issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'project emails are disabled' do
|
||||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.reopen_issue(issue, @u_disabled) }
|
||||
|
@ -1689,6 +1751,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.issue_moved(issue, new_issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.issue_moved(issue, new_issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'project emails are disabled' do
|
||||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.issue_moved(issue, new_issue, @u_disabled) }
|
||||
|
@ -1720,6 +1787,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.issue_cloned(issue, new_issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.issue_cloned(issue, new_issue, @u_disabled) }
|
||||
end
|
||||
|
||||
it_behaves_like 'project emails are disabled' do
|
||||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.issue_cloned(issue, new_issue, @u_disabled) }
|
||||
|
@ -1765,6 +1837,11 @@ RSpec.describe NotificationService, :mailer do
|
|||
let(:notification_trigger) { notification.issue_due(issue) }
|
||||
end
|
||||
|
||||
it_behaves_like 'participating by confidential note notification' do
|
||||
let(:issuable) { issue }
|
||||
let(:notification_trigger) { notification.issue_due(issue) }
|
||||
end
|
||||
|
||||
it_behaves_like 'project emails are disabled' do
|
||||
let(:notification_target) { issue }
|
||||
let(:notification_trigger) { notification.issue_due(issue) }
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe WorkItems::Widgets::WeightService::UpdateService do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be_with_reload(:work_item) { create(:work_item, project: project, weight: 1) }
|
||||
|
||||
let(:widget) { work_item.widgets.find {|widget| widget.is_a?(WorkItems::Widgets::Weight) } }
|
||||
|
||||
describe '#update' do
|
||||
subject { described_class.new(widget: widget, current_user: user).update(params: params) } # rubocop:disable Rails/SaveBang
|
||||
|
||||
context 'when weight param is present' do
|
||||
let(:params) { { weight: 2 } }
|
||||
|
||||
it 'correctly sets work item weight value' do
|
||||
subject
|
||||
|
||||
expect(work_item.weight).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when weight param is not present' do
|
||||
let(:params) { {} }
|
||||
|
||||
it 'does not change work item weight value', :aggregate_failures do
|
||||
expect { subject }
|
||||
.to not_change { work_item.weight }
|
||||
|
||||
expect(work_item.weight).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -83,7 +83,6 @@ RSpec.shared_context 'project navbar structure' do
|
|||
nav_item: _('Monitor'),
|
||||
nav_sub_items: [
|
||||
_('Metrics'),
|
||||
_('Logs'),
|
||||
_('Error Tracking'),
|
||||
_('Alerts'),
|
||||
_('Incidents'),
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'update work item weight widget' do
|
||||
it 'updates the weight widget' do
|
||||
expect do
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
work_item.reload
|
||||
end.to change(work_item, :weight).from(nil).to(new_weight)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(mutation_response['workItem']['widgets']).to include(
|
||||
{
|
||||
'weight' => new_weight,
|
||||
'type' => 'WEIGHT'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the updated work item is not valid' do
|
||||
it 'returns validation errors without the work item' do
|
||||
errors = ActiveModel::Errors.new(work_item).tap { |e| e.add(:weight, 'error message') }
|
||||
|
||||
allow_next_found_instance_of(::WorkItem) do |instance|
|
||||
allow(instance).to receive(:valid?).and_return(false)
|
||||
allow(instance).to receive(:errors).and_return(errors)
|
||||
end
|
||||
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(mutation_response['workItem']).to be_nil
|
||||
expect(mutation_response['errors']).to match_array(['Weight error message'])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,53 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'issuable participants' do
|
||||
context 'when resource parent is public' do
|
||||
context 'and users are referenced on notes' do
|
||||
let_it_be(:notes_author) { create(:user) }
|
||||
|
||||
let(:note_params) { params.merge(author: notes_author) }
|
||||
|
||||
before do
|
||||
create(:note, note_params)
|
||||
end
|
||||
|
||||
it 'includes the issue author' do
|
||||
expect(issuable.participants).to include(issuable.author)
|
||||
end
|
||||
|
||||
it 'includes the authors of the notes' do
|
||||
expect(issuable.participants).to include(notes_author)
|
||||
end
|
||||
|
||||
context 'and note is confidential' do
|
||||
context 'and mentions users' do
|
||||
let_it_be(:guest_1) { create(:user) }
|
||||
let_it_be(:guest_2) { create(:user) }
|
||||
let_it_be(:reporter) { create(:user) }
|
||||
|
||||
before do
|
||||
issuable_parent.add_guest(guest_1)
|
||||
issuable_parent.add_guest(guest_2)
|
||||
issuable_parent.add_reporter(reporter)
|
||||
|
||||
confidential_note_params =
|
||||
note_params.merge(
|
||||
confidential: true,
|
||||
note: "mentions #{guest_1.to_reference} and #{guest_2.to_reference} and #{reporter.to_reference}"
|
||||
)
|
||||
|
||||
regular_note_params =
|
||||
note_params.merge(note: "Mentions #{guest_2.to_reference}")
|
||||
|
||||
create(:note, confidential_note_params)
|
||||
create(:note, regular_note_params)
|
||||
end
|
||||
|
||||
it 'only includes users that can read the note as participants' do
|
||||
expect(issuable.participants).to contain_exactly(issuable.author, notes_author, reporter, guest_2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -260,6 +260,25 @@ RSpec.shared_examples 'mentions in notes' do |mentionable_type|
|
|||
expect(mentionable.referenced_projects(user)).to eq [mentionable.project].compact # epic.project is nil, and we want empty []
|
||||
expect(mentionable.referenced_groups(user)).to eq [group]
|
||||
end
|
||||
|
||||
if [:epic, :issue].include?(mentionable_type)
|
||||
context 'and note is confidential' do
|
||||
let_it_be(:guest) { create(:user) }
|
||||
|
||||
let(:note_desc) { "#{guest.to_reference} and #{user2.to_reference} and #{user.to_reference}" }
|
||||
|
||||
before do
|
||||
note.resource_parent.add_reporter(user2)
|
||||
note.resource_parent.add_guest(guest)
|
||||
# Bypass :confidential update model validation for testing purposes
|
||||
note.update_attribute(:confidential, true)
|
||||
end
|
||||
|
||||
it 'returns only mentioned users that has permissions' do
|
||||
expect(note.mentioned_users).to contain_exactly(user, user2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -294,6 +313,26 @@ RSpec.shared_examples 'load mentions from DB' do |mentionable_type|
|
|||
end
|
||||
end
|
||||
|
||||
if [:epic, :issue].include?(mentionable_type)
|
||||
context 'and note is confidential' do
|
||||
let_it_be(:guest) { create(:user) }
|
||||
|
||||
let(:note_desc) { "#{guest.to_reference} and #{mentioned_user.to_reference}" }
|
||||
|
||||
before do
|
||||
note.resource_parent.add_reporter(mentioned_user)
|
||||
note.resource_parent.add_guest(guest)
|
||||
# Bypass :confidential update model validation for testing purposes
|
||||
note.update_attribute(:confidential, true)
|
||||
note.store_mentions!
|
||||
end
|
||||
|
||||
it 'stores only mentioned users that has permissions' do
|
||||
expect(mentionable.referenced_users).to contain_exactly(mentioned_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when private projects and groups are mentioned' do
|
||||
let(:mega_user) { create(:user) }
|
||||
let(:private_project) { create(:project, :private) }
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
*.gem
|
||||
*.rbc
|
||||
.bundle
|
||||
.config
|
||||
.yardoc
|
||||
.rvmrc
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
doc/
|
||||
lib/bundler/man
|
||||
pkg
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
|
@ -0,0 +1,30 @@
|
|||
workflow:
|
||||
rules:
|
||||
- if: $CI_MERGE_REQUEST_ID
|
||||
|
||||
.rspec:
|
||||
cache:
|
||||
key: omniauth-gitlab-ruby
|
||||
paths:
|
||||
- vendor/gems/omniauth-gitlab/vendor/ruby
|
||||
before_script:
|
||||
- cd vendor/gems/omniauth-gitlab
|
||||
- ruby -v # Print out ruby version for debugging
|
||||
- gem install bundler --no-document # Bundler is not installed with the image
|
||||
- bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby
|
||||
- bundle config set with 'development'
|
||||
- bundle install -j $(nproc)
|
||||
script:
|
||||
- bundle exec rspec
|
||||
|
||||
rspec-2.6:
|
||||
image: "ruby:2.6"
|
||||
extends: .rspec
|
||||
|
||||
rspec-2.7:
|
||||
image: "ruby:2.7"
|
||||
extends: .rspec
|
||||
|
||||
rspec-3.0:
|
||||
image: "ruby:3.0"
|
||||
extends: .rspec
|
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in omniauth-gitlab.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,73 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
omniauth-gitlab (4.0.0)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.7.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
diff-lcs (1.5.0)
|
||||
docile (1.4.0)
|
||||
faraday (2.3.0)
|
||||
faraday-net_http (~> 2.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-net_http (2.0.3)
|
||||
hashie (5.0.0)
|
||||
jwt (2.4.1)
|
||||
multi_xml (0.6.0)
|
||||
oauth2 (2.0.1)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
rash_alt (>= 0.4, < 1)
|
||||
version_gem (~> 1.0)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-oauth2 (1.7.3)
|
||||
oauth2 (>= 1.4, < 3)
|
||||
omniauth (>= 1.9, < 3)
|
||||
rack (2.2.3.1)
|
||||
rake (13.0.6)
|
||||
rash_alt (0.4.12)
|
||||
hashie (>= 3.4)
|
||||
rspec (3.11.0)
|
||||
rspec-core (~> 3.11.0)
|
||||
rspec-expectations (~> 3.11.0)
|
||||
rspec-mocks (~> 3.11.0)
|
||||
rspec-core (3.11.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-expectations (3.11.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-its (1.3.0)
|
||||
rspec-core (>= 3.0.0)
|
||||
rspec-expectations (>= 3.0.0)
|
||||
rspec-mocks (3.11.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-support (3.11.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
simplecov (0.21.2)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
version_gem (1.0.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
omniauth-gitlab!
|
||||
rake (>= 12.0)
|
||||
rspec (~> 3.1)
|
||||
rspec-its (~> 1.0)
|
||||
simplecov
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.15
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2013 ssein
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,94 @@
|
|||
# Omniauth::Gitlab
|
||||
|
||||
This is fork of [omniauth-gitlab](https://github.com/linchus/omniauth-gitlab) to support:
|
||||
|
||||
1. OmniAuth v1 and v2. OmniAuth v2 disables GET requests by default
|
||||
and defaults to POST. GitLab already has patched v1 to use POST,
|
||||
but other dependencies need to be updated:
|
||||
https://gitlab.com/gitlab-org/gitlab/-/issues/30073.
|
||||
|
||||
2. [`oauth2`](https://github.com/oauth-xx/oauth2) v1.4.9 and up.
|
||||
[v1.4.9 fixed relative URL handling](https://github.com/oauth-xx/oauth2/pull/469).
|
||||
|
||||
However, this breaks the default GitLab.com configuration and
|
||||
existing configurations that use the `/api/v4` suffix in the `site`
|
||||
parameter.
|
||||
[omniauth-gitlab v4.0.0 fixed the first issue](https://github.com/linchus/omniauth-gitlab/pull/22),
|
||||
but the second issue requires an admin to update `site` to drop the suffix.
|
||||
|
||||
This fork restores backwards compatibility that was removed in omniauth-gitlab v2.0.0:
|
||||
https://github.com/linchus/omniauth-gitlab/commit/bb4cec2c9f8f067fdfe1f9aa219973e5d8e4a0a3
|
||||
|
||||
[![Join the chat at https://gitter.im/linchus/omniauth-gitlab](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/linchus/omniauth-gitlab?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
This is the OAuth2 strategy for authenticating to your GitLab service.
|
||||
|
||||
## Requirements
|
||||
|
||||
Gitlab 7.7.0+
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
gem 'omniauth-gitlab'
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install omniauth-gitlab
|
||||
|
||||
## Basic Usage
|
||||
|
||||
use OmniAuth::Builder do
|
||||
provider :gitlab, ENV['GITLAB_KEY'], ENV['GITLAB_SECRET']
|
||||
end
|
||||
|
||||
## Standalone Usage
|
||||
|
||||
use OmniAuth::Builder do
|
||||
provider :gitlab, ENV['GITLAB_KEY'], ENV['GITLAB_SECRET'],
|
||||
{
|
||||
client_options: {
|
||||
site: 'https://gitlab.YOURDOMAIN.com/api/v4'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
## Custom scopes
|
||||
|
||||
By default, the `api` scope is requested and must be allowed in GitLab's application configuration. To use different scopes:
|
||||
|
||||
use OmniAuth::Builder do
|
||||
provider :gitlab, ENV['GITLAB_KEY'], ENV['GITLAB_SECRET'], scope: 'read_user openid'
|
||||
end
|
||||
|
||||
Requesting a scope that is not configured will result the error "The requested scope is invalid, unknown, or malformed.".
|
||||
|
||||
## Old API version
|
||||
|
||||
API V3 will be unsupported from GitLab 9.5 and will be removed in GitLab 9.5 or later.
|
||||
|
||||
[https://gitlab.com/help/api/v3_to_v4.md](https://gitlab.com/help/api/v3_to_v4.md)
|
||||
|
||||
If you use GitLab 9.0 and below you could configure V3 API:
|
||||
|
||||
use OmniAuth::Builder do
|
||||
provider :gitlab, ENV['GITLAB_KEY'], ENV['GITLAB_SECRET'],
|
||||
{
|
||||
client_options: {
|
||||
site: 'https://gitlab.YOURDOMAIN.com/api/v3'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork it
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
4. Push to the branch (`git push origin my-new-feature`)
|
||||
5. Create new Pull Request
|
|
@ -0,0 +1,7 @@
|
|||
require 'bundler/gem_tasks'
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new
|
||||
|
||||
desc 'Run specs'
|
||||
task default: :spec
|
|
@ -0,0 +1,2 @@
|
|||
require 'omniauth-gitlab/version'
|
||||
require 'omniauth/strategies/gitlab'
|
|
@ -0,0 +1,5 @@
|
|||
module Omniauth
|
||||
module Gitlab
|
||||
VERSION = '4.0.0'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'omniauth-oauth2'
|
||||
|
||||
module OmniAuth
|
||||
module Strategies
|
||||
class GitLab < OmniAuth::Strategies::OAuth2
|
||||
API_SUFFIX_REGEX = %r{/api/v(\d+)/?$}.freeze
|
||||
|
||||
option :client_options, site: 'https://gitlab.com'
|
||||
|
||||
option :redirect_url
|
||||
|
||||
uid { raw_info['id'].to_s }
|
||||
|
||||
info do
|
||||
{
|
||||
name: raw_info['name'],
|
||||
username: raw_info['username'],
|
||||
email: raw_info['email'],
|
||||
image: raw_info['avatar_url']
|
||||
}
|
||||
end
|
||||
|
||||
extra do
|
||||
{ raw_info: raw_info }
|
||||
end
|
||||
|
||||
def raw_info
|
||||
@raw_info ||= access_token.get(user_endpoint_url).parsed
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_endpoint_url
|
||||
options.client_options.site.match(API_SUFFIX_REGEX) ? 'user' : 'api/v4/user'
|
||||
end
|
||||
|
||||
def callback_url
|
||||
options.redirect_url || (full_host + script_name + callback_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
OmniAuth.config.add_camelization 'gitlab', 'GitLab'
|
|
@ -0,0 +1,25 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'omniauth-gitlab/version'
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = 'omniauth-gitlab'
|
||||
gem.version = Omniauth::Gitlab::VERSION
|
||||
gem.authors = ['Sergey Sein']
|
||||
gem.email = ['linchus@gmail.com']
|
||||
gem.description = 'This is the strategy for authenticating to your GitLab service'
|
||||
gem.summary = 'This is the strategy for authenticating to your GitLab service'
|
||||
gem.homepage = 'https://github.com/linchus/omniauth-gitlab'
|
||||
|
||||
gem.files = Dir['lib/**/*.rb']
|
||||
gem.test_files = Dir['spec/**/*.rb']
|
||||
gem.require_paths = ['lib']
|
||||
|
||||
gem.add_dependency 'omniauth', '~> 1.0'
|
||||
gem.add_dependency 'omniauth-oauth2', '~> 1.7.1'
|
||||
gem.add_development_dependency 'rspec', '~> 3.1'
|
||||
gem.add_development_dependency 'rspec-its', '~> 1.0'
|
||||
gem.add_development_dependency 'simplecov'
|
||||
gem.add_development_dependency 'rake', '>= 12.0'
|
||||
end
|
|
@ -0,0 +1,80 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe OmniAuth::Strategies::GitLab do
|
||||
let(:access_token) { double('AccessToken') }
|
||||
let(:parsed_response) { double('ParsedResponse') }
|
||||
let(:response) { double('Response', parsed: parsed_response) }
|
||||
|
||||
let(:enterprise_site) { 'https://some.other.site.com' }
|
||||
|
||||
let(:gitlab_service) { OmniAuth::Strategies::GitLab.new({}) }
|
||||
let(:enterprise) do
|
||||
OmniAuth::Strategies::GitLab.new(
|
||||
'GITLAB_KEY',
|
||||
'GITLAB_SECRET',
|
||||
client_options: { site: enterprise_site },
|
||||
redirect_url: 'http://localhost:9292/callback_url'
|
||||
)
|
||||
end
|
||||
|
||||
subject { gitlab_service }
|
||||
|
||||
before(:each) do
|
||||
allow(subject).to receive(:access_token).and_return(access_token)
|
||||
end
|
||||
|
||||
describe 'client options' do
|
||||
context 'with defaults' do
|
||||
subject { gitlab_service.options.client_options }
|
||||
|
||||
its(:site) { is_expected.to eq 'https://gitlab.com' }
|
||||
end
|
||||
|
||||
context 'with override' do
|
||||
subject { enterprise.options.client_options }
|
||||
|
||||
its(:site) { is_expected.to eq enterprise_site }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'redirect_url' do
|
||||
context 'with defaults' do
|
||||
subject { gitlab_service.options }
|
||||
its(:redirect_url) { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'with customs' do
|
||||
subject { enterprise.options }
|
||||
its(:redirect_url) { is_expected.to eq 'http://localhost:9292/callback_url' }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#raw_info' do
|
||||
context 'with new configuration' do
|
||||
it 'sent request to current user endpoint' do
|
||||
expect(access_token).to receive(:get).with('api/v4/user').and_return(response)
|
||||
expect(subject.raw_info).to eq(parsed_response)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with old style configuration' do
|
||||
let(:enterprise_site) { 'https://some.other.site.com/api/v4' }
|
||||
|
||||
subject { enterprise }
|
||||
|
||||
it 'sent request to current user endpoint' do
|
||||
expect(access_token).to receive(:get).with('user').and_return(response)
|
||||
expect(subject.raw_info).to eq(parsed_response)
|
||||
end
|
||||
|
||||
context 'with a trailing slash' do
|
||||
let(:enterprise_site) { 'https://some.other.site.com/api/v4/' }
|
||||
|
||||
it 'sent request to current user endpoint' do
|
||||
expect(access_token).to receive(:get).with('user').and_return(response)
|
||||
expect(subject.raw_info).to eq(parsed_response)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
$LOAD_PATH.unshift File.expand_path('..', __FILE__)
|
||||
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
||||
require 'simplecov'
|
||||
SimpleCov.start
|
||||
require 'rspec'
|
||||
require 'rspec/its'
|
||||
require 'omniauth'
|
||||
require 'omniauth-gitlab'
|
16
yarn.lock
16
yarn.lock
|
@ -1048,15 +1048,15 @@
|
|||
stylelint-declaration-strict-value "1.8.0"
|
||||
stylelint-scss "4.2.0"
|
||||
|
||||
"@gitlab/svgs@2.21.0":
|
||||
version "2.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.21.0.tgz#bc71951dc35a61647fb2c0267cca6fb55a04d317"
|
||||
integrity sha512-cVa5cgvVmY2MsRdV61id+rLTsY/tAGPq7Og9ETblUuZXl06ciw8H/g7cYPMxN39DdEfDklzbUnS98OJlMmD9TQ==
|
||||
"@gitlab/svgs@2.22.0":
|
||||
version "2.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.22.0.tgz#66211ba26418b8dfb3ac796d795a0e3392d22ada"
|
||||
integrity sha512-9Es97o/VByIsCNNfSF28oTYW5XIJ2dZSK0YjSpyy5yBF0QPwEjzRhxapYGz2c8YBFVC9WkoGHjp5PJ9tJgmmuA==
|
||||
|
||||
"@gitlab/ui@42.9.0":
|
||||
version "42.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.9.0.tgz#506a642b9bef9eb5d363684c8ef81129a9b284ef"
|
||||
integrity sha512-i575fmHOXYPGWdaaSqt7cdgpfhPvnbIwhavslgbj9g9LNzffH7fea4P6BobKakb1AZuOfahJfarqfOJ2pYuRSQ==
|
||||
"@gitlab/ui@42.11.0":
|
||||
version "42.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.11.0.tgz#68b1cca7414a9f8e6d7e18ab8325daac000588f8"
|
||||
integrity sha512-IxawSvXyL4ysvriOcQ+2TpdEzZxDumj9H/K3MTxmvKYtrFEygNE7wCPasQa3/jxmdfn6sYuPDHVg1tk1ziXyVQ==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.11.2"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
Loading…
Reference in New Issue