summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/jira_connect/events_controller.rb2
-rw-r--r--app/graphql/mutations/ci/job_token_scope/remove_project.rb49
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/models/ci/job_token/project_scope_link.rb4
-rw-r--r--app/models/concerns/issuable.rb5
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/services/ci/job_token_scope/add_project_service.rb31
-rw-r--r--app/services/ci/job_token_scope/remove_project_service.rb31
-rw-r--r--app/services/concerns/ci/job_token_scope/edit_scope_validations.rb26
-rw-r--r--app/services/incident_management/incidents/create_service.rb9
-rw-r--r--app/services/incident_management/incidents/update_severity_service.rb38
-rw-r--r--app/services/issuable_base_service.rb19
-rw-r--r--app/services/issues/update_service.rb9
-rw-r--r--app/services/jira_connect_installations/destroy_service.rb24
-rw-r--r--app/views/shared/_new_project_item_select.html.haml2
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/jira_connect/forward_event_worker.rb25
-rw-r--r--doc/administration/auth/ldap/ldap-troubleshooting.md2
-rw-r--r--doc/administration/database_load_balancing.md6
-rw-r--r--doc/administration/geo/replication/datatypes.md2
-rw-r--r--doc/administration/geo/replication/version_specific_updates.md2
-rw-r--r--doc/administration/geo/setup/database.md34
-rw-r--r--doc/administration/geo/setup/external_database.md4
-rw-r--r--doc/administration/job_logs.md2
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md2
-rw-r--r--doc/administration/packages/container_registry.md2
-rw-r--r--doc/administration/reference_architectures/10k_users.md4
-rw-r--r--doc/administration/reference_architectures/25k_users.md4
-rw-r--r--doc/administration/reference_architectures/3k_users.md6
-rw-r--r--doc/administration/reference_architectures/50k_users.md4
-rw-r--r--doc/administration/reference_architectures/5k_users.md4
-rw-r--r--doc/administration/repository_storage_paths.md2
-rw-r--r--doc/administration/troubleshooting/debug.md2
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md6
-rw-r--r--doc/api/graphql/getting_started.md2
-rw-r--r--doc/api/graphql/reference/index.md21
-rw-r--r--doc/api/index.md2
-rw-r--r--doc/api/repositories.md2
-rw-r--r--doc/api/status_checks.md2
-rw-r--r--doc/ci/docker/using_docker_build.md2
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md2
-rw-r--r--doc/ci/runners/build_cloud/linux_build_cloud.md1
-rw-r--r--doc/development/api_graphql_styleguide.md2
-rw-r--r--doc/development/background_migrations.md8
-rw-r--r--doc/development/changelog.md2
-rw-r--r--doc/development/dangerbot.md5
-rw-r--r--doc/development/database/pagination_performance_guidelines.md2
-rw-r--r--doc/development/database/rename_database_tables.md2
-rw-r--r--doc/development/documentation/testing.md2
-rw-r--r--doc/development/fe_guide/performance.md14
-rw-r--r--doc/development/fe_guide/storybook.md2
-rw-r--r--doc/development/foreign_keys.md2
-rw-r--r--doc/development/pipelines.md81
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/frontend_testing.md7
-rw-r--r--doc/topics/autodevops/quick_start_guide.md2
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/index.md2
-rw-r--r--doc/topics/gitlab_flow.md2
-rw-r--r--doc/user/admin_area/moderate_users.md2
-rw-r--r--doc/user/application_security/dast/browser_based.md4
-rw-r--r--doc/user/application_security/dast/index.md4
-rw-r--r--doc/user/application_security/dependency_list/index.md2
-rw-r--r--doc/user/application_security/sast/index.md4
-rw-r--r--doc/user/application_security/vulnerability_report/index.md4
-rw-r--r--doc/user/clusters/management_project_template.md14
-rw-r--r--doc/user/clusters/migrating_from_gma_to_project_template.md6
-rw-r--r--doc/user/discussions/index.md4
-rw-r--r--doc/user/group/saml_sso/index.md4
-rw-r--r--doc/user/group/value_stream_analytics/index.md2
-rw-r--r--doc/user/packages/container_registry/index.md2
-rw-r--r--doc/user/packages/npm_registry/index.md6
-rw-r--r--doc/user/packages/package_registry/index.md2
-rw-r--r--doc/user/profile/account/two_factor_authentication.md2
-rw-r--r--doc/user/project/code_owners.md2
-rw-r--r--doc/user/project/import/bitbucket_server.md2
-rw-r--r--doc/user/project/members/index.md6
-rw-r--r--doc/user/project/service_desk.md8
-rw-r--r--lib/gitlab/hook_data/issue_builder.rb4
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/controllers/jira_connect/events_controller_spec.rb29
-rw-r--r--spec/frontend/fixtures/projects.rb3
-rw-r--r--spec/frontend/fixtures/releases.rb8
-rw-r--r--spec/frontend/fixtures/runner.rb9
-rw-r--r--spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb68
-rw-r--r--spec/graphql/mutations/issues/set_severity_spec.rb2
-rw-r--r--spec/lib/gitlab/hook_data/issue_builder_spec.rb1
-rw-r--r--spec/models/ci/job_token/project_scope_link_spec.rb18
-rw-r--r--spec/models/concerns/issuable_spec.rb20
-rw-r--r--spec/models/integrations/buildkite_spec.rb32
-rw-r--r--spec/models/integrations/custom_issue_tracker_spec.rb10
-rw-r--r--spec/models/integrations/emails_on_push_spec.rb14
-rw-r--r--spec/models/integrations/open_project_spec.rb8
-rw-r--r--spec/models/integrations/pivotaltracker_spec.rb26
-rw-r--r--spec/models/integrations/youtrack_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb84
-rw-r--r--spec/services/ci/job_token_scope/add_project_service_spec.rb72
-rw-r--r--spec/services/ci/job_token_scope/remove_project_service_spec.rb45
-rw-r--r--spec/services/incident_management/incidents/update_severity_service_spec.rb86
-rw-r--r--spec/services/issues/update_service_spec.rb145
-rw-r--r--spec/services/jira_connect_installations/destroy_service_spec.rb41
-rw-r--r--spec/support/helpers/javascript_fixtures_helpers.rb14
-rw-r--r--spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb40
-rw-r--r--spec/workers/jira_connect/forward_event_worker_spec.rb56
104 files changed, 977 insertions, 495 deletions
diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb
index d833491b8f7..fe66e742c44 100644
--- a/app/controllers/jira_connect/events_controller.rb
+++ b/app/controllers/jira_connect/events_controller.rb
@@ -19,7 +19,7 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
end
def uninstalled
- if current_jira_installation.destroy
+ if JiraConnectInstallations::DestroyService.execute(current_jira_installation, jira_connect_base_path, jira_connect_events_uninstalled_path)
head :ok
else
head :unprocessable_entity
diff --git a/app/graphql/mutations/ci/job_token_scope/remove_project.rb b/app/graphql/mutations/ci/job_token_scope/remove_project.rb
new file mode 100644
index 00000000000..71c9083bef8
--- /dev/null
+++ b/app/graphql/mutations/ci/job_token_scope/remove_project.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module JobTokenScope
+ class RemoveProject < BaseMutation
+ include FindsProject
+
+ graphql_name 'CiJobTokenScopeRemoveProject'
+
+ authorize :admin_project
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project that the CI job token scope belongs to.'
+
+ argument :target_project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project to be removed from the CI job token scope.'
+
+ field :ci_job_token_scope,
+ Types::Ci::JobTokenScopeType,
+ null: true,
+ description: "The CI job token's scope of access."
+
+ def resolve(project_path:, target_project_path:)
+ project = authorized_find!(project_path)
+ target_project = Project.find_by_full_path(target_project_path)
+
+ result = ::Ci::JobTokenScope::RemoveProjectService
+ .new(project, current_user)
+ .execute(target_project)
+
+ if result.success?
+ {
+ ci_job_token_scope: ::Ci::JobToken::Scope.new(project),
+ errors: []
+ }
+ else
+ {
+ ci_job_token_scope: nil,
+ errors: [result.message]
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 7c4d5c06628..c9f5fd5ec9c 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -100,6 +100,7 @@ module Types
mount_mutation Mutations::Ci::Job::Play
mount_mutation Mutations::Ci::Job::Retry
mount_mutation Mutations::Ci::JobTokenScope::AddProject
+ mount_mutation Mutations::Ci::JobTokenScope::RemoveProject
mount_mutation Mutations::Ci::Runner::Update, feature_flag: :runner_graphql_query
mount_mutation Mutations::Ci::Runner::Delete, feature_flag: :runner_graphql_query
mount_mutation Mutations::Ci::RunnersRegistrationToken::Reset, feature_flag: :runner_graphql_query
diff --git a/app/models/ci/job_token/project_scope_link.rb b/app/models/ci/job_token/project_scope_link.rb
index 283ad4a190d..99118f8090b 100644
--- a/app/models/ci/job_token/project_scope_link.rb
+++ b/app/models/ci/job_token/project_scope_link.rb
@@ -19,6 +19,10 @@ module Ci
validates :target_project, presence: true
validate :not_self_referential_link
+ def self.for_source_and_target(source_project, target_project)
+ self.find_by(source_project: source_project, target_project: target_project)
+ end
+
private
def not_self_referential_link
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 9424bcf0424..e6419dff092 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -459,6 +459,7 @@ module Issuable
if old_associations
old_labels = old_associations.fetch(:labels, labels)
old_assignees = old_associations.fetch(:assignees, assignees)
+ old_severity = old_associations.fetch(:severity, severity)
if old_labels != labels
changes[:labels] = [old_labels.map(&:hook_attrs), labels.map(&:hook_attrs)]
@@ -468,6 +469,10 @@ module Issuable
changes[:assignees] = [old_assignees.map(&:hook_attrs), assignees.map(&:hook_attrs)]
end
+ if supports_severity? && old_severity != severity
+ changes[:severity] = [old_severity, severity]
+ end
+
if self.respond_to?(:total_time_spent)
old_total_time_spent = old_associations.fetch(:total_time_spent, total_time_spent)
old_time_change = old_associations.fetch(:time_change, time_change)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 48f388ea48d..6816b479d7a 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -80,6 +80,7 @@ class Issue < ApplicationRecord
has_and_belongs_to_many :prometheus_alert_events, join_table: :issues_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
has_many :prometheus_alerts, through: :prometheus_alert_events
+ accepts_nested_attributes_for :issuable_severity, update_only: true
accepts_nested_attributes_for :sentry_issue
validates :project, presence: true
diff --git a/app/services/ci/job_token_scope/add_project_service.rb b/app/services/ci/job_token_scope/add_project_service.rb
index 6ae0a8428c2..d03ae434b69 100644
--- a/app/services/ci/job_token_scope/add_project_service.rb
+++ b/app/services/ci/job_token_scope/add_project_service.rb
@@ -3,13 +3,10 @@
module Ci
module JobTokenScope
class AddProjectService < ::BaseService
- TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND = "The target_project that you are attempting to access does " \
- "not exist or you don't have permission to perform this action"
+ include EditScopeValidations
def execute(target_project)
- if error_response = validation_error(target_project)
- return error_response
- end
+ validate_edit!(project, target_project, current_user)
link = add_project!(target_project)
ServiceResponse.success(payload: { project_link: link })
@@ -18,28 +15,8 @@ module Ci
ServiceResponse.error(message: "Target project is already in the job token scope")
rescue ActiveRecord::RecordInvalid => e
ServiceResponse.error(message: e.message)
- end
-
- private
-
- def validation_error(target_project)
- unless project.ci_job_token_scope_enabled?
- return ServiceResponse.error(message: "Job token scope is disabled for this project")
- end
-
- unless can?(current_user, :admin_project, project)
- return ServiceResponse.error(message: "Insufficient permissions to modify the job token scope")
- end
-
- unless target_project
- return ServiceResponse.error(message: TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
- end
-
- unless can?(current_user, :read_project, target_project)
- return ServiceResponse.error(message: TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
- end
-
- nil
+ rescue EditScopeValidations::ValidationError => e
+ ServiceResponse.error(message: e.message)
end
def add_project!(target_project)
diff --git a/app/services/ci/job_token_scope/remove_project_service.rb b/app/services/ci/job_token_scope/remove_project_service.rb
new file mode 100644
index 00000000000..15644e529d9
--- /dev/null
+++ b/app/services/ci/job_token_scope/remove_project_service.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Ci
+ module JobTokenScope
+ class RemoveProjectService < ::BaseService
+ include EditScopeValidations
+
+ def execute(target_project)
+ validate_edit!(project, target_project, current_user)
+
+ if project == target_project
+ return ServiceResponse.error(message: "Source project cannot be removed from the job token scope")
+ end
+
+ link = ::Ci::JobToken::ProjectScopeLink.for_source_and_target(project, target_project)
+
+ unless link
+ return ServiceResponse.error(message: "Target project is not in the job token scope")
+ end
+
+ if link.destroy
+ ServiceResponse.success
+ else
+ ServiceResponse.error(message: link.errors.full_messages.to_sentence, payload: { project_link: link })
+ end
+ rescue EditScopeValidations::ValidationError => e
+ ServiceResponse.error(message: e.message)
+ end
+ end
+ end
+end
diff --git a/app/services/concerns/ci/job_token_scope/edit_scope_validations.rb b/app/services/concerns/ci/job_token_scope/edit_scope_validations.rb
new file mode 100644
index 00000000000..23053975313
--- /dev/null
+++ b/app/services/concerns/ci/job_token_scope/edit_scope_validations.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Ci
+ module JobTokenScope
+ module EditScopeValidations
+ ValidationError = Class.new(StandardError)
+
+ TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND = "The target_project that you are attempting to access does " \
+ "not exist or you don't have permission to perform this action"
+
+ def validate_edit!(source_project, target_project, current_user)
+ unless source_project.ci_job_token_scope_enabled?
+ raise ValidationError, "Job token scope is disabled for this project"
+ end
+
+ unless can?(current_user, :admin_project, source_project)
+ raise ValidationError, "Insufficient permissions to modify the job token scope"
+ end
+
+ unless can?(current_user, :read_project, target_project)
+ raise ValidationError, TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/incident_management/incidents/create_service.rb b/app/services/incident_management/incidents/create_service.rb
index 5d92a33eb2b..f8437290d9b 100644
--- a/app/services/incident_management/incidents/create_service.rb
+++ b/app/services/incident_management/incidents/create_service.rb
@@ -20,15 +20,14 @@ module IncidentManagement
params: {
title: title,
description: description,
- issue_type: ISSUE_TYPE
+ issue_type: ISSUE_TYPE,
+ severity: severity
},
spam_params: nil
).execute
return error(issue.errors.full_messages.to_sentence, issue) unless issue.valid?
- update_severity_for(issue)
-
success(issue)
end
@@ -43,10 +42,6 @@ module IncidentManagement
def error(message, issue = nil)
ServiceResponse.error(payload: { issue: issue }, message: message)
end
-
- def update_severity_for(issue)
- ::IncidentManagement::Incidents::UpdateSeverityService.new(issue, current_user, severity).execute
- end
end
end
end
diff --git a/app/services/incident_management/incidents/update_severity_service.rb b/app/services/incident_management/incidents/update_severity_service.rb
deleted file mode 100644
index faa9277c469..00000000000
--- a/app/services/incident_management/incidents/update_severity_service.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module IncidentManagement
- module Incidents
- class UpdateSeverityService < BaseService
- def initialize(issuable, current_user, severity)
- super(issuable.project, current_user)
-
- @issuable = issuable
- @severity = severity.to_s.downcase
- @severity = IssuableSeverity::DEFAULT unless IssuableSeverity.severities.key?(@severity)
- end
-
- def execute
- return unless issuable.supports_severity?
-
- update_severity!
- add_system_note
- end
-
- private
-
- attr_reader :issuable, :severity
-
- def issuable_severity
- issuable.issuable_severity || issuable.build_issuable_severity(issue_id: issuable.id)
- end
-
- def update_severity!
- issuable_severity.update!(severity: severity)
- end
-
- def add_system_note
- ::IncidentManagement::AddSeveritySystemNoteWorker.perform_async(issuable.id, current_user.id)
- end
- end
- end
-end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 02c1f078a40..8d65865e7da 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -57,6 +57,7 @@ class IssuableBaseService < ::BaseProjectService
filter_assignees(issuable)
filter_milestone
filter_labels
+ filter_severity(issuable)
end
def filter_assignees(issuable)
@@ -135,6 +136,16 @@ class IssuableBaseService < ::BaseProjectService
@labels_service ||= ::Labels::AvailableLabelsService.new(current_user, parent, params)
end
+ def filter_severity(issuable)
+ severity = params.delete(:severity)
+ return unless severity && issuable.supports_severity?
+
+ severity = IssuableSeverity::DEFAULT unless IssuableSeverity.severities.key?(severity)
+ return if severity == issuable.severity
+
+ params[:issuable_severity_attributes] = { severity: severity }
+ end
+
def process_label_ids(attributes, existing_label_ids: nil, extra_label_ids: [])
label_ids = attributes.delete(:label_ids)
add_label_ids = attributes.delete(:add_label_ids)
@@ -352,7 +363,6 @@ class IssuableBaseService < ::BaseProjectService
def change_additional_attributes(issuable)
change_state(issuable)
- change_severity(issuable)
change_subscription(issuable)
change_todo(issuable)
toggle_award(issuable)
@@ -371,12 +381,6 @@ class IssuableBaseService < ::BaseProjectService
end
end
- def change_severity(issuable)
- if severity = params.delete(:severity)
- ::IncidentManagement::Incidents::UpdateSeverityService.new(issuable, current_user, severity).execute
- end
- end
-
def change_subscription(issuable)
case params.delete(:subscription_event)
when 'subscribe'
@@ -443,6 +447,7 @@ class IssuableBaseService < ::BaseProjectService
associations[:time_change] = issuable.time_change if issuable.respond_to?(:time_change)
associations[:description] = issuable.description
associations[:reviewers] = issuable.reviewers.to_a if issuable.allows_reviewers?
+ associations[:severity] = issuable.severity if issuable.supports_severity?
associations
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index dc442a2fca1..9ede5ef728b 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -42,6 +42,7 @@ module Issues
old_labels = old_associations.fetch(:labels, [])
old_mentioned_users = old_associations.fetch(:mentioned_users, [])
old_assignees = old_associations.fetch(:assignees, [])
+ old_severity = old_associations[:severity]
if has_changes?(issue, old_labels: old_labels, old_assignees: old_assignees)
todo_service.resolve_todos_for_target(issue, current_user)
@@ -74,6 +75,8 @@ module Issues
if added_mentions.present?
notification_service.async.new_mentions_in_issue(issue, added_mentions, current_user)
end
+
+ handle_severity_change(issue, old_severity)
end
def handle_assignee_changes(issue, old_assignees)
@@ -181,6 +184,12 @@ module Issues
end
end
+ def handle_severity_change(issue, old_severity)
+ return unless old_severity && issue.severity != old_severity
+
+ ::IncidentManagement::AddSeveritySystemNoteWorker.perform_async(issue.id, current_user.id)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def issuable_for_positioning(id, board_group_id = nil)
return unless id
diff --git a/app/services/jira_connect_installations/destroy_service.rb b/app/services/jira_connect_installations/destroy_service.rb
new file mode 100644
index 00000000000..cfe58575dcf
--- /dev/null
+++ b/app/services/jira_connect_installations/destroy_service.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module JiraConnectInstallations
+ class DestroyService
+ def self.execute(installation, jira_connect_base_path, jira_connect_uninstalled_event_path)
+ new(installation, jira_connect_base_path, jira_connect_uninstalled_event_path).execute
+ end
+
+ def initialize(installation, jira_connect_base_path, jira_connect_uninstalled_event_path)
+ @installation = installation
+ @jira_connect_base_path = jira_connect_base_path
+ @jira_connect_uninstalled_event_path = jira_connect_uninstalled_event_path
+ end
+
+ def execute
+ if @installation.instance_url.present?
+ JiraConnect::ForwardEventWorker.perform_async(@installation.id, @jira_connect_base_path, @jira_connect_uninstalled_event_path)
+ return true
+ end
+
+ @installation.destroy
+ end
+ end
+end
diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml
index 3817ff8a56d..d5f4add2796 100644
--- a/app/views/shared/_new_project_item_select.html.haml
+++ b/app/views/shared/_new_project_item_select.html.haml
@@ -1,5 +1,5 @@
- if any_projects?(@projects)
- .project-item-select-holder.btn-group.gl-ml-auto.gl-mr-auto.gl-py-3.gl-relative.gl-display-flex.gl-overflow-hidden
+ .project-item-select-holder.btn-group.gl-ml-auto.gl-mr-auto.gl-relative.gl-overflow-hidden{ class: 'gl-display-flex!' }
%a.btn.gl-button.btn-confirm.new-project-item-link.block-truncated.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] }, class: "gl-m-0!" }
= loading_icon(color: 'light')
= project_select_tag :project_path, class: "project-item-select gl-absolute! gl-visibility-hidden", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled]
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 61edd4b91e3..aaa6edcd0cf 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -1078,6 +1078,15 @@
:weight: 2
:idempotent: true
:tags: []
+- :name: jira_connect:jira_connect_forward_event
+ :worker_name: JiraConnect::ForwardEventWorker
+ :feature_category: :integrations
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent:
+ :tags: []
- :name: jira_connect:jira_connect_sync_branch
:worker_name: JiraConnect::SyncBranchWorker
:feature_category: :integrations
diff --git a/app/workers/jira_connect/forward_event_worker.rb b/app/workers/jira_connect/forward_event_worker.rb
new file mode 100644
index 00000000000..877ab46cfe5
--- /dev/null
+++ b/app/workers/jira_connect/forward_event_worker.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module JiraConnect
+ class ForwardEventWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ queue_namespace :jira_connect
+ feature_category :integrations
+ worker_has_external_dependencies!
+
+ def perform(installation_id, base_path, event_path)
+ installation = JiraConnectInstallation.find_by_id(installation_id)
+
+ return if installation&.instance_url.nil?
+
+ proxy_url = installation.instance_url + event_path
+ qsh = Atlassian::Jwt.create_query_string_hash(proxy_url, 'POST', installation.instance_url + base_path)
+ jwt = Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)
+
+ Gitlab::HTTP.post(proxy_url, headers: { 'Authorization' => "JWT #{jwt}" })
+ ensure
+ installation.destroy if installation
+ end
+ end
+end
diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md
index 1215d90134f..5e6c3443e44 100644
--- a/doc/administration/auth/ldap/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap/ldap-troubleshooting.md
@@ -552,7 +552,7 @@ LDAP.
If the email has changed and the DN has not, GitLab finds the user with
the DN and update its own record of the user's email to match the one in LDAP.
-However, if the primary email _and_ the DN change in LDAP, then GitLab
+However, if the primary email _and_ the DN change in LDAP, then GitLab
has no way of identifying the correct LDAP record of the user and, as a
result, the user is blocked. To rectify this, the user's existing
profile must be updated with at least one of the new values (primary
diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md
index 1c1066c8e12..1aa01ae1f64 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -109,17 +109,17 @@ the following. This balances the load between `host1.example.com` and
Sidekiq mostly writes to the database, which means that most of its traffic hits the
primary database.
-Some background jobs can use database replicas to read application state.
+Some background jobs can use database replicas to read application state.
This allows to offload the primary database.
Load balancing is disabled by default in Sidekiq. When enabled, we can define
[the data consistency](../development/sidekiq_style_guide.md#job-data-consistency-strategies)
requirements for a specific job.
-To enable it, define the `ENABLE_LOAD_BALANCING_FOR_SIDEKIQ` variable to the environment, as shown below.
+To enable it, define the `ENABLE_LOAD_BALANCING_FOR_SIDEKIQ` variable to the environment, as shown below.
For Omnibus installations:
-
+
```ruby
gitlab_rails['env'] = {"ENABLE_LOAD_BALANCING_FOR_SIDEKIQ" => "true"}
```
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index 6989765dbad..a56d9dc813c 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -209,6 +209,6 @@ successfully, you must replicate their data using some other means.
#### Limitation of verification for files in Object Storage
-GitLab managed Object Storage replication support [is in beta](object_storage.md#enabling-gitlab-managed-object-storage-replication).
+GitLab managed Object Storage replication support [is in beta](object_storage.md#enabling-gitlab-managed-object-storage-replication).
Locally stored files are verified but remote stored files are not.
diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md
index 557f93c3712..b8f847d163c 100644
--- a/doc/administration/geo/replication/version_specific_updates.md
+++ b/doc/administration/geo/replication/version_specific_updates.md
@@ -13,7 +13,7 @@ for updating Geo nodes.
## Updating to GitLab 13.11
-We found an [issue with Git clone/pull through HTTP(s)](https://gitlab.com/gitlab-org/gitlab/-/issues/330787) on Geo secondaries and on any GitLab instance if maintenance mode is enabled. This was caused by a regression in GitLab Workhorse. This is fixed in the [GitLab 13.11.4 patch release](https://about.gitlab.com/releases/2021/05/14/gitlab-13-11-4-released/). To avoid this issue, upgrade to GitLab 13.11.4 or later.
+We found an [issue with Git clone/pull through HTTP(s)](https://gitlab.com/gitlab-org/gitlab/-/issues/330787) on Geo secondaries and on any GitLab instance if maintenance mode is enabled. This was caused by a regression in GitLab Workhorse. This is fixed in the [GitLab 13.11.4 patch release](https://about.gitlab.com/releases/2021/05/14/gitlab-13-11-4-released/). To avoid this issue, upgrade to GitLab 13.11.4 or later.
## Updating to GitLab 13.9
diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md
index a5a6311287c..a3b48476941 100644
--- a/doc/administration/geo/setup/database.md
+++ b/doc/administration/geo/setup/database.md
@@ -31,17 +31,17 @@ A single instance database replication is easier to set up and still provides th
as a clusterized alternative. It's useful for setups running on a single machine
or trying to evaluate Geo for a future clusterized installation.
-A single instance can be expanded to a clusterized version using Patroni, which is recommended for a
+A single instance can be expanded to a clusterized version using Patroni, which is recommended for a
highly available architecture.
-Follow below the instructions on how to set up PostgreSQL replication as a single instance database.
-Alternatively, you can look at the [Multi-node database replication](#multi-node-database-replication)
+Follow below the instructions on how to set up PostgreSQL replication as a single instance database.
+Alternatively, you can look at the [Multi-node database replication](#multi-node-database-replication)
instructions on setting up replication with a Patroni cluster.
### PostgreSQL replication
The GitLab **primary** node where the write operations happen connects to
-the **primary** database server, and **secondary** nodes
+the **primary** database server, and **secondary** nodes
connect to their own database servers (which are also read-only).
We recommend using [PostgreSQL replication slots](https://medium.com/@tk512/replication-slots-in-postgresql-b4b03d277c75)
@@ -112,13 +112,13 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
# must be present in all application nodes.
gitlab_rails['db_password'] = '<your_password_here>'
```
-
+
1. Define a password for the database [replication user](https://wiki.postgresql.org/wiki/Streaming_Replication).
We will use the username defined in `/etc/gitlab/gitlab.rb` under the `postgresql['sql_replication_user']`
- setting. The default value is `gitlab_replicator`, but if you changed it to something else, adapt
+ setting. The default value is `gitlab_replicator`, but if you changed it to something else, adapt
the instructions below.
-
+
Generate a MD5 hash of the desired password:
```shell
@@ -484,12 +484,12 @@ The replication process is now complete.
### PgBouncer support (optional)
[PgBouncer](https://www.pgbouncer.org/) may be used with GitLab Geo to pool
-PostgreSQL connections, which can improve performance even when using in a
-single instance installation.
+PostgreSQL connections, which can improve performance even when using in a
+single instance installation.
We recommend using PgBouncer if you use GitLab in a highly available
-configuration with a cluster of nodes supporting a Geo **primary** site and
-two other clusters of nodes supporting a Geo **secondary** site. One for the
+configuration with a cluster of nodes supporting a Geo **primary** site and
+two other clusters of nodes supporting a Geo **secondary** site. One for the
main database and the other for the tracking database. For more information,
see [High Availability with Omnibus GitLab](../../postgresql/replication_and_failover.md).
@@ -505,7 +505,7 @@ If you still haven't [migrated from repmgr to Patroni](#migrating-from-repmgr-to
Patroni is the official replication management solution for Geo. It
can be used to build a highly available cluster on the **primary** and a **secondary** Geo site.
-Using Patroni on a **secondary** site is optional and you don't have to use the same amount of
+Using Patroni on a **secondary** site is optional and you don't have to use the same amount of
nodes on each Geo site.
For instructions about how to set up Patroni on the primary site, see the
@@ -515,7 +515,7 @@ For instructions about how to set up Patroni on the primary site, see the
In a Geo secondary site, the main PostgreSQL database is a read-only replica of the primary site’s PostgreSQL database.
-If you are currently using `repmgr` on your Geo primary site, see [these instructions](#migrating-from-repmgr-to-patroni)
+If you are currently using `repmgr` on your Geo primary site, see [these instructions](#migrating-from-repmgr-to-patroni)
for migrating from `repmgr` to Patroni.
A production-ready and secure setup requires at least:
@@ -526,9 +526,9 @@ A production-ready and secure setup requires at least:
- 1 internal load-balancer _(primary site only)_
The internal load balancer provides a single endpoint for connecting to the Patroni cluster's leader whenever a new leader is
-elected, and it is required for enabling cascading replication from the secondary sites.
+elected, and it is required for enabling cascading replication from the secondary sites.
-Be sure to use [password credentials](../../postgresql/replication_and_failover.md#database-authorization-for-patroni)
+Be sure to use [password credentials](../../postgresql/replication_and_failover.md#database-authorization-for-patroni)
and other database best practices.
##### Step 1. Configure Patroni permanent replication slot on the primary site
@@ -790,13 +790,13 @@ Secondary sites use a separate PostgreSQL installation as a tracking database to
keep track of replication status and automatically recover from potential replication issues.
Omnibus automatically configures a tracking database when `roles(['geo_secondary_role'])` is set.
-If you want to run this database in a highly available configuration, don't use the `geo_secondary_role` above.
+If you want to run this database in a highly available configuration, don't use the `geo_secondary_role` above.
Instead, follow the instructions below.
A production-ready and secure setup requires at least three Consul nodes, two
Patroni nodes and one PgBouncer node on the secondary site.
-Be sure to use [password credentials](../../postgresql/replication_and_failover.md#database-authorization-for-patroni)
+Be sure to use [password credentials](../../postgresql/replication_and_failover.md#database-authorization-for-patroni)
and other database best practices.
#### Step 1. Configure a PgBouncer node on the secondary site
diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md
index 9e187424afa..62b258afcf3 100644
--- a/doc/administration/geo/setup/external_database.md
+++ b/doc/administration/geo/setup/external_database.md
@@ -208,8 +208,8 @@ the tracking database on port 5432.
1. Set up PostgreSQL according to the
[database requirements document](../../../install/requirements.md#database).
1. Set up a `gitlab_geo` user with a password of your choice, create the `gitlabhq_geo_production` database, and make the user an owner of the database. You can see an example of this setup in the [installation from source documentation](../../../install/installation.md#6-database).
-1. If you are **not** using a cloud-managed PostgreSQL database, ensure that your secondary
- node can communicate with your tracking database by manually changing the
+1. If you are **not** using a cloud-managed PostgreSQL database, ensure that your secondary
+ node can communicate with your tracking database by manually changing the
`pg_hba.conf` that is associated with your tracking database.
Remember to restart PostgreSQL afterwards for the changes to take effect:
diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md
index d42444b4ec2..54a5bdaaf67 100644
--- a/doc/administration/job_logs.md
+++ b/doc/administration/job_logs.md
@@ -145,7 +145,7 @@ in `/var/opt/gitlab/gitlab-ci/builds` by Omnibus GitLab. After the job completes
a background job archives the job log. The log is moved to `/var/opt/gitlab/gitlab-rails/shared/artifacts/`
by default, or to object storage if configured.
-In a [scaled-out architecture](reference_architectures/index.md) with Rails and Sidekiq running on more than one
+In a [scaled-out architecture](reference_architectures/index.md) with Rails and Sidekiq running on more than one
server, these two locations on the filesystem have to be shared using NFS.
To eliminate both filesystem requirements:
diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md
index b910a789d29..34bf7214441 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -171,7 +171,7 @@ When disabling `sidekiq_cluster`, you must copy your configuration for
`sidekiq_cluster` is overridden by the options for `sidekiq` when
setting `sidekiq['cluster'] = true`.
-When using this feature, the service called `sidekiq` is now
+When using this feature, the service called `sidekiq` is now
running `sidekiq-cluster`.
The [concurrency](#manage-concurrency) and other options configured
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index a6829b90f18..15a93981ccb 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -1359,7 +1359,7 @@ For Omnibus installations:
[image upgrade](#images-upgrade)) steps. You should [stop](https://docs.gitlab.com/omnibus/maintenance/#starting-and-stopping)
the registry service before replacing its binary and start it right after. No registry
configuration changes are required.
-
+
#### Source installations
For source installations, locate your `registry` binary and temporarily replace it with the one
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index 55f5c977b02..f94a500746c 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -1605,7 +1605,7 @@ To configure the Praefect nodes, on each one:
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
-
+
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
@@ -1613,7 +1613,7 @@ To configure the Praefect nodes, on each one:
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
-
+
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect and
to run the Praefect database migrations.
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 1322f05f93a..aed54b236ce 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -1623,7 +1623,7 @@ the file of the same name on this server. If this is the first Omnibus node you
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
-
+
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
@@ -1631,7 +1631,7 @@ the file of the same name on this server. If this is the first Omnibus node you
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
-
+
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect and
to run the Praefect database migrations.
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index b2d153182e9..71ca67075d3 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -829,7 +829,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
username of `gitlab_replicator` (recommended). The command will request a password
and a confirmation. Use the value that is output by this command in the next step
as the value of `<postgresql_replication_password_hash>`:
-
+
```shell
sudo gitlab-ctl pg-password-md5 gitlab_replicator
```
@@ -1328,7 +1328,7 @@ the file of the same name on this server. If this is the first Omnibus node you
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
-
+
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
@@ -1336,7 +1336,7 @@ the file of the same name on this server. If this is the first Omnibus node you
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
-
+
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect and
to run the Praefect database migrations.
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 03c40eea153..51c80330329 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -1627,7 +1627,7 @@ the file of the same name on this server. If this is the first Omnibus node you
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
-
+
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
@@ -1635,7 +1635,7 @@ the file of the same name on this server. If this is the first Omnibus node you
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
-
+
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect and
to run the Praefect database migrations.
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index 563fad98f59..3456e1193bd 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -1320,7 +1320,7 @@ the file of the same name on this server. If this is the first Omnibus node you
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
-
+
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
@@ -1328,7 +1328,7 @@ the file of the same name on this server. If this is the first Omnibus node you
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
-
+
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect and
to run the Praefect database migrations.
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index a1391f3e0ed..3a80b922d1a 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -155,5 +155,5 @@ often it is chosen. That is, `(storage weight) / (sum of all weights) * 100 = ch
## Move repositories
-To move a repository to a different repository storage (for example, from `default` to `storage2`), use the
+To move a repository to a different repository storage (for example, from `default` to `storage2`), use the
same process as [migrating to Gitaly Cluster](gitaly/praefect.md#migrate-to-gitaly-cluster).
diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md
index 748bc95aa6c..04c83370b60 100644
--- a/doc/administration/troubleshooting/debug.md
+++ b/doc/administration/troubleshooting/debug.md
@@ -224,7 +224,7 @@ gitlab_rails['env'] = {
}
```
-For source installations, set the environment variable.
+For source installations, set the environment variable.
Refer to [Puma Worker timeout](https://docs.gitlab.com/omnibus/settings/puma.html#worker-timeout).
[Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index b6dc1907af5..c759ca4b168 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -348,10 +348,10 @@ end
puts "#{artifact_storage} bytes"
```
-### Identify deploy keys associated with blocked and non-member users
+### Identify deploy keys associated with blocked and non-member users
-When the user who created a deploy key is blocked or removed from the project, the key
-can no longer be used to push to protected branches in a private project (see [issue #329742](https://gitlab.com/gitlab-org/gitlab/-/issues/329742)).
+When the user who created a deploy key is blocked or removed from the project, the key
+can no longer be used to push to protected branches in a private project (see [issue #329742](https://gitlab.com/gitlab-org/gitlab/-/issues/329742)).
The following script identifies unusable deploy keys:
```ruby
diff --git a/doc/api/graphql/getting_started.md b/doc/api/graphql/getting_started.md
index e7ccc242866..ade3ad1f9b6 100644
--- a/doc/api/graphql/getting_started.md
+++ b/doc/api/graphql/getting_started.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This guide demonstrates basic usage of the GitLab GraphQL API.
-Read the [GraphQL API style guide](../../development/api_graphql_styleguide.md)
+Read the [GraphQL API style guide](../../development/api_graphql_styleguide.md)
for implementation details aimed at developers who wish to work on developing
the API itself.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 5e62a75ab49..82ea25fb514 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -800,6 +800,26 @@ Input type: `CiJobTokenScopeAddProjectInput`
| <a id="mutationcijobtokenscopeaddprojectclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcijobtokenscopeaddprojecterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.ciJobTokenScopeRemoveProject`
+
+Input type: `CiJobTokenScopeRemoveProjectInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationcijobtokenscoperemoveprojectclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationcijobtokenscoperemoveprojectprojectpath"></a>`projectPath` | [`ID!`](#id) | The project that the CI job token scope belongs to. |
+| <a id="mutationcijobtokenscoperemoveprojecttargetprojectpath"></a>`targetProjectPath` | [`ID!`](#id) | The project to be removed from the CI job token scope. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationcijobtokenscoperemoveprojectcijobtokenscope"></a>`ciJobTokenScope` | [`CiJobTokenScopeType`](#cijobtokenscopetype) | The CI job token's scope of access. |
+| <a id="mutationcijobtokenscoperemoveprojectclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationcijobtokenscoperemoveprojecterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.clusterAgentDelete`
Input type: `ClusterAgentDeleteInput`
@@ -11180,6 +11200,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="pipelinesecurityreportfindingsreporttype"></a>`reportType` | [`[String!]`](#string) | Filter vulnerability findings by report type. |
| <a id="pipelinesecurityreportfindingsscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerability findings by Scanner.externalId. |
| <a id="pipelinesecurityreportfindingsseverity"></a>`severity` | [`[String!]`](#string) | Filter vulnerability findings by severity. |
+| <a id="pipelinesecurityreportfindingsstate"></a>`state` | [`[VulnerabilityState!]`](#vulnerabilitystate) | Filter vulnerability findings by state. |
##### `Pipeline.testSuite`
diff --git a/doc/api/index.md b/doc/api/index.md
index b05e0efa455..e4b7cc56aab 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -61,7 +61,7 @@ version number.
New features and bug fixes are released in tandem with GitLab. Apart
from incidental patch and security releases, GitLab is released on the 22nd of each
-month. Major API version changes, and removal of entire API versions, are done in tandem
+month. Major API version changes, and removal of entire API versions, are done in tandem
with major GitLab releases.
All deprecations and changes between versions are in the documentation.
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 4212377b684..7e50a2c9f4c 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -313,7 +313,7 @@ Supported attributes:
WARNING:
GitLab treats trailers case-sensitively. If you set the `trailer` field to
-`Example`, GitLab _won't_ include commits that use the trailer `example`,
+`Example`, GitLab _won't_ include commits that use the trailer `example`,
`eXaMpLE`, or anything else that isn't _exactly_ `Example`.
If the `from` attribute is unspecified, GitLab uses the Git tag of the last
diff --git a/doc/api/status_checks.md b/doc/api/status_checks.md
index 4d117b7b3b7..22f56ea191f 100644
--- a/doc/api/status_checks.md
+++ b/doc/api/status_checks.md
@@ -12,7 +12,7 @@ type: reference, api
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-external-status-checks).
-
+
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index fb45d8f295c..c56bc9a4dc8 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -25,7 +25,7 @@ To enable Docker commands for your CI/CD jobs, you can use:
If you don't want to execute a runner in privileged mode,
but want to use `docker build`, you can also [use kaniko](using_kaniko.md).
-If you are using shared runners on GitLab.com,
+If you are using shared runners on GitLab.com,
[learn more about how these runners are configured](../runners/index.md).
### Use the shell executor
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 410d5ff5100..1bd4d09bcf5 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -204,7 +204,7 @@ read_secrets:
```
NOTE:
-If you're using a Vault instance provided by HashiCorp Cloud Platform,
+If you're using a Vault instance provided by HashiCorp Cloud Platform,
you need to export the `VAULT_NAMESPACE` variable. Its default value is `admin`.
![read_secrets staging](img/vault-read-secrets-staging.png)
diff --git a/doc/ci/runners/build_cloud/linux_build_cloud.md b/doc/ci/runners/build_cloud/linux_build_cloud.md
index 63517c49a79..710054921ef 100644
--- a/doc/ci/runners/build_cloud/linux_build_cloud.md
+++ b/doc/ci/runners/build_cloud/linux_build_cloud.md
@@ -27,7 +27,6 @@ Below are the shared runners settings.
| Setting | GitLab.com | Default |
| ----------- | ----------------- | ---------- |
-| [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) | [Runner versions dashboard](https://dashboards.gitlab.net/d/ci-runners-deployment/ci-runners-deployment-overview?orgId=1&refresh=1m) | - |
| Executor | `docker+machine` | - |
| Default Docker image | `ruby:2.5` | - |
| `privileged` (run [Docker in Docker](https://hub.docker.com/_/docker/)) | `true` | `false` |
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 2f3f00eb20c..ed00149e7a1 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -685,7 +685,7 @@ The API will also accept these types in the query signature for the argument:
- `IntegrationsPrometheusID`
NOTE:
-Although queries that use the old type (`PrometheusServiceID` in this example) will be
+Although queries that use the old type (`PrometheusServiceID` in this example) will be
considered valid and executable by the API, validator tools will consider them to be invalid.
This is because we are deprecating using a bespoke method outside of the
[`@deprecated` directive](https://spec.graphql.org/June2018/#sec--deprecated), so validators are not
diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md
index 0b81d40f585..26ec7d4f522 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/background_migrations.md
@@ -7,9 +7,9 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo
# Background migrations
-Background migrations should be used to perform data migrations whenever a
-migration exceeds [the time limits in our guidelines](database_review.md#timing-guidelines-for-migrations). For example, you can use background
-migrations to migrate data that's stored in a single JSON column
+Background migrations should be used to perform data migrations whenever a
+migration exceeds [the time limits in our guidelines](database_review.md#timing-guidelines-for-migrations). For example, you can use background
+migrations to migrate data that's stored in a single JSON column
to a separate table instead.
If the database cluster is considered to be in an unhealthy state, background
@@ -17,7 +17,7 @@ migrations automatically reschedule themselves for a later point in time.
## When To Use Background Migrations
-You should use a background migration when you migrate _data_ in tables that have
+You should use a background migration when you migrate _data_ in tables that have
so many rows that the process would exceed [the time limits in our guidelines](database_review.md#timing-guidelines-for-migrations) if performed using a regular Rails migration.
- Background migrations should be used when migrating data in [high-traffic tables](migration_style_guide.md#high-traffic-tables).
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index e05428ea826..c9d2d820c54 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -81,7 +81,7 @@ EE: true
- Any change that introduces a database migration, whether it's regular, post,
or data migration, **must** have a changelog entry, even if it is behind a
- disabled feature flag.
+ disabled feature flag.
- [Security fixes](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md)
**must** have a changelog entry, with `Changelog` trailer set to `security`.
- Any user-facing change **must** have a changelog entry. Example: "GitLab now
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
index 808ae22bb9e..8f5788785f0 100644
--- a/doc/development/dangerbot.md
+++ b/doc/development/dangerbot.md
@@ -153,8 +153,9 @@ Danger is run but its output is not added to a merge request comment if working
on a fork. This happens because the secret variable from the canonical project
is not shared to forks. To work around this, you can add an [environment
variable](../ci/variables/index.md) called `DANGER_GITLAB_API_TOKEN` with a
-personal API token to your fork. That way the danger comments are made from CI
-using that API token instead. Making the variable
+[personal API token](https://gitlab.com/-/profile/personal_access_tokens?name=GitLab+Dangerbot&scopes=api)
+to your fork that has the `api` scope set. That way the danger comments are made
+from CI using that API token instead. Making the variable
[masked](../ci/variables/index.md#mask-a-cicd-variable) makes sure it
doesn't show up in the job logs. The variable cannot be
[protected](../ci/variables/index.md#protect-a-cicd-variable), as it needs
diff --git a/doc/development/database/pagination_performance_guidelines.md b/doc/development/database/pagination_performance_guidelines.md
index ade1e853027..90e4faf2de7 100644
--- a/doc/development/database/pagination_performance_guidelines.md
+++ b/doc/development/database/pagination_performance_guidelines.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
---
# Pagination performance guidelines
-
+
The following document gives a few ideas for improving the pagination (sorting) performance. These apply both on [offset](pagination_guidelines.md#offset-pagination) and [keyset](pagination_guidelines.md#keyset-pagination) paginations.
## Tie-breaker column
diff --git a/doc/development/database/rename_database_tables.md b/doc/development/database/rename_database_tables.md
index 743558fae19..8ac50d2c0a0 100644
--- a/doc/development/database/rename_database_tables.md
+++ b/doc/development/database/rename_database_tables.md
@@ -81,7 +81,7 @@ Execute a standard migration (not a post-migration):
when naming indexes, so there is a possibility that not all indexes are properly renamed. After running
the migration locally, check if there are inconsistently named indexes (`db/structure.sql`). Those can be
renamed manually in a separate migration, which can be also part of the release M.N+1.
-- Foreign key columns might still contain the old table name. For smaller tables, follow our [standard column
+- Foreign key columns might still contain the old table name. For smaller tables, follow our [standard column
rename process](../avoiding_downtime_in_migrations.md#renaming-columns)
- Avoid renaming database tables which are using with triggers.
- Table modifications (add or remove columns) are not allowed during the rename process, please make sure that all changes to the table happen before the rename migration is started (or in the next release).
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index 95b3d4e47a7..ddd44801ae9 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -221,7 +221,7 @@ guidelines:
| *correctly-capitalized* name of a product or service | Add the word to the [vale spelling exceptions list](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/spelling-exceptions.txt). |
| name of a person | Remove the name if it's not needed, or [add the vale exception code in-line](#disable-vale-tests). |
| a command, variable, code, or similar | Put it in backticks or a code block. For example: ``The git clone command can be used with the CI_COMMIT_BRANCH variable.`` -> ``The `git clone` command can be used with the `CI_COMMIT_BRANCH` variable.`` |
-| UI text from GitLab | Verify it correctly matches the UI, then: <ul><li>If it does not match the UI, update it.</li><li>If it matches the UI, but the UI seems incorrect, create an issue to see if the UI needs to be fixed.</li><li>If it matches the UI and seems correct, add it to the [vale spelling exceptions list](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/spelling-exceptions.txt).</li></ul> |
+| UI text from GitLab | Verify it correctly matches the UI, then: If it does not match the UI, update it. If it matches the UI, but the UI seems incorrect, create an issue to see if the UI needs to be fixed. If it matches the UI and seems correct, add it to the [vale spelling exceptions list](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/spelling-exceptions.txt). |
| UI text from a third-party product | Rewrite the sentence to avoid it, or [add the vale exception code in-line](#disable-vale-tests). |
### Install linters
diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md
index dd3945ae324..c6784f3bb5f 100644
--- a/doc/development/fe_guide/performance.md
+++ b/doc/development/fe_guide/performance.md
@@ -256,17 +256,17 @@ We support two types of prefetching for the chunks:
- The [`prefetch` link type](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/prefetch)
is used to prefetch a chunk for the future navigation
- The [`preload` link type](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preloadh)
- is used to prefetch a chunk that is crucial for the current navigation but is not
+ is used to prefetch a chunk that is crucial for the current navigation but is not
discovered until later in the rendering process
-Both `prefetch` and `preload` links bring the loading performance benefit to the pages. Both are
+Both `prefetch` and `preload` links bring the loading performance benefit to the pages. Both are
fetched asynchronously, but contrary to [deferring the loading](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer)
of the assets which is used for other JavaScript resources in the product by default, `prefetch` and
-`preload` neither parse nor execute the fetched script unless explicitly imported in any JavaScript
-module. This allows to cache the fetched resources without blocking the execution of the
+`preload` neither parse nor execute the fetched script unless explicitly imported in any JavaScript
+module. This allows to cache the fetched resources without blocking the execution of the
remaining page resources.
-To prefetch a JavaScript chunk in a HAML view, `:prefetch_asset_tags` with the combination of
+To prefetch a JavaScript chunk in a HAML view, `:prefetch_asset_tags` with the combination of
the `webpack_preload_asset_tag` helper is provided:
```javascript
@@ -280,8 +280,8 @@ This snippet will add a new `<link rel="preload">` element into the resulting HT
<link rel="preload" href="/assets/webpack/monaco.chunk.js" as="script" type="text/javascript">
```
-By default, `webpack_preload_asset_tag` will `preload` the chunk. You don't need to worry about
-`as` and `type` attributes for preloading the JavaScript chunks. However, when a chunk is not
+By default, `webpack_preload_asset_tag` will `preload` the chunk. You don't need to worry about
+`as` and `type` attributes for preloading the JavaScript chunks. However, when a chunk is not
critical, for the current navigation, one has to explicitly request `prefetch`:
```javascript
diff --git a/doc/development/fe_guide/storybook.md b/doc/development/fe_guide/storybook.md
index c0adbb29b4b..eefca906837 100644
--- a/doc/development/fe_guide/storybook.md
+++ b/doc/development/fe_guide/storybook.md
@@ -43,7 +43,7 @@ To add a story:
```
1. Write the story as per the [official Storybook instructions](https://storybook.js.org/docs/vue/writing-stories/introduction)
-
+
Notes:
- Specify the `title` field of the story as the component's file path from the `javascripts/` directory,
e.g. if the component is located at `app/assets/javascripts/vue_shared/components/todo_button.vue`, specify the `title` as
diff --git a/doc/development/foreign_keys.md b/doc/development/foreign_keys.md
index 0c68e8a5b34..e234cf9a177 100644
--- a/doc/development/foreign_keys.md
+++ b/doc/development/foreign_keys.md
@@ -28,7 +28,7 @@ Guide](migration_style_guide.md) for more information.
Keep in mind that you can only safely add foreign keys to existing tables after
you have removed any orphaned rows. The method `add_concurrent_foreign_key`
-does not take care of this so you'll need to do so manually. See
+does not take care of this so you'll need to do so manually. See
[adding foreign key constraint to an existing column](database/add_foreign_key_to_existing_column.md).
## Cascading Deletes
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index bfa1b77a08d..dd51d981658 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -82,15 +82,15 @@ graph RL;
subgraph "No needed jobs";
1-1["danger-review (2.3 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
- 1-2["build-qa-image (1.6 minutes)"];
+ 1-2["build-qa-image (2 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
- 1-3["compile-test-assets (7 minutes)"];
+ 1-3["compile-test-assets (6 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
1-4["compile-test-assets as-if-foss (7 minutes)"];
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
- 1-5["compile-production-assets (19 minutes)"];
+ 1-5["compile-production-assets (14 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
- 1-6["setup-test-env (9 minutes)"];
+ 1-6["setup-test-env (4 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];
@@ -111,24 +111,24 @@ graph RL;
class 1-6 criticalPath;
end
- 2_1-1["graphql-verify (4 minutes)"];
+ 2_1-1["graphql-verify (2.3 minutes)"];
click 2_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356715&udv=0"
2_1-2["memory-static (4.75 minutes)"];
click 2_1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356721&udv=0"
- 2_1-3["run-dev-fixtures (6 minutes)"];
+ 2_1-3["run-dev-fixtures (3 minutes)"];
click 2_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356729&udv=0"
- 2_1-4["run-dev-fixtures-ee (6.75 minutes)"];
+ 2_1-4["run-dev-fixtures-ee (4 minutes)"];
click 2_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356731&udv=0"
subgraph "Needs `setup-test-env`";
2_1-1 & 2_1-2 & 2_1-3 & 2_1-4 --> 1-6;
end
- 2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (12 minutes)"];
+ 2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (11 minutes)"];
class 2_2-2 criticalPath;
click 2_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910143&udv=0"
- 2_2-4["memory-on-boot (6 minutes)"];
+ 2_2-4["memory-on-boot (3.5 minutes)"];
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
- 2_2-5["webpack-dev-server (4.5 minutes)"];
+ 2_2-5["webpack-dev-server (4 minutes)"];
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-test-assets`";
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
@@ -152,22 +152,22 @@ graph RL;
click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
end
- 3_1-1["jest (15 minutes)"];
+ 3_1-1["jest (16 minutes)"];
class 3_1-1 criticalPath;
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
- 3_1-2["karma (4 minutes)"];
+ 3_1-2["karma (2 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
subgraph "Needs `rspec frontend_fixture/rspec-ee frontend_fixture`";
3_1-1 & 3_1-2 --> 2_2-2;
end
- 3_2-1["rspec:coverage (4.6 minutes)"];
+ 3_2-1["rspec:coverage (5.3 minutes)"];
subgraph "Depends on `rspec` jobs";
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
end
- 4_1-1["coverage-frontend (2.75 minutes)"];
+ 4_1-1["coverage-frontend (2 minutes)"];
subgraph "Needs `jest`";
4_1-1 --> 3_1-1;
class 4_1-1 criticalPath;
@@ -186,15 +186,15 @@ graph RL;
subgraph "No needed jobs";
1-1["danger-review (2.3 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
- 1-2["build-qa-image (1.6 minutes)"];
+ 1-2["build-qa-image (2 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
- 1-3["compile-test-assets (7 minutes)"];
+ 1-3["compile-test-assets (6 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
1-4["compile-test-assets as-if-foss (7 minutes)"];
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
- 1-5["compile-production-assets (19 minutes)"];
+ 1-5["compile-production-assets (14 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
- 1-6["setup-test-env (9 minutes)"];
+ 1-6["setup-test-env (4 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];
@@ -216,24 +216,24 @@ graph RL;
class 1-6 criticalPath;
end
- 2_1-1["graphql-verify (4 minutes)"];
+ 2_1-1["graphql-verify (2.3 minutes)"];
click 2_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356715&udv=0"
2_1-2["memory-static (4.75 minutes)"];
click 2_1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356721&udv=0"
- 2_1-3["run-dev-fixtures (6 minutes)"];
+ 2_1-3["run-dev-fixtures (3 minutes)"];
click 2_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356729&udv=0"
- 2_1-4["run-dev-fixtures-ee (6.75 minutes)"];
+ 2_1-4["run-dev-fixtures-ee (4 minutes)"];
click 2_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356731&udv=0"
subgraph "Needs `setup-test-env`";
2_1-1 & 2_1-2 & 2_1-3 & 2_1-4 --> 1-6;
end
- 2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (12 minutes)"];
+ 2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (11 minutes)"];
class 2_2-2 criticalPath;
click 2_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910143&udv=0"
- 2_2-4["memory-on-boot (6 minutes)"];
+ 2_2-4["memory-on-boot (3.5 minutes)"];
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
- 2_2-5["webpack-dev-server (4.5 minutes)"];
+ 2_2-5["webpack-dev-server (4 minutes)"];
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-test-assets`";
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
@@ -258,51 +258,48 @@ graph RL;
click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
end
- 2_6-1["review-build-cng (27.3 minutes)"];
+ 2_6-1["review-build-cng (27 minutes)"];
subgraph "Needs `build-assets-image`";
2_6-1 --> 2_3-1;
class 2_6-1 criticalPath;
click 2_6-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914314&udv=0"
end
- 3_1-1["jest (15 minutes)"];
+ 3_1-1["jest (16 minutes)"];
class 3_1-1 criticalPath;
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
- 3_1-2["karma (4 minutes)"];
+ 3_1-2["karma (2 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
subgraph "Needs `rspec frontend_fixture/rspec-ee frontend_fixture`";
3_1-1 & 3_1-2 --> 2_2-2;
end
- 3_2-1["rspec:coverage (4.6 minutes)"];
+ 3_2-1["rspec:coverage (5.3 minutes)"];
subgraph "Depends on `rspec` jobs";
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
end
- 4_1-1["coverage-frontend (2.75 minutes)"];
+ 4_1-1["coverage-frontend (2 minutes)"];
subgraph "Needs `jest`";
4_1-1 --> 3_1-1;
class 4_1-1 criticalPath;
click 4_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910777&udv=0"
end
- 3_3-1["review-deploy (6 minutes)"];
+ 3_3-1["review-deploy (10.5 minutes)"];
subgraph "Played by `review-build-cng`";
3_3-1 --> 2_6-1;
class 3_3-1 criticalPath;
click 3_3-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6721130&udv=0"
end
- 4_2-1["review-qa-smoke (8 minutes)"];
+ 4_2-1["review-qa-smoke (7.4 minutes)"];
click 4_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6729805&udv=0"
- 4_2-2["review-performance (4 minutes)"];
+ 4_2-2["review-performance (2.5 minutes)"];
click 4_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356817&udv=0"
- 4_2-3["dast (18 minutes)"];
- click 4_2-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356819&udv=0"
- class 4_2-3 criticalPath;
subgraph "Played by `review-deploy`";
- 4_2-1 & 4_2-2 & 4_2-3 -.->|"(don't use needs because of limitations)"| 3_3-1;
+ 4_2-1 & 4_2-2 --> 3_3-1;
end
```
@@ -317,15 +314,15 @@ graph RL;
subgraph "No needed jobs";
1-1["danger-review (2.3 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
- 1-2["build-qa-image (1.6 minutes)"];
+ 1-2["build-qa-image (2 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
- 1-3["compile-test-assets (7 minutes)"];
+ 1-3["compile-test-assets (6 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
1-4["compile-test-assets as-if-foss (7 minutes)"];
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
- 1-5["compile-production-assets (19 minutes)"];
+ 1-5["compile-production-assets (14 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
- 1-6["setup-test-env (9 minutes)"];
+ 1-6["setup-test-env (4 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];
@@ -345,7 +342,7 @@ graph RL;
class 1-5 criticalPath;
end
- 2_1-1["graphql-verify (4 minutes)"];
+ 2_1-1["graphql-verify (2.3 minutes)"];
click 2_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356715&udv=0"
subgraph "Needs `setup-test-env`";
2_1-1 --> 1-6;
@@ -357,7 +354,7 @@ graph RL;
class 2_3-1 criticalPath;
end
- 2_4-1["package-and-qa (105 minutes)"];
+ 2_4-1["package-and-qa (140 minutes)"];
subgraph "Needs `build-qa-image` & `build-assets-image`";
2_4-1 --> 1-2 & 2_3-1;
class 2_4-1 criticalPath;
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 6ab288b0525..84cc32a5ad3 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -100,7 +100,7 @@ You may have noticed that we use `gitlab-org/build/omnibus-gitlab-mirror` instea
This is due to technical limitations in the GitLab permission model: the ability to run a pipeline
against a protected branch is controlled by the ability to push/merge to this branch.
This means that for developers to be able to trigger a pipeline for the default branch in
-`gitlab-org/omnibus-gitlab`/`gitlab-org/gitlab-qa`, they would need to have the
+`gitlab-org/omnibus-gitlab`/`gitlab-org/gitlab-qa`, they would need to have the
[Maintainer role](../../../user/permissions.md) for those projects.
For security reasons and implications, we couldn't open up the default branch to all the Developers.
Hence we created these mirrors where Developers and Maintainers are allowed to push/merge to the default branch.
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 8573fa81718..6759d11d936 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -891,14 +891,13 @@ describe GraphQL::Query, type: :request do
include GraphqlHelpers
all_releases_query_path = 'releases/graphql/queries/all_releases.query.graphql'
- fragment_paths = ['releases/graphql/fragments/release.fragment.graphql']
before(:all) do
clean_frontend_fixtures('graphql/releases/')
end
it "graphql/#{all_releases_query_path}.json" do
- query = get_graphql_query_as_string(all_releases_query_path, fragment_paths)
+ query = get_graphql_query_as_string(all_releases_query_path)
post_graphql(query, current_user: admin, variables: { fullPath: project.full_path })
@@ -910,10 +909,6 @@ end
This will create a new fixture located at
`tmp/tests/frontend/fixtures-ee/graphql/releases/graphql/queries/all_releases.query.graphql.json`.
-You will need to provide the paths to all fragments used by the query.
-`get_graphql_query_as_string` reads all of the provided file paths and returns
-the result as a single, concatenated string.
-
You can import the JSON fixture in a Jest test using the `getJSONFixture` method
[as described below](#use-fixtures).
diff --git a/doc/topics/autodevops/quick_start_guide.md b/doc/topics/autodevops/quick_start_guide.md
index ef5a110049a..3a63c210e86 100644
--- a/doc/topics/autodevops/quick_start_guide.md
+++ b/doc/topics/autodevops/quick_start_guide.md
@@ -131,7 +131,7 @@ Follow these steps to configure the Base Domain where your apps will be accessib
1. A few minutes after you install NGINX, the load balancer obtains an IP address, and you can
get the external IP address with the following command:
-
+
```shell
kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -ojson | jq -r '.status.loadBalancer.ingress[].ip'
```
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
index 6de62897041..4d58c7ab455 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
@@ -249,7 +249,7 @@ commits `A-B-C-D` and you want to modify something introduced in commit `B`.
```
A list of commits is displayed in your editor.
-
+
1. In front of commit `B`, replace `pick` with `edit`.
1. Leave the default, `pick`, for all other commits.
1. Save and exit the editor.
diff --git a/doc/topics/gitlab_flow.md b/doc/topics/gitlab_flow.md
index df5029bb0d1..d9aff6c35e5 100644
--- a/doc/topics/gitlab_flow.md
+++ b/doc/topics/gitlab_flow.md
@@ -152,7 +152,7 @@ After the assigned person feels comfortable with the result, they can merge the
If the assigned person does not feel comfortable, they can request more changes or close the merge request without merging.
In GitLab, it is common to protect the long-lived branches, such as the `main` branch, so [most developers can't modify them](../user/permissions.md).
-So, if you want to merge into a protected branch, assign your merge request to someone with the
+So, if you want to merge into a protected branch, assign your merge request to someone with the
[Maintainer role](../user/permissions.md).
After you merge a feature branch, you should remove it from the source control software.
diff --git a/doc/user/admin_area/moderate_users.md b/doc/user/admin_area/moderate_users.md
index 71e72cc630c..e2b4e97d824 100644
--- a/doc/user/admin_area/moderate_users.md
+++ b/doc/user/admin_area/moderate_users.md
@@ -145,7 +145,7 @@ A deactivated user can also activate their account themselves by logging back in
GitLab administrators can ban users.
NOTE:
-This feature is behind a feature flag that is disabled by default. GitLab administrators
+This feature is behind a feature flag that is disabled by default. GitLab administrators
with access to the GitLab Rails console can [enable](../../administration/feature_flags.md)
this feature for your GitLab instance.
diff --git a/doc/user/application_security/dast/browser_based.md b/doc/user/application_security/dast/browser_based.md
index 072f6fba4ba..17773492fa3 100644
--- a/doc/user/application_security/dast/browser_based.md
+++ b/doc/user/application_security/dast/browser_based.md
@@ -63,8 +63,8 @@ The browser-based crawler can be configured using CI/CD variables.
The [DAST variables](index.md#available-cicd-variables) `SECURE_ANALYZERS_PREFIX`, `DAST_FULL_SCAN_ENABLED`, `DAST_AUTO_UPDATE_ADDONS`, `DAST_EXCLUDE_RULES`, `DAST_REQUEST_HEADERS`, `DAST_HTML_REPORT`, `DAST_MARKDOWN_REPORT`, `DAST_XML_REPORT`,
`DAST_AUTH_URL`, `DAST_USERNAME`, `DAST_PASSWORD`, `DAST_USERNAME_FIELD`, `DAST_PASSWORD_FIELD`, `DAST_FIRST_SUBMIT_FIELD`, `DAST_SUBMIT_FIELD`, `DAST_EXCLUDE_URLS`, `DAST_AUTH_VERIFICATION_URL`, `DAST_BROWSER_AUTH_VERIFICATION_SELECTOR`, `DAST_BROWSER_AUTH_VERIFICATION_LOGIN_FORM`, `DAST_BROWSER_AUTH_REPORT`,
-`DAST_INCLUDE_ALPHA_VULNERABILITIES`, `DAST_PATHS_FILE`, `DAST_PATHS`, `DAST_ZAP_CLI_OPTIONS`, and `DAST_ZAP_LOG_CONFIGURATION` are also compatible with browser-based crawler scans.
-
+`DAST_INCLUDE_ALPHA_VULNERABILITIES`, `DAST_PATHS_FILE`, `DAST_PATHS`, `DAST_ZAP_CLI_OPTIONS`, and `DAST_ZAP_LOG_CONFIGURATION` are also compatible with browser-based crawler scans.
+
## Vulnerability detection
While the browser-based crawler crawls modern web applications efficiently, vulnerability detection is still managed by the standard DAST/Zed Attack Proxy (ZAP) solution.
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 0168f37ea4d..355300ca9f3 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -791,9 +791,9 @@ In order of preference, it is recommended to choose as selectors:
- `id` fields. These are generally unique on a page, and rarely change.
- `name` fields. These are generally unique on a page, and rarely change.
-- `class` values specific to the field, such as the selector `"css:.username"` for the `username` class on the username field.
+- `class` values specific to the field, such as the selector `"css:.username"` for the `username` class on the username field.
- Presence of field specific data attributes, such as the selector, `"css:[data-username]"` when the `data-username` field has any value on the username field.
-- Multiple `class` hierarchy values, such as the selector `"css:.login-form .username"` when there are multiple elements with class `username` but only one nested inside the element with the class `login-form`.
+- Multiple `class` hierarchy values, such as the selector `"css:.login-form .username"` when there are multiple elements with class `username` but only one nested inside the element with the class `login-form`.
When using selectors to locate specific fields we recommend you avoid searching on:
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index fcefba943ad..9fc90c427c5 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -13,7 +13,7 @@ Use the dependency list to review your project's dependencies and key
details about those dependencies, including their known vulnerabilities. It is a collection of dependencies in your project, including existing and new findings. To see the dependency list, go to your project and select **Security & Compliance > Dependency List**.
This information is sometimes referred to as a Software Bill of Materials or SBoM / BOM.
-The dependency list only shows the results of the last successful pipeline to run on the default branch. This is why we recommend not changing the default behavior of allowing the secure jobs to fail.
+The dependency list only shows the results of the last successful pipeline to run on the default branch. This is why we recommend not changing the default behavior of allowing the secure jobs to fail.
## Prerequisites
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 4291443caa9..c64df616925 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -512,8 +512,8 @@ Some analyzers can be customized with CI/CD variables.
| `SBT_PATH` | SpotBugs | Path to the `sbt` executable. |
| `FAIL_NEVER` | SpotBugs | Set to `1` to ignore compilation failure. |
| `SAST_GOSEC_CONFIG` | Gosec | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328301)** in GitLab 14.0 - use custom rulesets instead. Path to configuration for Gosec (optional). |
-| `PHPCS_SECURITY_AUDIT_PHP_EXTENSIONS` | phpcs-security-audit | Comma separated list of additional PHP Extensions. |
-| `SAST_DISABLE_BABEL` | NodeJsScan | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64025)** in GitLab 13.5 |
+| `PHPCS_SECURITY_AUDIT_PHP_EXTENSIONS` | phpcs-security-audit | Comma separated list of additional PHP Extensions. |
+| `SAST_DISABLE_BABEL` | NodeJsScan | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64025)** in GitLab 13.5 |
| `SAST_SEMGREP_METRICS` | Semgrep | Set to `"false"` to disable sending anonymized scan metrics to [r2c](https://r2c.dev/). Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330565) in GitLab 14.0. |
#### Custom CI/CD variables
diff --git a/doc/user/application_security/vulnerability_report/index.md b/doc/user/application_security/vulnerability_report/index.md
index 07025d193af..da59c0fbe79 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -128,11 +128,11 @@ To view the relevant file, select the filename in the vulnerability's details.
## View issues raised for a vulnerability
The **Activity** column indicates the number of issues that have been created for the vulnerability.
-Hover over an **Activity** entry and select a link go to that issue. The status of whether the issue is open or closed also displays in the hover menu.
+Hover over an **Activity** entry and select a link go to that issue. The status of whether the issue is open or closed also displays in the hover menu.
![Display attached issues](img/vulnerability_list_table_v13_9.png)
-If Jira issue support is enabled, the issue link found in the Activity entry links out to the issue in Jira. Unlike GitLab issues, the status of whether a Jira issue is Open or Closed does not display in the GitLab UI.
+If Jira issue support is enabled, the issue link found in the Activity entry links out to the issue in Jira. Unlike GitLab issues, the status of whether a Jira issue is Open or Closed does not display in the GitLab UI.
## Change status of vulnerabilities
diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md
index 75206a1aca8..eb86c1702cc 100644
--- a/doc/user/clusters/management_project_template.md
+++ b/doc/user/clusters/management_project_template.md
@@ -18,7 +18,7 @@ need, or even add new ones that are not built-in.
## How to use this template
-1. Create a new project, choosing "GitLab Cluster Management" from the list of [built-in project templates](../project/working_with_projects.md#built-in-templates).
+1. Create a new project, choosing "GitLab Cluster Management" from the list of [built-in project templates](../project/working_with_projects.md#built-in-templates).
1. Make this project a [cluster management project](management_project.md).
1. If you used the [GitLab Managed Apps](applications.md), refer to
[Migrating from GitLab Managed Apps](migrating_from_gma_to_project_template.md).
@@ -37,10 +37,10 @@ In the repository of the newly-created project, you will find:
The base image used in your pipeline is built by the [cluster-applications](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications)
project. This image consists of a set of Bash utility scripts to support [Helm v3 releases](https://helm.sh/docs/intro/using_helm/#three-big-concepts):
-- `gl-fail-if-helm2-releases-exist {namespace}`: It tries to detect whether you have apps deployed through Helm v2
- releases for a given namespace. If so, it will fail the pipeline and ask you to manually
+- `gl-fail-if-helm2-releases-exist {namespace}`: It tries to detect whether you have apps deployed through Helm v2
+ releases for a given namespace. If so, it will fail the pipeline and ask you to manually
[migrate your Helm v2 releases to Helm v3](https://helm.sh/docs/topics/v2_v3_migration/).
-- `gl-ensure-namespace {namespace}`: It creates the given namespace if it does not exist and adds the necessary label
+- `gl-ensure-namespace {namespace}`: It creates the given namespace if it does not exist and adds the necessary label
for the [Cilium](https://github.com/cilium/cilium/) app network policies to work.
- `gl-adopt-resource-with-helm-v3 {arguments}`: Used only internally in the [cert-manager's](https://cert-manager.io/) Helmfile to
facilitate the GitLab Managed Apps adoption.
@@ -50,7 +50,7 @@ project. This image consists of a set of Bash utility scripts to support [Helm v
#### The main `helmfile.yml` file
-This file has a list of paths to other Helmfiles for each app. They're all commented out by default, so you must uncomment
+This file has a list of paths to other Helmfiles for each app. They're all commented out by default, so you must uncomment
the paths for the apps that you would like to manage.
By default, each `helmfile.yaml` in these sub-paths will have the attribute `installed: true`, which signifies that everytime
@@ -58,7 +58,7 @@ the pipeline runs, Helmfile will try to either install or update your apps accor
cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile will try to uninstall this app
from your cluster. [Read more](https://github.com/roboll/helmfile) about how Helmfile works.
-Furthermore, each app has an `applications/{app}/values.yaml` file. This is the
+Furthermore, each app has an `applications/{app}/values.yaml` file. This is the
place where you can define some default values for your app's Helm chart. Some apps will already have defaults
pre-defined by GitLab.
@@ -82,5 +82,5 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp
### Migrating from GitLab Managed Apps
-If you had GitLab Managed Apps, either One-Click or CI/CD install, read the docs on how to
+If you had GitLab Managed Apps, either One-Click or CI/CD install, read the docs on how to
[migrate from GitLab Managed Apps to project template](migrating_from_gma_to_project_template.md)
diff --git a/doc/user/clusters/migrating_from_gma_to_project_template.md b/doc/user/clusters/migrating_from_gma_to_project_template.md
index 7fa6ccea433..dc16cf5cc45 100644
--- a/doc/user/clusters/migrating_from_gma_to_project_template.md
+++ b/doc/user/clusters/migrating_from_gma_to_project_template.md
@@ -35,9 +35,9 @@ The [GitLab Managed Apps](applications.md) are deprecated in GitLab 14.0. To mig
applications that you would like to manage with this project. Although you could uncomment all the ones you want to
managed at once, we recommend you repeat the following steps separately for each app, so you do not get lost during
the process.
-1. Edit the associated `applications/{app}/helmfiles.yaml` to match the chart version currently deployed
+1. Edit the associated `applications/{app}/helmfiles.yaml` to match the chart version currently deployed
for your app. Take a GitLab Runner Helm v3 release as an example:
-
+
The following command lists the releases and their versions:
```shell
@@ -83,7 +83,7 @@ The [GitLab Managed Apps](applications.md) are deprecated in GitLab 14.0. To mig
1. After following all the previous steps, [run a pipeline manually](../../ci/pipelines/index.md#run-a-pipeline-manually)
and watch the `apply` job logs to see if any of your applications were successfully detected, installed, and whether they got any
unexpected updates.
-
+
Some annotation checksums are expected to be updated, as well as this attribute:
```diff
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 74ee95e7ded..0c0a8480a7b 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -52,7 +52,7 @@ To create a thread by replying to a comment:
![Reply to comment button](img/reply_to_comment_button.png)
The reply area is displayed.
-
+
1. Type your reply.
1. Select **Comment** or **Add comment now** (depending on where in the UI you are replying).
@@ -81,7 +81,7 @@ A threaded comment is created.
## Reply to a comment by sending email
If you have ["reply by email"](../../administration/reply_by_email.md) configured,
-you can reply to comments by sending an email.
+you can reply to comments by sending an email.
- When you reply to a standard comment, another standard comment is created.
- When you reply to a threaded comment, it creates a reply in the thread.
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 3a5ea85ef15..c3b57018154 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -330,11 +330,11 @@ Ensure your SAML identity provider sends an attribute statement named `Groups` o
NOTE:
To inspect the SAML response, you can use one of these [SAML debugging tools](#saml-debugging-tools).
-Also note that the value for `Groups` or `groups` in the SAML reponse can be either the group name or
+Also note that the value for `Groups` or `groups` in the SAML reponse can be either the group name or
the group ID depending what the IdP sends to GitLab.
When SAML SSO is enabled for the top-level group, `Maintainer` and `Owner` level users
-see a new menu item in group **Settings > SAML Group Links**. You can configure one or more **SAML Group Links** to map
+see a new menu item in group **Settings > SAML Group Links**. You can configure one or more **SAML Group Links** to map
a SAML identity provider group name to a GitLab Access Level. This can be done for the parent group or the subgroups.
To link the SAML groups from the `saml:AttributeStatement` example above:
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index 618f5cb229a..737a068b5e7 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -346,7 +346,7 @@ In this example, we'd like to measure times for deployment from a staging enviro
After you create a value stream, you can customize it to suit your purposes. To edit a value stream:
1. Go to your group and select **Analytics > Value Stream**.
-1. Find and select the relevant value stream from the value stream dropdown.
+1. Find and select the relevant value stream from the value stream dropdown.
1. Next to the value stream dropdown, select **Edit**.
The edit form is populated with the value stream details.
1. Optional:
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index ecda8e9b13b..a0186371d40 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -332,7 +332,7 @@ If you forget to set the service alias, the `docker:19.03.12` image is unable to
error during connect: Get http://docker:2376/v1.39/info: dial tcp: lookup docker on 192.168.0.1:53: no such host
```
-### Using a Docker-in-Docker image with Dependency Proxy
+### Using a Docker-in-Docker image with Dependency Proxy
To use your own Docker images with Dependency Proxy, follow these steps
in addition to the steps in the
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 5d0a8200e43..3ce5f9cea02 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -536,7 +536,7 @@ If you get this error, one of the following problems could be causing it.
#### Package name does not meet the naming convention
-Your package name may not meet the
+Your package name may not meet the
[`@scope/package-name` package naming convention](#package-naming-convention).
Ensure the name meets the convention exactly, including the case.
@@ -544,10 +544,10 @@ Then try to publish again.
#### Package already exists
-Your package has already been published to another project in the same
+Your package has already been published to another project in the same
root namespace and therefore cannot be published again using the same name.
-This is also true even if the prior published package shares the same name,
+This is also true even if the prior published package shares the same name,
but not the version.
### `npm publish` returns `npm ERR! 500 Internal Server Error - PUT`
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 15648546b71..a7c59cbd4f4 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -94,7 +94,7 @@ To delete package files in the UI, from your group or project:
1. Go to **Packages & Registries > Package Registry**.
1. Find the name of the package you want to delete.
1. Select the package to view additional details.
-1. Find the name of the file you would like to delete.
+1. Find the name of the file you would like to delete.
1. Expand the ellipsis and select **Delete file**.
The package files are permanently deleted.
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index 25677853f67..597170540ab 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -507,7 +507,7 @@ If you are receiving an `invalid pin code` error, this may indicate that there i
To avoid the time sync issue, enable time synchronization in the device that generates the codes. For example:
-- For Android (Google Authenticator):
+- For Android (Google Authenticator):
1. Go to the Main Menu in Google Authenticator.
1. Select Settings.
1. Select the Time correction for the codes.
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 4097b93b5ae..790836ddbd9 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -30,7 +30,7 @@ As an alternative to using Code Owners for approvals, you can instead
Code Owners allows for a version controlled, single source of
truth file outlining the exact GitLab users or groups that
own certain files or paths in a repository. In larger organizations
-or popular open source projects, Code Owners can help you understand
+or popular open source projects, Code Owners can help you understand
who to contact if you have a question about a specific portion of
the codebase. Code Owners can also streamline the merge request approval
process, identifying the most relevant reviewers and approvers for a
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index 3a28b3c8afa..7ccdb632c19 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -36,7 +36,7 @@ created as private in GitLab as well.
- Attachments in Markdown are not imported.
- Task lists are not imported.
- Emoji reactions are not imported.
-- Project filtering does not support fuzzy search (only `starts with` or `full match strings` are
+- Project filtering does not support fuzzy search (only `starts with` or `full match strings` are
supported).
## How it works
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index 11d6bfb5d0c..8af23002a4e 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -24,7 +24,7 @@ To add a user to a project:
1. Go to your project and select **Project information > Members**.
1. On the **Invite member** tab, under **GitLab member or Email address**, type the username or email address.
In GitLab 13.11 and later, you can [replace this form with a modal window](#add-a-member-modal-window).
-1. Select a [role](../../permissions.md).
+1. Select a [role](../../permissions.md).
1. Optional. Choose an expiration date. On that date, the user can no longer access the project.
1. Select **Invite**.
@@ -54,7 +54,7 @@ To add groups to a project:
1. Go to your project and select **Project information > Members**.
1. On the **Invite group** tab, under **Select a group to invite**, choose a group.
-1. Select the highest max [role](../../permissions.md) for users in the group.
+1. Select the highest max [role](../../permissions.md) for users in the group.
1. Optional. Choose an expiration date. On that date, the user can no longer access the project.
1. Select **Invite**.
@@ -156,7 +156,7 @@ You can sort members by **Account**, **Access granted**, **Max role**, or **Last
## Request access to a project
-GitLab users can request to become a member of a project.
+GitLab users can request to become a member of a project.
1. Go to the project you'd like to be a member of.
1. By the project name, select **Request Access**.
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index dc8bfdfef42..d46e55ca005 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -172,16 +172,16 @@ both a [custom mailbox](#configuring-a-custom-mailbox) and a
#### Configuring a custom mailbox
NOTE:
-On GitLab.com a custom mailbox is already configured with `contact-project+%{key}@incoming.gitlab.com` as the email address, so you only have to configure the
+On GitLab.com a custom mailbox is already configured with `contact-project+%{key}@incoming.gitlab.com` as the email address, so you only have to configure the
[custom suffix](#configuring-a-custom-email-address-suffix) in project settings.
Using the `service_desk_email` configuration, you can customize the mailbox
-used by Service Desk. This allows you to have a separate email address for
+used by Service Desk. This allows you to have a separate email address for
Service Desk by also configuring a [custom suffix](#configuring-a-custom-email-address-suffix)
in project settings.
-The `address` must include the `+%{key}` placeholder within the 'user'
-portion of the address, before the `@`. This is used to identify the project
+The `address` must include the `+%{key}` placeholder within the 'user'
+portion of the address, before the `@`. This is used to identify the project
where the issue should be created.
NOTE:
diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb
index 2d1bb515058..181ce447b52 100644
--- a/lib/gitlab/hook_data/issue_builder.rb
+++ b/lib/gitlab/hook_data/issue_builder.rb
@@ -8,6 +8,7 @@ module Gitlab
labels
total_time_spent
time_change
+ severity
].freeze
def self.safe_hook_attributes
@@ -51,7 +52,8 @@ module Gitlab
assignee_ids: issue.assignee_ids,
assignee_id: issue.assignee_ids.first, # This key is deprecated
labels: issue.labels_hook_attrs,
- state: issue.state
+ state: issue.state,
+ severity: issue.severity
}
issue.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b81208c4324..eb59ba769bf 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -31521,9 +31521,6 @@ msgstr ""
msgid "SuperSonics|There is a connectivity issue."
msgstr ""
-msgid "SuperSonics|This field is required."
-msgstr ""
-
msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
msgstr ""
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb
index 8a07f69e480..e9fecb594a7 100644
--- a/spec/controllers/jira_connect/events_controller_spec.rb
+++ b/spec/controllers/jira_connect/events_controller_spec.rb
@@ -66,19 +66,19 @@ RSpec.describe JiraConnect::EventsController do
request.headers['Authorization'] = "JWT #{auth_token}"
end
- subject { post :uninstalled }
+ subject(:post_uninstalled) { post :uninstalled }
context 'when JWT is invalid' do
let(:auth_token) { 'invalid_token' }
it 'returns 403' do
- subject
+ post_uninstalled
expect(response).to have_gitlab_http_status(:forbidden)
end
it 'does not delete the installation' do
- expect { subject }.not_to change { JiraConnectInstallation.count }
+ expect { post_uninstalled }.not_to change { JiraConnectInstallation.count }
end
end
@@ -87,8 +87,27 @@ RSpec.describe JiraConnect::EventsController do
Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)
end
- it 'deletes the installation' do
- expect { subject }.to change { JiraConnectInstallation.count }.by(-1)
+ let(:jira_base_path) { '/-/jira_connect' }
+ let(:jira_event_path) { '/-/jira_connect/events/uninstalled' }
+
+ it 'calls the DestroyService and returns ok in case of success' do
+ expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
+ expect(destroy_service).to receive(:execute).and_return(true)
+ end
+
+ post_uninstalled
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'calls the DestroyService and returns unprocessable_entity in case of failure' do
+ expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service|
+ expect(destroy_service).to receive(:execute).and_return(false)
+ end
+
+ post_uninstalled
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end
diff --git a/spec/frontend/fixtures/projects.rb b/spec/frontend/fixtures/projects.rb
index 778ae218160..7873d59dbad 100644
--- a/spec/frontend/fixtures/projects.rb
+++ b/spec/frontend/fixtures/projects.rb
@@ -61,13 +61,12 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
clean_frontend_fixtures('graphql/projects/access_tokens')
end
- fragment_paths = ['graphql_shared/fragments/pageInfo.fragment.graphql']
base_input_path = 'access_tokens/graphql/queries/'
base_output_path = 'graphql/projects/access_tokens/'
query_name = 'get_projects.query.graphql'
it "#{base_output_path}#{query_name}.json" do
- query = get_graphql_query_as_string("#{base_input_path}#{query_name}", fragment_paths)
+ query = get_graphql_query_as_string("#{base_input_path}#{query_name}")
post_graphql(query, current_user: user, variables: { search: '', first: 2 })
diff --git a/spec/frontend/fixtures/releases.rb b/spec/frontend/fixtures/releases.rb
index ac34400bc01..e8f259fba15 100644
--- a/spec/frontend/fixtures/releases.rb
+++ b/spec/frontend/fixtures/releases.rb
@@ -133,15 +133,13 @@ RSpec.describe 'Releases (JavaScript fixtures)' do
all_releases_query_path = 'releases/graphql/queries/all_releases.query.graphql'
one_release_query_path = 'releases/graphql/queries/one_release.query.graphql'
one_release_for_editing_query_path = 'releases/graphql/queries/one_release_for_editing.query.graphql'
- release_fragment_path = 'releases/graphql/fragments/release.fragment.graphql'
- release_for_editing_fragment_path = 'releases/graphql/fragments/release_for_editing.fragment.graphql'
before(:all) do
clean_frontend_fixtures('graphql/releases/')
end
it "graphql/#{all_releases_query_path}.json" do
- query = get_graphql_query_as_string(all_releases_query_path, [release_fragment_path])
+ query = get_graphql_query_as_string(all_releases_query_path)
post_graphql(query, current_user: admin, variables: { fullPath: project.full_path })
@@ -150,7 +148,7 @@ RSpec.describe 'Releases (JavaScript fixtures)' do
end
it "graphql/#{one_release_query_path}.json" do
- query = get_graphql_query_as_string(one_release_query_path, [release_fragment_path])
+ query = get_graphql_query_as_string(one_release_query_path)
post_graphql(query, current_user: admin, variables: { fullPath: project.full_path, tagName: release.tag })
@@ -159,7 +157,7 @@ RSpec.describe 'Releases (JavaScript fixtures)' do
end
it "graphql/#{one_release_for_editing_query_path}.json" do
- query = get_graphql_query_as_string(one_release_for_editing_query_path, [release_for_editing_fragment_path])
+ query = get_graphql_query_as_string(one_release_for_editing_query_path)
post_graphql(query, current_user: admin, variables: { fullPath: project.full_path, tagName: release.tag })
diff --git a/spec/frontend/fixtures/runner.rb b/spec/frontend/fixtures/runner.rb
index b88fb840137..e29a58f43b9 100644
--- a/spec/frontend/fixtures/runner.rb
+++ b/spec/frontend/fixtures/runner.rb
@@ -36,10 +36,7 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
get_runners_query_name = 'get_runners.query.graphql'
let_it_be(:query) do
- get_graphql_query_as_string("#{query_path}#{get_runners_query_name}", [
- 'runner/graphql/runner_node.fragment.graphql',
- 'graphql_shared/fragments/pageInfo.fragment.graphql'
- ])
+ get_graphql_query_as_string("#{query_path}#{get_runners_query_name}")
end
it "#{fixtures_path}#{get_runners_query_name}.json" do
@@ -59,9 +56,7 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
get_runner_query_name = 'get_runner.query.graphql'
let_it_be(:query) do
- get_graphql_query_as_string("#{query_path}#{get_runner_query_name}", [
- 'runner/graphql/runner_details.fragment.graphql'
- ])
+ get_graphql_query_as_string("#{query_path}#{get_runner_query_name}")
end
it "#{fixtures_path}#{get_runner_query_name}.json" do
diff --git a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
new file mode 100644
index 00000000000..f922ee85624
--- /dev/null
+++ b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject do
+ let(:mutation) do
+ described_class.new(object: nil, context: { current_user: current_user }, field: nil)
+ end
+
+ describe '#resolve' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:target_project) { create(:project) }
+
+ let_it_be(:link) do
+ create(:ci_job_token_project_scope_link,
+ source_project: project,
+ target_project: target_project)
+ end
+
+ let(:target_project_path) { target_project.full_path }
+
+ subject do
+ mutation.resolve(project_path: project.full_path, target_project_path: target_project_path)
+ end
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it 'raises error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when user is logged in' do
+ let(:current_user) { create(:user) }
+
+ context 'when user does not have permissions to admin project' do
+ it 'raises error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when user has permissions to admin project and read target project' do
+ before do
+ project.add_maintainer(current_user)
+ target_project.add_guest(current_user)
+ end
+
+ it 'removes target project from the job token scope' do
+ expect do
+ expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty)
+ end.to change { Ci::JobToken::ProjectScopeLink.count }.by(-1)
+ end
+
+ context 'when the service returns an error' do
+ let(:service) { double(:service) }
+
+ it 'returns an error response' do
+ expect(::Ci::JobTokenScope::RemoveProjectService).to receive(:new).with(project, current_user).and_return(service)
+ expect(service).to receive(:execute).with(target_project).and_return(ServiceResponse.error(message: 'The error message'))
+
+ expect(subject.fetch(:ci_job_token_scope)).to be_nil
+ expect(subject.fetch(:errors)).to include("The error message")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/issues/set_severity_spec.rb b/spec/graphql/mutations/issues/set_severity_spec.rb
index 401db6cdb44..7ce9c7f6621 100644
--- a/spec/graphql/mutations/issues/set_severity_spec.rb
+++ b/spec/graphql/mutations/issues/set_severity_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Mutations::Issues::SetSeverity do
specify { expect(described_class).to require_graphql_authorizations(:update_issue) }
describe '#resolve' do
- let(:severity) { 'CRITICAL' }
+ let(:severity) { 'critical' }
let(:mutated_incident) { subject[:issue] }
subject(:resolve) { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, severity: severity) }
diff --git a/spec/lib/gitlab/hook_data/issue_builder_spec.rb b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
index 8f976bcf09d..039b4c19522 100644
--- a/spec/lib/gitlab/hook_data/issue_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
@@ -48,6 +48,7 @@ RSpec.describe Gitlab::HookData::IssueBuilder do
expect(data).to include(:human_time_change)
expect(data).to include(:assignee_ids)
expect(data).to include(:state)
+ expect(data).to include(:severity)
expect(data).to include('labels' => [label.hook_attrs])
end
diff --git a/spec/models/ci/job_token/project_scope_link_spec.rb b/spec/models/ci/job_token/project_scope_link_spec.rb
index d18495b9312..dd6a75dfd89 100644
--- a/spec/models/ci/job_token/project_scope_link_spec.rb
+++ b/spec/models/ci/job_token/project_scope_link_spec.rb
@@ -65,4 +65,22 @@ RSpec.describe Ci::JobToken::ProjectScopeLink do
expect(subject).to contain_exactly(target_link)
end
end
+
+ describe '.for_source_and_target' do
+ let_it_be(:link) { create(:ci_job_token_project_scope_link, source_project: project) }
+
+ subject { described_class.for_source_and_target(project, target_project) }
+
+ context 'when link is found' do
+ let(:target_project) { link.target_project }
+
+ it { is_expected.to eq(link) }
+ end
+
+ context 'when link is not found' do
+ let(:target_project) { create(:project) }
+
+ it { is_expected.to be_nil }
+ end
+ end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 7b100b7a6f3..071e0dcba44 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -535,6 +535,26 @@ RSpec.describe Issuable do
merge_request.to_hook_data(user, old_associations: { assignees: [user] })
end
end
+
+ context 'incident severity is updated' do
+ let(:issue) { create(:incident) }
+
+ before do
+ issue.update!(issuable_severity_attributes: { severity: 'low' })
+ expect(Gitlab::HookData::IssuableBuilder)
+ .to receive(:new).with(issue).and_return(builder)
+ end
+
+ it 'delegates to Gitlab::HookData::IssuableBuilder#build' do
+ expect(builder).to receive(:build).with(
+ user: user,
+ changes: hash_including(
+ 'severity' => %w(unknown low)
+ ))
+
+ issue.to_hook_data(user, old_associations: { severity: 'unknown' })
+ end
+ end
end
describe '#labels_array' do
diff --git a/spec/models/integrations/buildkite_spec.rb b/spec/models/integrations/buildkite_spec.rb
index 7dc81da7003..3ed68c67b81 100644
--- a/spec/models/integrations/buildkite_spec.rb
+++ b/spec/models/integrations/buildkite_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
let(:project) { create(:project) }
- subject(:service) do
+ subject(:integration) do
described_class.create!(
project: project,
properties: {
@@ -25,17 +25,17 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
end
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:token) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
+ it_behaves_like 'issue tracker integration URL attribute', :project_url
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
@@ -47,7 +47,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
describe '.supported_events' do
it 'supports push, merge_request, and tag_push events' do
- expect(service.supported_events).to eq %w(push merge_request tag_push)
+ expect(integration.supported_events).to eq %w(push merge_request tag_push)
end
end
@@ -57,18 +57,18 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
end
it 'always activates SSL verification after saved' do
- service.create_service_hook(enable_ssl_verification: false)
+ integration.create_service_hook(enable_ssl_verification: false)
- service.enable_ssl_verification = false
- service.active = true
+ integration.enable_ssl_verification = false
+ integration.active = true
- expect { service.save! }
- .to change { service.service_hook.enable_ssl_verification }.from(false).to(true)
+ expect { integration.save! }
+ .to change { integration.service_hook.enable_ssl_verification }.from(false).to(true)
end
describe '#webhook_url' do
it 'returns the webhook url' do
- expect(service.webhook_url).to eq(
+ expect(integration.webhook_url).to eq(
'https://webhook.buildkite.com/deliver/secret-sauce-webhook-token'
)
end
@@ -76,7 +76,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
describe '#commit_status_path' do
it 'returns the correct status page' do
- expect(service.commit_status_path('2ab7834c')).to eq(
+ expect(integration.commit_status_path('2ab7834c')).to eq(
'https://gitlab.buildkite.com/status/secret-sauce-status-token.json?commit=2ab7834c'
)
end
@@ -84,7 +84,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
describe '#build_page' do
it 'returns the correct build page' do
- expect(service.build_page('2ab7834c', nil)).to eq(
+ expect(integration.build_page('2ab7834c', nil)).to eq(
'https://buildkite.com/organization-name/example-pipeline/builds?commit=2ab7834c'
)
end
@@ -92,9 +92,9 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
describe '#commit_status' do
it 'returns the contents of the reactive cache' do
- stub_reactive_cache(service, { commit_status: 'foo' }, 'sha', 'ref')
+ stub_reactive_cache(integration, { commit_status: 'foo' }, 'sha', 'ref')
- expect(service.commit_status('sha', 'ref')).to eq('foo')
+ expect(integration.commit_status('sha', 'ref')).to eq('foo')
end
end
@@ -104,7 +104,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
'https://gitlab.buildkite.com/status/secret-sauce-status-token.json?commit=123'
end
- subject { service.calculate_reactive_cache('123', 'unused')[:commit_status] }
+ subject { integration.calculate_reactive_cache('123', 'unused')[:commit_status] }
it 'sets commit status to :error when status is 500' do
stub_request(status: 500)
diff --git a/spec/models/integrations/custom_issue_tracker_spec.rb b/spec/models/integrations/custom_issue_tracker_spec.rb
index 25f2648e738..a050343228e 100644
--- a/spec/models/integrations/custom_issue_tracker_spec.rb
+++ b/spec/models/integrations/custom_issue_tracker_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Integrations::CustomIssueTracker do
end
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -17,12 +17,12 @@ RSpec.describe Integrations::CustomIssueTracker do
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
it { is_expected.to validate_presence_of(:new_issue_url) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
- it_behaves_like 'issue tracker service URL attribute', :issues_url
- it_behaves_like 'issue tracker service URL attribute', :new_issue_url
+ it_behaves_like 'issue tracker integration URL attribute', :project_url
+ it_behaves_like 'issue tracker integration URL attribute', :issues_url
+ it_behaves_like 'issue tracker integration URL attribute', :new_issue_url
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
diff --git a/spec/models/integrations/emails_on_push_spec.rb b/spec/models/integrations/emails_on_push_spec.rb
index c82d4bdff9b..bdca267f6cb 100644
--- a/spec/models/integrations/emails_on_push_spec.rb
+++ b/spec/models/integrations/emails_on_push_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Integrations::EmailsOnPush do
let_it_be(:project) { create_default(:project).freeze }
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -14,7 +14,7 @@ RSpec.describe Integrations::EmailsOnPush do
it { is_expected.to validate_presence_of(:recipients) }
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
@@ -27,7 +27,7 @@ RSpec.describe Integrations::EmailsOnPush do
stub_const("#{described_class}::RECIPIENTS_LIMIT", 2)
end
- subject(:service) { described_class.new(project: project, recipients: recipients, active: true) }
+ subject(:integration) { described_class.new(project: project, recipients: recipients, active: true) }
context 'valid number of recipients' do
let(:recipients) { 'foo@bar.com duplicate@example.com Duplicate@example.com invalid-email' }
@@ -43,14 +43,14 @@ RSpec.describe Integrations::EmailsOnPush do
it { is_expected.not_to be_valid }
it 'adds an error message' do
- service.valid?
+ integration.valid?
- expect(service.errors).to contain_exactly('Recipients can\'t exceed 2')
+ expect(integration.errors).to contain_exactly('Recipients can\'t exceed 2')
end
- context 'when service is not active' do
+ context 'when integration is not active' do
before do
- service.active = false
+ integration.active = false
end
it { is_expected.to be_valid }
diff --git a/spec/models/integrations/open_project_spec.rb b/spec/models/integrations/open_project_spec.rb
index e5b976dc91d..5084024a8e8 100644
--- a/spec/models/integrations/open_project_spec.rb
+++ b/spec/models/integrations/open_project_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Integrations::OpenProject do
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -13,11 +13,11 @@ RSpec.describe Integrations::OpenProject do
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:project_identifier_code) }
- it_behaves_like 'issue tracker service URL attribute', :url
- it_behaves_like 'issue tracker service URL attribute', :api_url
+ it_behaves_like 'issue tracker integration URL attribute', :url
+ it_behaves_like 'issue tracker integration URL attribute', :api_url
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
diff --git a/spec/models/integrations/pivotaltracker_spec.rb b/spec/models/integrations/pivotaltracker_spec.rb
index 2ce90b6f739..8da77f7c8f9 100644
--- a/spec/models/integrations/pivotaltracker_spec.rb
+++ b/spec/models/integrations/pivotaltracker_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Integrations::Pivotaltracker do
end
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -19,7 +19,7 @@ RSpec.describe Integrations::Pivotaltracker do
it { is_expected.to validate_presence_of(:token) }
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
@@ -29,9 +29,9 @@ RSpec.describe Integrations::Pivotaltracker do
end
describe 'Execute' do
- let(:service) do
- described_class.new.tap do |service|
- service.token = 'secret_api_token'
+ let(:integration) do
+ described_class.new.tap do |integration|
+ integration.token = 'secret_api_token'
end
end
@@ -59,7 +59,7 @@ RSpec.describe Integrations::Pivotaltracker do
end
it 'posts correct message' do
- service.execute(push_data)
+ integration.execute(push_data)
expect(WebMock).to have_requested(:post, stubbed_hostname(url)).with(
body: {
'source_commit' => {
@@ -77,22 +77,22 @@ RSpec.describe Integrations::Pivotaltracker do
end
context 'when allowed branches is specified' do
- let(:service) do
- super().tap do |service|
- service.restrict_to_branch = 'master,v10'
+ let(:integration) do
+ super().tap do |integration|
+ integration.restrict_to_branch = 'master,v10'
end
end
it 'posts message if branch is in the list' do
- service.execute(push_data(branch: 'master'))
- service.execute(push_data(branch: 'v10'))
+ integration.execute(push_data(branch: 'master'))
+ integration.execute(push_data(branch: 'v10'))
expect(WebMock).to have_requested(:post, stubbed_hostname(url)).twice
end
it 'does not post message if branch is not in the list' do
- service.execute(push_data(branch: 'mas'))
- service.execute(push_data(branch: 'v11'))
+ integration.execute(push_data(branch: 'mas'))
+ integration.execute(push_data(branch: 'v11'))
expect(WebMock).not_to have_requested(:post, stubbed_hostname(url))
end
diff --git a/spec/models/integrations/youtrack_spec.rb b/spec/models/integrations/youtrack_spec.rb
index 314204f6fb4..0c4014dffc0 100644
--- a/spec/models/integrations/youtrack_spec.rb
+++ b/spec/models/integrations/youtrack_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Integrations::Youtrack do
end
describe 'Validations' do
- context 'when service is active' do
+ context 'when integration is active' do
before do
subject.active = true
end
@@ -17,11 +17,11 @@ RSpec.describe Integrations::Youtrack do
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
- it_behaves_like 'issue tracker service URL attribute', :project_url
- it_behaves_like 'issue tracker service URL attribute', :issues_url
+ it_behaves_like 'issue tracker integration URL attribute', :project_url
+ it_behaves_like 'issue tracker integration URL attribute', :issues_url
end
- context 'when service is inactive' do
+ context 'when integration is inactive' do
before do
subject.active = false
end
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index 926c310cad6..9101fd5904c 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe 'CiJobTokenScopeAddProject' do
it 'has mutation errors' do
post_graphql_mutation(mutation, current_user: current_user)
- expect(mutation_response['errors']).to contain_exactly(Ci::JobTokenScope::AddProjectService::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
+ expect(mutation_response['errors']).to contain_exactly(Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
end
end
end
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
new file mode 100644
index 00000000000..2e439610d97
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CiJobTokenScopeRemoveProject' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:target_project) { create(:project) }
+
+ let_it_be(:link) do
+ create(:ci_job_token_project_scope_link,
+ source_project: project,
+ target_project: target_project)
+ end
+
+ let(:variables) do
+ {
+ project_path: project.full_path,
+ target_project_path: target_project.full_path
+ }
+ end
+
+ let(:mutation) do
+ graphql_mutation(:ci_job_token_scope_remove_project, variables) do
+ <<~QL
+ errors
+ ciJobTokenScope {
+ projects {
+ nodes {
+ path
+ }
+ }
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:ci_job_token_scope_remove_project) }
+
+ context 'when unauthorized' do
+ let(:current_user) { create(:user) }
+
+ context 'when not a maintainer' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'has graphql errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).not_to be_empty
+ end
+ end
+ end
+
+ context 'when authorized' do
+ let_it_be(:current_user) { project.owner }
+
+ before do
+ target_project.add_guest(current_user)
+ end
+
+ it 'removes the target project from the job token scope' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty
+ end.to change { Ci::JobToken::Scope.new(project).includes?(target_project) }.from(true).to(false)
+ end
+
+ context 'when invalid target project is provided' do
+ before do
+ variables[:target_project_path] = 'unknown/project'
+ end
+
+ it 'has mutation errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to contain_exactly(Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND)
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/job_token_scope/add_project_service_spec.rb b/spec/services/ci/job_token_scope/add_project_service_spec.rb
index 37134af7c2a..7812f79b7a7 100644
--- a/spec/services/ci/job_token_scope/add_project_service_spec.rb
+++ b/spec/services/ci/job_token_scope/add_project_service_spec.rb
@@ -11,68 +11,28 @@ RSpec.describe Ci::JobTokenScope::AddProjectService do
describe '#execute' do
subject(:result) { service.execute(target_project) }
- shared_examples 'returns error' do |error|
- it 'returns an error response', :aggregate_failures do
- expect(result).to be_error
- expect(result.message).to eq(error)
- end
- end
-
- context 'when job token scope is disabled for the given project' do
- before do
- allow(project).to receive(:ci_job_token_scope_enabled?).and_return(false)
- end
-
- it_behaves_like 'returns error', 'Job token scope is disabled for this project'
- end
-
- context 'when user does not have permissions to edit the job token scope' do
- it_behaves_like 'returns error', 'Insufficient permissions to modify the job token scope'
- end
-
- context 'when user has permissions to edit the job token scope' do
- before do
- project.add_maintainer(current_user)
- end
-
- context 'when target project is not provided' do
- let(:target_project) { nil }
-
- it_behaves_like 'returns error', Ci::JobTokenScope::AddProjectService::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND
- end
-
- context 'when target project is provided' do
- context 'when user does not have permissions to read the target project' do
- it_behaves_like 'returns error', Ci::JobTokenScope::AddProjectService::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND
+ it_behaves_like 'editable job token scope' do
+ context 'when user has permissions on source and target projects' do
+ before do
+ project.add_maintainer(current_user)
+ target_project.add_developer(current_user)
end
- context 'when user has permissions to read the target project' do
- before do
- target_project.add_guest(current_user)
- end
-
- it 'adds the project to the scope' do
- expect do
- expect(result).to be_success
- end.to change { Ci::JobToken::ProjectScopeLink.count }.by(1)
- end
-
- context 'when target project is already in scope' do
- before do
- create(:ci_job_token_project_scope_link,
- source_project: project,
- target_project: target_project)
- end
+ it 'adds the project to the scope' do
+ expect do
+ expect(result).to be_success
+ end.to change { Ci::JobToken::ProjectScopeLink.count }.by(1)
+ end
+ end
- it_behaves_like 'returns error', "Target project is already in the job token scope"
- end
+ context 'when target project is same as the source project' do
+ before do
+ project.add_maintainer(current_user)
end
- context 'when target project is same as the source project' do
- let(:target_project) { project }
+ let(:target_project) { project }
- it_behaves_like 'returns error', "Validation failed: Target project can't be the same as the source project"
- end
+ it_behaves_like 'returns error', "Validation failed: Target project can't be the same as the source project"
end
end
end
diff --git a/spec/services/ci/job_token_scope/remove_project_service_spec.rb b/spec/services/ci/job_token_scope/remove_project_service_spec.rb
new file mode 100644
index 00000000000..a92ea1854d2
--- /dev/null
+++ b/spec/services/ci/job_token_scope/remove_project_service_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Ci::JobTokenScope::RemoveProjectService do
+ let(:service) { described_class.new(project, current_user) }
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:target_project) { create(:project) }
+ let_it_be(:current_user) { create(:user) }
+
+ let_it_be(:link) do
+ create(:ci_job_token_project_scope_link,
+ source_project: project,
+ target_project: target_project)
+ end
+
+ describe '#execute' do
+ subject(:result) { service.execute(target_project) }
+
+ it_behaves_like 'editable job token scope' do
+ context 'when user has permissions on source and target project' do
+ before do
+ project.add_maintainer(current_user)
+ target_project.add_developer(current_user)
+ end
+
+ it 'removes the project from the scope' do
+ expect do
+ expect(result).to be_success
+ end.to change { Ci::JobToken::ProjectScopeLink.count }.by(-1)
+ end
+ end
+
+ context 'when target project is same as the source project' do
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ let(:target_project) { project }
+
+ it_behaves_like 'returns error', "Source project cannot be removed from the job token scope"
+ end
+ end
+ end
+end
diff --git a/spec/services/incident_management/incidents/update_severity_service_spec.rb b/spec/services/incident_management/incidents/update_severity_service_spec.rb
deleted file mode 100644
index bc1abf82cf2..00000000000
--- a/spec/services/incident_management/incidents/update_severity_service_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe IncidentManagement::Incidents::UpdateSeverityService do
- let_it_be(:user) { create(:user) }
-
- describe '#execute' do
- let(:severity) { 'low' }
- let(:system_note_worker) { ::IncidentManagement::AddSeveritySystemNoteWorker }
-
- subject(:update_severity) { described_class.new(issuable, user, severity).execute }
-
- before do
- allow(system_note_worker).to receive(:perform_async)
- end
-
- shared_examples 'adds a system note' do
- it 'calls AddSeveritySystemNoteWorker' do
- update_severity
-
- expect(system_note_worker).to have_received(:perform_async).with(issuable.id, user.id)
- end
- end
-
- context 'when issuable not an incident' do
- %i(issue merge_request).each do |issuable_type|
- let(:issuable) { build_stubbed(issuable_type) }
-
- it { is_expected.to be_nil }
-
- it 'does not set severity' do
- expect { update_severity }.not_to change(IssuableSeverity, :count)
- end
-
- it 'does not add a system note' do
- update_severity
-
- expect(system_note_worker).not_to have_received(:perform_async)
- end
- end
- end
-
- context 'when issuable is an incident' do
- let!(:issuable) { create(:incident) }
-
- context 'when issuable does not have issuable severity yet' do
- it 'creates new record' do
- expect { update_severity }.to change { IssuableSeverity.where(issue: issuable).count }.to(1)
- end
-
- it 'sets severity to specified value' do
- expect { update_severity }.to change { issuable.severity }.to('low')
- end
-
- it_behaves_like 'adds a system note'
- end
-
- context 'when issuable has an issuable severity' do
- let!(:issuable_severity) { create(:issuable_severity, issue: issuable, severity: 'medium') }
-
- it 'does not create new record' do
- expect { update_severity }.not_to change(IssuableSeverity, :count)
- end
-
- it 'updates existing issuable severity' do
- expect { update_severity }.to change { issuable_severity.severity }.to(severity)
- end
-
- it_behaves_like 'adds a system note'
- end
-
- context 'when severity value is unsupported' do
- let(:severity) { 'unsupported-severity' }
-
- it 'sets the severity to default value' do
- update_severity
-
- expect(issuable.issuable_severity.severity).to eq(IssuableSeverity::DEFAULT)
- end
-
- it_behaves_like 'adds a system note'
- end
- end
- end
-end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 054f390f325..70c3c2a0f5d 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -83,16 +83,16 @@ RSpec.describe Issues::UpdateService, :mailer do
end
context 'when issue type is not incident' do
- it 'returns default severity' do
+ before do
update_issue(opts)
-
- expect(issue.severity).to eq(IssuableSeverity::DEFAULT)
end
- it_behaves_like 'not an incident issue' do
- before do
- update_issue(opts)
- end
+ it_behaves_like 'not an incident issue'
+
+ context 'when confidentiality is changed' do
+ subject { update_issue(confidential: true) }
+
+ it_behaves_like 'does not track incident management event'
end
end
@@ -105,12 +105,16 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'incident issue'
- it 'changes updates the severity' do
- expect(issue.severity).to eq('low')
+ it 'does not add an incident label' do
+ expect(issue.labels).to match_array [label]
end
- it 'does not apply incident labels' do
- expect(issue.labels).to match_array [label]
+ context 'when confidentiality is changed' do
+ let(:current_user) { user }
+
+ subject { update_issue(confidential: true) }
+
+ it_behaves_like 'an incident management tracked event', :incident_management_incident_change_confidential
end
end
@@ -140,24 +144,6 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.confidential).to be_falsey
end
- context 'issue in incident type' do
- let(:current_user) { user }
-
- before do
- opts.merge!(issue_type: 'incident', confidential: true)
- end
-
- subject { update_issue(opts) }
-
- it_behaves_like 'an incident management tracked event', :incident_management_incident_change_confidential
-
- it_behaves_like 'incident issue' do
- before do
- subject
- end
- end
- end
-
context 'changing issue_type' do
let!(:label_1) { create(:label, project: project, title: 'incident') }
let!(:label_2) { create(:label, project: project, title: 'missed-sla') }
@@ -167,6 +153,12 @@ RSpec.describe Issues::UpdateService, :mailer do
end
context 'from issue to incident' do
+ it_behaves_like 'incident issue' do
+ before do
+ update_issue(**opts, issue_type: 'incident')
+ end
+ end
+
it 'adds a `incident` label if one does not exist' do
expect { update_issue(issue_type: 'incident') }.to change(issue.labels, :count).by(1)
expect(issue.labels.pluck(:title)).to eq(['incident'])
@@ -1020,6 +1012,101 @@ RSpec.describe Issues::UpdateService, :mailer do
include_examples 'updating mentions', described_class
end
+ context 'updating severity' do
+ let(:opts) { { severity: 'low' } }
+
+ shared_examples 'updates the severity' do |expected_severity|
+ it 'has correct value' do
+ update_issue(opts)
+
+ expect(issue.severity).to eq(expected_severity)
+ end
+
+ it 'creates a system note' do
+ expect(::IncidentManagement::AddSeveritySystemNoteWorker).to receive(:perform_async).with(issue.id, user.id)
+
+ update_issue(opts)
+ end
+
+ it 'triggers webhooks' do
+ expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
+ expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :issue_hooks)
+
+ update_issue(opts)
+ end
+ end
+
+ shared_examples 'does not change the severity' do
+ it 'retains the original value' do
+ expected_severity = issue.severity
+
+ update_issue(opts)
+
+ expect(issue.severity).to eq(expected_severity)
+ end
+
+ it 'does not trigger side-effects' do
+ expect(::IncidentManagement::AddSeveritySystemNoteWorker).not_to receive(:perform_async)
+ expect(project).not_to receive(:execute_hooks)
+ expect(project).not_to receive(:execute_integrations)
+
+ expect { update_issue(opts) }.not_to change(IssuableSeverity, :count)
+ end
+ end
+
+ context 'on incidents' do
+ let(:issue) { create(:incident, project: project) }
+
+ context 'when severity has not been set previously' do
+ it_behaves_like 'updates the severity', 'low'
+
+ it 'creates a new record' do
+ expect { update_issue(opts) }.to change(IssuableSeverity, :count).by(1)
+ end
+
+ context 'with unsupported severity value' do
+ let(:opts) { { severity: 'unsupported-severity' } }
+
+ it_behaves_like 'does not change the severity'
+ end
+
+ context 'with severity value defined but unchanged' do
+ let(:opts) { { severity: IssuableSeverity::DEFAULT } }
+
+ it_behaves_like 'does not change the severity'
+ end
+ end
+
+ context 'when severity has been set before' do
+ before do
+ create(:issuable_severity, issue: issue, severity: 'high')
+ end
+
+ it_behaves_like 'updates the severity', 'low'
+
+ it 'does not create a new record' do
+ expect { update_issue(opts) }.not_to change(IssuableSeverity, :count)
+ end
+
+ context 'with unsupported severity value' do
+ let(:opts) { { severity: 'unsupported-severity' } }
+
+ it_behaves_like 'updates the severity', IssuableSeverity::DEFAULT
+ end
+
+ context 'with severity value defined but unchanged' do
+ let(:opts) { { severity: issue.severity } }
+
+ it_behaves_like 'does not change the severity'
+ end
+ end
+ end
+
+ context 'when issue type is not incident' do
+ it_behaves_like 'does not change the severity'
+ end
+ end
+
context 'duplicate issue' do
let(:canonical_issue) { create(:issue, project: project) }
diff --git a/spec/services/jira_connect_installations/destroy_service_spec.rb b/spec/services/jira_connect_installations/destroy_service_spec.rb
new file mode 100644
index 00000000000..bb5bab53ccb
--- /dev/null
+++ b/spec/services/jira_connect_installations/destroy_service_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe JiraConnectInstallations::DestroyService do
+ describe '.execute' do
+ it 'creates an instance and calls execute' do
+ expect_next_instance_of(described_class, 'param1', 'param2', 'param3') do |destroy_service|
+ expect(destroy_service).to receive(:execute)
+ end
+
+ described_class.execute('param1', 'param2', 'param3')
+ end
+ end
+
+ describe '#execute' do
+ let!(:installation) { create(:jira_connect_installation) }
+ let(:jira_base_path) { '/-/jira_connect' }
+ let(:jira_event_path) { '/-/jira_connect/events/uninstalled' }
+
+ subject { described_class.new(installation, jira_base_path, jira_event_path).execute }
+
+ it { is_expected.to be_truthy }
+
+ it 'deletes the installation' do
+ expect { subject }.to change(JiraConnectInstallation, :count).by(-1)
+ end
+
+ context 'and the installation has an instance_url set' do
+ let!(:installation) { create(:jira_connect_installation, instance_url: 'http://example.com') }
+
+ it { is_expected.to be_truthy }
+
+ it 'schedules a ForwardEventWorker background job and keeps the installation' do
+ expect(JiraConnect::ForwardEventWorker).to receive(:perform_async).with(installation.id, jira_base_path, jira_event_path)
+
+ expect { subject }.not_to change(JiraConnectInstallation, :count)
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb
index 8fd8a548011..4c90b907d2d 100644
--- a/spec/support/helpers/javascript_fixtures_helpers.rb
+++ b/spec/support/helpers/javascript_fixtures_helpers.rb
@@ -43,12 +43,14 @@ module JavaScriptFixturesHelpers
# Public: Reads a GraphQL query from the filesystem as a string
#
# query_path - file path to the GraphQL query, relative to `app/assets/javascripts`
- # fragment_paths - an optional array of file paths to any fragments the query uses,
- # also relative to `app/assets/javascripts`
- def get_graphql_query_as_string(query_path, fragment_paths = [])
- [query_path, *fragment_paths].map do |path|
- File.read(File.join(Rails.root, '/app/assets/javascripts', path))
- end.join("\n")
+ def get_graphql_query_as_string(query_path)
+ path = Rails.root / 'app/assets/javascripts' / query_path
+ queries = Gitlab::Graphql::Queries.find(path)
+ if queries.length == 1
+ queries.first.text(mode: Gitlab.ee? ? :ee : :ce )
+ else
+ raise "Could not find query file at #{path}, please check your query_path" % path
+ end
end
private
diff --git a/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb b/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb
new file mode 100644
index 00000000000..05b2b5f5de1
--- /dev/null
+++ b/spec/support/shared_examples/ci/edit_job_token_scope_shared_examples.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'editable job token scope' do
+ shared_examples 'returns error' do |error|
+ it 'returns an error response', :aggregate_failures do
+ expect(result).to be_error
+ expect(result.message).to eq(error)
+ end
+ end
+
+ context 'when job token scope is disabled for the given project' do
+ before do
+ allow(project).to receive(:ci_job_token_scope_enabled?).and_return(false)
+ end
+
+ it_behaves_like 'returns error', 'Job token scope is disabled for this project'
+ end
+
+ context 'when user does not have permissions to edit the job token scope' do
+ it_behaves_like 'returns error', 'Insufficient permissions to modify the job token scope'
+ end
+
+ context 'when user has permissions to edit the job token scope' do
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ context 'when target project is not provided' do
+ let(:target_project) { nil }
+
+ it_behaves_like 'returns error', Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND
+ end
+
+ context 'when target project is provided' do
+ context 'when user does not have permissions to read the target project' do
+ it_behaves_like 'returns error', Ci::JobTokenScope::EditScopeValidations::TARGET_PROJECT_UNAUTHORIZED_OR_UNFOUND
+ end
+ end
+ end
+end
diff --git a/spec/workers/jira_connect/forward_event_worker_spec.rb b/spec/workers/jira_connect/forward_event_worker_spec.rb
new file mode 100644
index 00000000000..adfc071779a
--- /dev/null
+++ b/spec/workers/jira_connect/forward_event_worker_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe JiraConnect::ForwardEventWorker do
+ describe '#perform' do
+ let!(:jira_connect_installation) { create(:jira_connect_installation, instance_url: self_managed_url, client_key: client_key, shared_secret: shared_secret) }
+ let(:base_path) { '/-/jira_connect' }
+ let(:event_path) { '/-/jira_connect/events/uninstalled' }
+
+ let(:self_managed_url) { 'http://example.com' }
+ let(:base_url) { self_managed_url + base_path }
+ let(:event_url) { self_managed_url + event_path }
+
+ let(:client_key) { '123' }
+ let(:shared_secret) { '123' }
+
+ subject { described_class.new.perform(jira_connect_installation.id, base_path, event_path) }
+
+ it 'forwards the event including the auth header and deletes the installation' do
+ stub_request(:post, event_url)
+
+ expect(Atlassian::Jwt).to receive(:create_query_string_hash).with(event_url, 'POST', base_url).and_return('some_qsh')
+ expect(Atlassian::Jwt).to receive(:encode).with({ iss: client_key, qsh: 'some_qsh' }, shared_secret).and_return('auth_token')
+ expect { subject }.to change(JiraConnectInstallation, :count).by(-1)
+
+ expect(WebMock).to have_requested(:post, event_url).with(headers: { 'Authorization' => 'JWT auth_token' })
+ end
+
+ context 'when installation does not exist' do
+ let(:jira_connect_installation) { instance_double(JiraConnectInstallation, id: -1) }
+
+ it 'does nothing' do
+ expect { subject }.not_to change(JiraConnectInstallation, :count)
+ end
+ end
+
+ context 'when installation does not have an instance_url' do
+ let!(:jira_connect_installation) { create(:jira_connect_installation) }
+
+ it 'forwards the event including the auth header' do
+ expect { subject }.to change(JiraConnectInstallation, :count).by(-1)
+
+ expect(WebMock).not_to have_requested(:post, '*')
+ end
+ end
+
+ context 'when it fails to forward the event' do
+ it 'still deletes the installation' do
+ allow(Gitlab::HTTP).to receive(:post).and_raise(StandardError)
+
+ expect { subject }.to raise_error(StandardError).and change(JiraConnectInstallation, :count).by(-1)
+ end
+ end
+ end
+end