Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml32
-rw-r--r--.haml-lint.yml1
-rw-r--r--.rubocop_todo.yml25
-rw-r--r--.rubocop_todo/layout/space_inside_block_braces.yml770
-rw-r--r--.rubocop_todo/lint/binary_operator_with_identical_operands.yml15
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue6
-rw-r--r--app/assets/javascripts/boards/components/issuable_title.vue21
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue2
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue5
-rw-r--r--app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue74
-rw-r--r--app/assets/javascripts/integrations/edit/index.js4
-rw-r--r--app/assets/javascripts/issues/manual_ordering.js7
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_list.vue4
-rw-r--r--app/assets/javascripts/sortable/constants.js19
-rw-r--r--app/assets/javascripts/sortable/sortable_config.js8
-rw-r--r--app/assets/javascripts/sortable/utils.js (renamed from app/assets/javascripts/boards/mixins/sortable_default_options.js)14
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue1
-rw-r--r--app/assets/stylesheets/bootstrap_migration.scss324
-rw-r--r--app/assets/stylesheets/bootstrap_migration_components.scss216
-rw-r--r--app/assets/stylesheets/bootstrap_migration_reset.scss94
-rw-r--r--app/assets/stylesheets/bootstrap_migration_variables.scss15
-rw-r--r--app/assets/stylesheets/notify_base.scss3
-rw-r--r--app/assets/stylesheets/notify_enhanced.scss18
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss14
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss14
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss12
-rw-r--r--app/helpers/issuables_helper.rb2
-rw-r--r--app/models/integrations/jira.rb19
-rw-r--r--app/services/bulk_imports/relation_export_service.rb5
-rw-r--r--app/views/admin/groups/index.html.haml3
-rw-r--r--app/views/projects/services/_form.html.haml2
-rw-r--r--app/views/shared/integrations/edit.html.haml2
-rw-r--r--app/workers/bulk_imports/relation_export_worker.rb4
-rw-r--r--data/deprecations/14-10-manual-iteration-management.yml34
-rw-r--r--doc/administration/package_information/postgresql_versions.md4
-rw-r--r--doc/administration/package_information/supported_os.md6
-rw-r--r--doc/api/runners.md4
-rw-r--r--doc/ci/runners/runners_scope.md25
-rw-r--r--doc/development/documentation/feature_flags.md47
-rw-r--r--doc/development/service_ping/implement.md2
-rw-r--r--doc/update/deprecations.md32
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md22
-rw-r--r--doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_input_v14_10.pngbin0 -> 10770 bytes
-rw-r--r--doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_0.pngbin80106 -> 0 bytes
-rw-r--r--doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_10.pngbin0 -> 9849 bytes
-rw-r--r--doc/user/group/iterations/index.md6
-rw-r--r--doc/user/markdown.md1
-rw-r--r--doc/user/project/settings/import_export.md2
-rw-r--r--doc/user/shortcuts.md6
-rw-r--r--locale/gitlab.pot5
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/multi-project_pipelines_spec.rb (renamed from qa/qa/specs/features/browser_ui/6_release/pipeline/multi-project_pipelines_spec.rb)5
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_dependent_relationship_spec.rb (renamed from qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb)10
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb (renamed from qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb)10
-rw-r--r--qa/spec/spec_helper.rb6
-rw-r--r--spec/features/admin/admin_runners_spec.rb60
-rw-r--r--spec/features/groups/group_runners_spec.rb28
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb6
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb6
-rw-r--r--spec/frontend/api_spec.js466
-rw-r--r--spec/frontend/boards/components/issuable_title_spec.js33
-rw-r--r--spec/frontend/diffs/components/commit_item_spec.js2
-rw-r--r--spec/frontend/integrations/edit/components/jira_issues_fields_spec.js44
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_spec.js15
-rw-r--r--spec/helpers/issuables_helper_spec.rb2
-rw-r--r--spec/services/bulk_imports/relation_export_service_spec.rb12
-rw-r--r--spec/support/shared_examples/features/runners_shared_examples.rb62
68 files changed, 1795 insertions, 931 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ac072f69b5b..c62de7d7ab0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,7 +16,7 @@ stages:
# in cases where jobs require Docker-in-Docker, the job
# definition must be extended with `.use-docker-in-docker`
default:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-11-graphicsmagick-1.3.36
+ image: $DEFAULT_CI_IMAGE
tags:
- gitlab-org
# All jobs are interruptible by default
@@ -58,6 +58,8 @@ workflow:
- if: '$CI_COMMIT_BRANCH =~ /^security\//'
variables:
+ PG_VERSION: "12"
+ DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-${PG_VERSION}-graphicsmagick-1.3.36"
RAILS_ENV: "test"
NODE_ENV: "test"
BUNDLE_WITHOUT: "production:development"
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index 96f81a7feee..4069dfe9a2b 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -44,16 +44,16 @@
- lib/gitlab/setup_helper.rb
prefix: "gitaly-binaries-${DEBIAN-VERSION}"
paths:
- - tmp/tests/gitaly/_build/bin/
- - tmp/tests/gitaly/_build/deps/git/install/
- - tmp/tests/gitaly/config.toml
- - tmp/tests/gitaly/gitaly2.config.toml
- - tmp/tests/gitaly/internal/
- - tmp/tests/gitaly/run/
- - tmp/tests/gitaly/run2/
- - tmp/tests/gitaly/Makefile
- - tmp/tests/gitaly/praefect.config.toml
- - tmp/tests/gitaly/ruby/
+ - ${TMP_TEST_FOLDER}/gitaly/_build/bin/
+ - ${TMP_TEST_FOLDER}/gitaly/_build/deps/git/install/
+ - ${TMP_TEST_FOLDER}/gitaly/config.toml
+ - ${TMP_TEST_FOLDER}/gitaly/gitaly2.config.toml
+ - ${TMP_TEST_FOLDER}/gitaly/internal/
+ - ${TMP_TEST_FOLDER}/gitaly/run/
+ - ${TMP_TEST_FOLDER}/gitaly/run2/
+ - ${TMP_TEST_FOLDER}/gitaly/Makefile
+ - ${TMP_TEST_FOLDER}/gitaly/praefect.config.toml
+ - ${TMP_TEST_FOLDER}/gitaly/ruby/
policy: pull
.go-pkg-cache: &go-pkg-cache
@@ -214,34 +214,33 @@
- *storybook-node-modules-cache-push
.use-pg11:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-11-graphicsmagick-1.3.36
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "11"
.use-pg12:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-12-graphicsmagick-1.3.36
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:6.0-alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "12"
.use-pg13:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-13-graphicsmagick-1.3.36
services:
- name: postgres:13
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "13"
.use-pg11-ee:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-11-graphicsmagick-1.3.36
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -250,9 +249,9 @@
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "11"
.use-pg12-ee:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-12-graphicsmagick-1.3.36
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -261,9 +260,9 @@
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "12"
.use-pg13-ee:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:debian-${DEBIAN_VERSION}-ruby-2.7.patched-golang-1.16-git-2.33-lfs-2.9-chrome-97-node-16.14-yarn-1.22-postgresql-13-graphicsmagick-1.3.36
services:
- name: postgres:13
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -272,6 +271,7 @@
command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "13"
.use-kaniko:
image:
diff --git a/.haml-lint.yml b/.haml-lint.yml
index 8d084a0c356..75139cb43dd 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -124,7 +124,6 @@ linters:
- Performance/RedundantMatch
- Performance/StringReplacement
- Rails/LinkToBlank
- - Rails/Presence
- Rails/RequestReferer
- Style/ColonMethodCall
- Style/ConditionalAssignment
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 502534e5010..d041ce385e3 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -25,15 +25,6 @@ Layout/MultilineOperationIndentation:
Layout/SpaceInLambdaLiteral:
Enabled: false
-# Offense count: 1209
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
-# SupportedStyles: space, no_space
-# SupportedStylesForEmptyBraces: space, no_space
-Layout/SpaceInsideBlockBraces:
- Enabled: false
- EnforcedStyle: space
-
# Offense count: 585
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
@@ -41,22 +32,6 @@ Layout/SpaceInsideBlockBraces:
Layout/SpaceInsideParens:
Enabled: false
-# Offense count: 18
-Lint/BinaryOperatorWithIdenticalOperands:
- Exclude:
- - 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
- - 'spec/helpers/visibility_level_helper_spec.rb'
- - 'spec/lib/gitlab/conan_token_spec.rb'
- - 'spec/lib/gitlab/git/conflict/parser_spec.rb'
- - 'spec/lib/gitlab/graphql/lazy_spec.rb'
- - 'spec/models/ci/build_trace_chunk_spec.rb'
- - 'spec/models/clusters/platforms/kubernetes_spec.rb'
- - 'spec/models/concerns/where_composite_spec.rb'
- - 'spec/models/metrics/dashboard/annotation_spec.rb'
- - 'spec/models/repository_spec.rb'
- - 'spec/models/ssh_host_key_spec.rb'
- - 'spec/tooling/danger/sidekiq_queues_spec.rb'
-
# Offense count: 84
Lint/ConstantDefinitionInBlock:
Enabled: false
diff --git a/.rubocop_todo/layout/space_inside_block_braces.yml b/.rubocop_todo/layout/space_inside_block_braces.yml
new file mode 100644
index 00000000000..fc838ccadd8
--- /dev/null
+++ b/.rubocop_todo/layout/space_inside_block_braces.yml
@@ -0,0 +1,770 @@
+---
+# Cop supports --auto-correct.
+Layout/SpaceInsideBlockBraces:
+ # Offense count: 1508
+ # Temporarily disabled due to too many offenses
+ Enabled: false
+ EnforcedStyle: space
+ Exclude:
+ - 'app/controllers/groups/boards_controller.rb'
+ - 'app/controllers/profiles/two_factor_auths_controller.rb'
+ - 'app/controllers/projects/boards_controller.rb'
+ - 'app/experiments/security_reports_mr_widget_prompt_experiment.rb'
+ - 'app/experiments/video_tutorials_continuous_onboarding_experiment.rb'
+ - 'app/graphql/types/concerns/find_closest.rb'
+ - 'app/helpers/favicon_helper.rb'
+ - 'app/helpers/time_zone_helper.rb'
+ - 'app/helpers/todos_helper.rb'
+ - 'app/models/authentication_event.rb'
+ - 'app/models/bulk_imports/entity.rb'
+ - 'app/models/ci/pipeline.rb'
+ - 'app/models/concerns/cache_markdown_field.rb'
+ - 'app/models/concerns/featurable.rb'
+ - 'app/models/integrations/bamboo.rb'
+ - 'app/models/integrations/buildkite.rb'
+ - 'app/models/integrations/teamcity.rb'
+ - 'app/models/network/graph.rb'
+ - 'app/models/operations/feature_flag.rb'
+ - 'app/models/packages/package.rb'
+ - 'app/models/preloaders/labels_preloader.rb'
+ - 'app/models/project.rb'
+ - 'app/models/release.rb'
+ - 'app/models/release_highlight.rb'
+ - 'app/services/authorized_project_update/project_recalculate_service.rb'
+ - 'app/services/notification_service.rb'
+ - 'config/initializers/wikicloth_redos_patch.rb'
+ - 'db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb'
+ - 'db/post_migrate/20210802043253_finalize_push_event_payloads_bigint_conversion_3.rb'
+ - 'ee/app/finders/security/training_providers/base_url_finder.rb'
+ - 'ee/app/graphql/mutations/incident_management/oncall_rotation/base.rb'
+ - 'ee/app/helpers/ee/dashboard_helper.rb'
+ - 'ee/app/models/approvals/scan_finding_wrapped_rule_set.rb'
+ - 'ee/app/models/compliance_management/framework.rb'
+ - 'ee/app/models/dora/daily_metrics.rb'
+ - 'ee/app/models/ee/application_setting.rb'
+ - 'ee/app/models/ee/member.rb'
+ - 'ee/app/models/vulnerabilities/identifier.rb'
+ - 'ee/app/serializers/vulnerabilities/finding_entity.rb'
+ - 'ee/app/services/elastic/cluster_reindexing_service.rb'
+ - 'ee/lib/ee/banzai/filter/references/iteration_reference_filter.rb'
+ - 'ee/lib/ee/gitlab/auth/ldap/group.rb'
+ - 'ee/lib/ee/gitlab/background_migration/drop_invalid_remediations.rb'
+ - 'ee/lib/elastic/latest/git_class_proxy.rb'
+ - 'ee/lib/gitlab/auth/smartcard/san_extension.rb'
+ - 'ee/lib/pseudonymizer/dumper.rb'
+ - 'ee/lib/world.rb'
+ - 'ee/spec/controllers/autocomplete_controller_spec.rb'
+ - 'ee/spec/controllers/countries_controller_spec.rb'
+ - 'ee/spec/controllers/groups/epics_controller_spec.rb'
+ - 'ee/spec/controllers/projects/issues_controller_spec.rb'
+ - 'ee/spec/controllers/projects/pipelines_controller_spec.rb'
+ - 'ee/spec/controllers/subscriptions_controller_spec.rb'
+ - 'ee/spec/elastic_integration/global_search_spec.rb'
+ - 'ee/spec/factories/dast/profiles_pipelines.rb'
+ - 'ee/spec/factories/licenses.rb'
+ - 'ee/spec/features/billings/billing_plans_spec.rb'
+ - 'ee/spec/features/boards/board_filters_spec.rb'
+ - 'ee/spec/features/boards/scoped_issue_board_spec.rb'
+ - 'ee/spec/features/boards/swimlanes/epics_swimlanes_filtering_spec.rb'
+ - 'ee/spec/features/epics/todo_spec.rb'
+ - 'ee/spec/features/google_analytics_datalayer_spec.rb'
+ - 'ee/spec/features/groups/issues_spec.rb'
+ - 'ee/spec/features/issues/filtered_search/filter_issues_by_iteration_spec.rb'
+ - 'ee/spec/features/issues/form_spec.rb'
+ - 'ee/spec/features/issues/issue_sidebar_spec.rb'
+ - 'ee/spec/features/issues/user_edits_issue_spec.rb'
+ - 'ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_spec.rb'
+ - 'ee/spec/features/merge_request/user_sees_closing_issues_message_spec.rb'
+ - 'ee/spec/features/merge_requests/user_resets_approvers_spec.rb'
+ - 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
+ - 'ee/spec/features/projects/integrations/user_activates_github_spec.rb'
+ - 'ee/spec/features/projects/push_rules_spec.rb'
+ - 'ee/spec/features/projects/security/dast_scanner_profiles_spec.rb'
+ - 'ee/spec/features/projects/security/dast_site_profiles_spec.rb'
+ - 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
+ - 'ee/spec/finders/billed_users_finder_spec.rb'
+ - 'ee/spec/finders/clusters/environments_finder_spec.rb'
+ - 'ee/spec/finders/dast/profiles_finder_spec.rb'
+ - 'ee/spec/finders/ee/namespaces/projects_finder_spec.rb'
+ - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb'
+ - 'ee/spec/finders/security/training_providers/kontra_url_finder_spec.rb'
+ - 'ee/spec/finders/security/vulnerabilities_finder_spec.rb'
+ - 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb'
+ - 'ee/spec/finders/status_page/incidents_finder_spec.rb'
+ - 'ee/spec/frontend/fixtures/epic.rb'
+ - 'ee/spec/frontend/fixtures/projects.rb'
+ - 'ee/spec/graphql/ee/resolvers/namespace_projects_resolver_spec.rb'
+ - 'ee/spec/graphql/mutations/boards/epics/create_spec.rb'
+ - 'ee/spec/graphql/mutations/compliance_management/frameworks/destroy_spec.rb'
+ - 'ee/spec/graphql/mutations/dast_site_validations/revoke_spec.rb'
+ - 'ee/spec/graphql/mutations/incident_management/escalation_policy/create_spec.rb'
+ - 'ee/spec/graphql/mutations/releases/update_spec.rb'
+ - 'ee/spec/graphql/mutations/vulnerabilities/destroy_external_issue_link_spec.rb'
+ - 'ee/spec/graphql/resolvers/iterations_resolver_spec.rb'
+ - 'ee/spec/helpers/ee/projects/pipeline_helper_spec.rb'
+ - 'ee/spec/helpers/ee/projects/security/dast_configuration_helper_spec.rb'
+ - 'ee/spec/helpers/ee/registrations_helper_spec.rb'
+ - 'ee/spec/helpers/ee/trial_helper_spec.rb'
+ - 'ee/spec/helpers/projects/on_demand_scans_helper_spec.rb'
+ - 'ee/spec/lib/analytics/group_activity_calculator_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/alert_management/payload/generic_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/drop_invalid_remediations_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/migrate_job_artifact_registry_to_ssf_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/ci/reports/security/reports_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/import_export/group/tree_saver_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/import_export/project/tree_restorer_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb'
+ - 'ee/spec/lib/ee/sidebars/groups/menus/issues_menu_spec.rb'
+ - 'ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb'
+ - 'ee/spec/lib/ee/sidebars/projects/menus/ci_cd_menu_spec.rb'
+ - 'ee/spec/lib/ee/sidebars/projects/menus/issues_menu_spec.rb'
+ - 'ee/spec/lib/ee/sidebars/projects/menus/repository_menu_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/gma_membership_enforcer_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/parsers/security/container_scanning_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/reports/license_scanning/dependency_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/reports/security/finding_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dependency_scanning_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/git_ssh_proxy_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_renamed_event_spec.rb'
+ - 'ee/spec/lib/gitlab/git_access_spec.rb'
+ - 'ee/spec/lib/gitlab/graphql/loaders/bulk_epic_aggregate_loader_spec.rb'
+ - 'ee/spec/lib/gitlab/ip_address_state_spec.rb'
+ - 'ee/spec/lib/gitlab/search_context/builder_spec.rb'
+ - 'ee/spec/lib/gitlab/status_page/filter/image_filter_spec.rb'
+ - 'ee/spec/lib/gitlab/usage/metrics/instrumentations/approval_project_rules_with_user_metric_spec.rb'
+ - 'ee/spec/lib/pseudonymizer/pager_spec.rb'
+ - 'ee/spec/lib/pseudonymizer/uploader_spec.rb'
+ - 'ee/spec/mailers/credentials_inventory_mailer_spec.rb'
+ - 'ee/spec/migrations/geo/migrate_job_artifact_registry_spec.rb'
+ - 'ee/spec/models/analytics/devops_adoption/enabled_namespace_spec.rb'
+ - 'ee/spec/models/analytics/devops_adoption/snapshot_spec.rb'
+ - 'ee/spec/models/approval_project_rule_spec.rb'
+ - 'ee/spec/models/approval_state_spec.rb'
+ - 'ee/spec/models/approvals/scan_finding_wrapped_rule_set_spec.rb'
+ - 'ee/spec/models/ci/minutes/limit_spec.rb'
+ - 'ee/spec/models/compliance_management/framework_spec.rb'
+ - 'ee/spec/models/concerns/ee/clusters/agents/authorization_config_scopes_spec.rb'
+ - 'ee/spec/models/concerns/elastic/issue_spec.rb'
+ - 'ee/spec/models/dast/profile_schedule_spec.rb'
+ - 'ee/spec/models/ee/audit_event_spec.rb'
+ - 'ee/spec/models/ee/ci/build_dependencies_spec.rb'
+ - 'ee/spec/models/ee/iteration_spec.rb'
+ - 'ee/spec/models/ee/namespace/root_storage_size_spec.rb'
+ - 'ee/spec/models/ee/namespace_limit_spec.rb'
+ - 'ee/spec/models/environment_spec.rb'
+ - 'ee/spec/models/epic_spec.rb'
+ - 'ee/spec/models/gitlab/seat_link_data_spec.rb'
+ - 'ee/spec/models/gitlab_subscription_spec.rb'
+ - 'ee/spec/models/member_spec.rb'
+ - 'ee/spec/models/milestone_release_spec.rb'
+ - 'ee/spec/models/project_member_spec.rb'
+ - 'ee/spec/models/protected_environment_spec.rb'
+ - 'ee/spec/models/push_rule_spec.rb'
+ - 'ee/spec/models/requirements_management/test_report_spec.rb'
+ - 'ee/spec/models/security/orchestration_policy_rule_schedule_spec.rb'
+ - 'ee/spec/models/vulnerabilities/feedback_spec.rb'
+ - 'ee/spec/models/vulnerabilities/finding_spec.rb'
+ - 'ee/spec/presenters/epic_issue_presenter_spec.rb'
+ - 'ee/spec/requests/api/analytics/code_review_analytics_spec.rb'
+ - 'ee/spec/requests/api/analytics/group_activity_analytics_spec.rb'
+ - 'ee/spec/requests/api/ci/minutes_spec.rb'
+ - 'ee/spec/requests/api/epic_links_spec.rb'
+ - 'ee/spec/requests/api/graphql/boards/board_lists_query_spec.rb'
+ - 'ee/spec/requests/api/graphql/group/epic/epic_aggregate_query_spec.rb'
+ - 'ee/spec/requests/api/graphql/group/epic/epic_issues_spec.rb'
+ - 'ee/spec/requests/api/graphql/group_query_spec.rb'
+ - 'ee/spec/requests/api/graphql/iteration_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/dast_site_validations/revoke_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/epic_tree/reorder_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/incident_management/oncall_rotation/update_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/releases/create_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/releases/update_spec.rb'
+ - 'ee/spec/requests/api/graphql/project/dast_profiles_spec.rb'
+ - 'ee/spec/requests/api/graphql/project/dast_site_validations_spec.rb'
+ - 'ee/spec/requests/api/graphql/project/issues_spec.rb'
+ - 'ee/spec/requests/api/graphql/projects/compliance_frameworks_spec.rb'
+ - 'ee/spec/requests/api/group_variables_spec.rb'
+ - 'ee/spec/requests/api/internal/base_spec.rb'
+ - 'ee/spec/requests/api/managed_licenses_spec.rb'
+ - 'ee/spec/requests/api/members_spec.rb'
+ - 'ee/spec/requests/api/projects_spec.rb'
+ - 'ee/spec/requests/api/protected_branches_spec.rb'
+ - 'ee/spec/requests/api/releases_spec.rb'
+ - 'ee/spec/requests/groups/contribution_analytics_spec.rb'
+ - 'ee/spec/requests/lfs_http_spec.rb'
+ - 'ee/spec/requests/projects/security/policies_controller_spec.rb'
+ - 'ee/spec/requests/survey_responses_controller_spec.rb'
+ - 'ee/spec/serializers/member_user_entity_spec.rb'
+ - 'ee/spec/serializers/merge_request_poll_widget_entity_spec.rb'
+ - 'ee/spec/serializers/vulnerabilities/finding_reports_comparer_entity_spec.rb'
+ - 'ee/spec/services/audit_events/register_runner_audit_event_service_spec.rb'
+ - 'ee/spec/services/audit_events/unregister_runner_audit_event_service_spec.rb'
+ - 'ee/spec/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service_spec.rb'
+ - 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
+ - 'ee/spec/services/ci/runners/register_runner_service_spec.rb'
+ - 'ee/spec/services/ee/design_management/delete_designs_service_spec.rb'
+ - 'ee/spec/services/ee/design_management/save_designs_service_spec.rb'
+ - 'ee/spec/services/ee/issuable/bulk_update_service_spec.rb'
+ - 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
+ - 'ee/spec/services/ee/notification_service_spec.rb'
+ - 'ee/spec/services/ee/vulnerability_feedback_module/update_service_spec.rb'
+ - 'ee/spec/services/epic_issues/create_service_spec.rb'
+ - 'ee/spec/services/epics/create_service_spec.rb'
+ - 'ee/spec/services/epics/descendant_count_service_spec.rb'
+ - 'ee/spec/services/epics/transfer_service_spec.rb'
+ - 'ee/spec/services/geo/container_repository_sync_service_spec.rb'
+ - 'ee/spec/services/geo/framework_repository_sync_service_spec.rb'
+ - 'ee/spec/services/geo/hashed_storage_attachments_event_store_spec.rb'
+ - 'ee/spec/services/geo/repository_sync_service_spec.rb'
+ - 'ee/spec/services/geo/wiki_sync_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/activate_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/apply_trial_service_spec.rb'
+ - 'ee/spec/services/group_saml/sign_up_service_spec.rb'
+ - 'ee/spec/services/groups/epics_count_service_spec.rb'
+ - 'ee/spec/services/groups/memberships/export_service_spec.rb'
+ - 'ee/spec/services/iterations/cadences/create_iterations_in_advance_service_spec.rb'
+ - 'ee/spec/services/merge_trains/check_status_service_spec.rb'
+ - 'ee/spec/services/personal_access_tokens/groups/update_lifetime_service_spec.rb'
+ - 'ee/spec/services/projects/destroy_service_spec.rb'
+ - 'ee/spec/services/projects/update_mirror_service_spec.rb'
+ - 'ee/spec/services/quick_actions/interpret_service_spec.rb'
+ - 'ee/spec/services/requirements_management/create_requirement_service_spec.rb'
+ - 'ee/spec/services/requirements_management/update_requirement_service_spec.rb'
+ - 'ee/spec/services/resource_access_tokens/create_service_spec.rb'
+ - 'ee/spec/services/search/group_service_spec.rb'
+ - 'ee/spec/services/security/ingestion/tasks/ingest_findings_spec.rb'
+ - 'ee/spec/services/security/security_orchestration_policies/policy_commit_service_spec.rb'
+ - 'ee/spec/services/sitemap/create_service_spec.rb'
+ - 'ee/spec/services/software_license_policies/update_service_spec.rb'
+ - 'ee/spec/services/status_page/publish_attachments_service_spec.rb'
+ - 'ee/spec/services/system_notes/epics_service_spec.rb'
+ - 'ee/spec/services/vulnerability_external_issue_links/create_service_spec.rb'
+ - 'ee/spec/services/vulnerability_feedback/destroy_service_spec.rb'
+ - 'ee/spec/support/shared_examples/features/ultimate_trial_callout_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/services/boards/base_service_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/services/search_notes_shared_examples.rb'
+ - 'ee/spec/tasks/gitlab/elastic_rake_spec.rb'
+ - 'ee/spec/uploaders/every_gitlab_uploader_spec.rb'
+ - 'ee/spec/views/registrations/groups_projects/new.html.haml_spec.rb'
+ - 'ee/spec/views/shared/billings/_eoa_bronze_plan_banner.html.haml_spec.rb'
+ - 'ee/spec/views/shared/credentials_inventory/_expiry_date.html.haml_spec.rb'
+ - 'ee/spec/views/shared/credentials_inventory/personal_access_tokens/_personal_access_token.html.haml_spec.rb'
+ - 'ee/spec/views/shared/credentials_inventory/ssh_keys/_ssh_key.html.haml_spec.rb'
+ - 'ee/spec/workers/adjourned_project_deletion_worker_spec.rb'
+ - 'ee/spec/workers/adjourned_projects_deletion_cron_worker_spec.rb'
+ - 'ee/spec/workers/security/create_orchestration_policy_worker_spec.rb'
+ - 'ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb'
+ - 'lib/api/commits.rb'
+ - 'lib/api/helpers/merge_requests_helpers.rb'
+ - 'lib/backup/manager.rb'
+ - 'lib/banzai/filter/references/label_reference_filter.rb'
+ - 'lib/banzai/filter/references/milestone_reference_filter.rb'
+ - 'lib/bitbucket/representation/base.rb'
+ - 'lib/bitbucket_server/representation/base.rb'
+ - 'lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb'
+ - 'lib/gitlab/contributions_calendar.rb'
+ - 'lib/gitlab/database/migrations/test_background_runner.rb'
+ - 'lib/gitlab/database/postgres_hll/buckets.rb'
+ - 'lib/gitlab/elasticsearch/logs/lines.rb'
+ - 'lib/gitlab/email/message/in_product_marketing/helper.rb'
+ - 'lib/gitlab/issues/rebalancing/state.rb'
+ - 'lib/gitlab/profiler.rb'
+ - 'lib/kramdown/converter/commonmark.rb'
+ - 'lib/release_highlights/validator/entry.rb'
+ - 'lib/security/ci_configuration/sast_build_action.rb'
+ - 'lib/tasks/gitlab/db.rake'
+ - 'lib/tasks/gitlab/info.rake'
+ - 'lib/tasks/gitlab/praefect.rake'
+ - 'lib/tasks/gitlab/shell.rake'
+ - 'lib/tasks/gitlab/tw/codeowners.rake'
+ - 'qa/qa/service/praefect_manager.rb'
+ - 'qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb'
+ - 'qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb'
+ - 'qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb'
+ - 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/license/cloud_activation_spec.rb'
+ - 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/license/license_spec.rb'
+ - 'qa/qa/specs/features/ee/browser_ui/12_geo/geo_replication_npm_registry_spec.rb'
+ - 'qa/spec/scenario/test/integration/mattermost_spec.rb'
+ - 'qa/spec/support/page_error_checker_spec.rb'
+ - 'rubocop/cop/migration/add_limit_to_text_columns.rb'
+ - 'spec/config/settings_spec.rb'
+ - 'spec/controllers/admin/application_settings_controller_spec.rb'
+ - 'spec/controllers/application_controller_spec.rb'
+ - 'spec/controllers/groups/labels_controller_spec.rb'
+ - 'spec/controllers/groups/releases_controller_spec.rb'
+ - 'spec/controllers/groups/settings/ci_cd_controller_spec.rb'
+ - 'spec/controllers/import/manifest_controller_spec.rb'
+ - 'spec/controllers/projects/blame_controller_spec.rb'
+ - 'spec/controllers/projects/deploy_keys_controller_spec.rb'
+ - 'spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb'
+ - 'spec/controllers/projects/feature_flags_controller_spec.rb'
+ - 'spec/controllers/projects/jobs_controller_spec.rb'
+ - 'spec/controllers/projects/labels_controller_spec.rb'
+ - 'spec/controllers/projects/notes_controller_spec.rb'
+ - 'spec/controllers/projects/releases_controller_spec.rb'
+ - 'spec/controllers/projects/tree_controller_spec.rb'
+ - 'spec/controllers/registrations/welcome_controller_spec.rb'
+ - 'spec/controllers/snippets/notes_controller_spec.rb'
+ - 'spec/dependencies/omniauth_saml_spec.rb'
+ - 'spec/experiments/application_experiment_spec.rb'
+ - 'spec/factories/ci/build_trace_chunks.rb'
+ - 'spec/factories/ci/job_artifacts.rb'
+ - 'spec/factories/ci/pipeline_artifacts.rb'
+ - 'spec/factories/commit_statuses.rb'
+ - 'spec/factories/emails.rb'
+ - 'spec/factories/external_pull_requests.rb'
+ - 'spec/factories/gitlab/database/postgres_index.rb'
+ - 'spec/factories/packages/dependencies.rb'
+ - 'spec/factories/packages/package_tags.rb'
+ - 'spec/factories/packages/packages.rb'
+ - 'spec/factories/prometheus_alert.rb'
+ - 'spec/factories/prometheus_metrics.rb'
+ - 'spec/features/admin/admin_mode/login_spec.rb'
+ - 'spec/features/admin/users/users_spec.rb'
+ - 'spec/features/boards/board_filters_spec.rb'
+ - 'spec/features/boards/reload_boards_on_browser_back_spec.rb'
+ - 'spec/features/dashboard/archived_projects_spec.rb'
+ - 'spec/features/error_tracking/user_filters_errors_by_status_spec.rb'
+ - 'spec/features/groups/issues_spec.rb'
+ - 'spec/features/groups_spec.rb'
+ - 'spec/features/issuables/user_sees_sidebar_spec.rb'
+ - 'spec/features/issues/gfm_autocomplete_spec.rb'
+ - 'spec/features/issues/todo_spec.rb'
+ - 'spec/features/issues/user_bulk_edits_issues_spec.rb'
+ - 'spec/features/issues/user_interacts_with_awards_spec.rb'
+ - 'spec/features/issues/user_uses_quick_actions_spec.rb'
+ - 'spec/features/merge_request/user_approves_spec.rb'
+ - 'spec/features/merge_request/user_customizes_merge_commit_message_spec.rb'
+ - 'spec/features/merge_request/user_edits_assignees_sidebar_spec.rb'
+ - 'spec/features/merge_request/user_sees_closing_issues_message_spec.rb'
+ - 'spec/features/merge_request/user_sees_deployment_widget_spec.rb'
+ - 'spec/features/merge_request/user_sees_diff_spec.rb'
+ - 'spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb'
+ - 'spec/features/merge_request/user_sees_versions_spec.rb'
+ - 'spec/features/merge_request/user_uses_quick_actions_spec.rb'
+ - 'spec/features/profiles/user_edit_profile_spec.rb'
+ - 'spec/features/projects/cluster_agents_spec.rb'
+ - 'spec/features/projects/commits/user_browses_commits_spec.rb'
+ - 'spec/features/projects/environments/environment_spec.rb'
+ - 'spec/features/projects/files/user_browses_files_spec.rb'
+ - 'spec/features/projects/pipelines/pipelines_spec.rb'
+ - 'spec/features/projects/settings/service_desk_setting_spec.rb'
+ - 'spec/features/projects/tree/tree_show_spec.rb'
+ - 'spec/features/refactor_blob_viewer_disabled/projects/files/user_browses_files_spec.rb'
+ - 'spec/features/users/login_spec.rb'
+ - 'spec/finders/ci/jobs_finder_spec.rb'
+ - 'spec/finders/ci/runners_finder_spec.rb'
+ - 'spec/finders/concerns/packages/finder_helper_spec.rb'
+ - 'spec/finders/container_repositories_finder_spec.rb'
+ - 'spec/finders/design_management/versions_finder_spec.rb'
+ - 'spec/finders/milestones_finder_spec.rb'
+ - 'spec/finders/packages/group_packages_finder_spec.rb'
+ - 'spec/finders/packages/npm/package_finder_spec.rb'
+ - 'spec/finders/projects_finder_spec.rb'
+ - 'spec/frontend/fixtures/api_merge_requests.rb'
+ - 'spec/frontend/fixtures/api_projects.rb'
+ - 'spec/frontend/fixtures/application_settings.rb'
+ - 'spec/frontend/fixtures/blob.rb'
+ - 'spec/frontend/fixtures/branches.rb'
+ - 'spec/frontend/fixtures/clusters.rb'
+ - 'spec/frontend/fixtures/deploy_keys.rb'
+ - 'spec/frontend/fixtures/groups.rb'
+ - 'spec/frontend/fixtures/issues.rb'
+ - 'spec/frontend/fixtures/jobs.rb'
+ - 'spec/frontend/fixtures/labels.rb'
+ - 'spec/frontend/fixtures/merge_requests.rb'
+ - 'spec/frontend/fixtures/merge_requests_diffs.rb'
+ - 'spec/frontend/fixtures/metrics_dashboard.rb'
+ - 'spec/frontend/fixtures/pipeline_schedules.rb'
+ - 'spec/frontend/fixtures/pipelines.rb'
+ - 'spec/frontend/fixtures/projects.rb'
+ - 'spec/frontend/fixtures/prometheus_service.rb'
+ - 'spec/frontend/fixtures/raw.rb'
+ - 'spec/frontend/fixtures/services.rb'
+ - 'spec/frontend/fixtures/snippet.rb'
+ - 'spec/frontend/fixtures/todos.rb'
+ - 'spec/graphql/mutations/merge_requests/set_labels_spec.rb'
+ - 'spec/graphql/mutations/releases/create_spec.rb'
+ - 'spec/graphql/mutations/releases/delete_spec.rb'
+ - 'spec/graphql/mutations/releases/update_spec.rb'
+ - 'spec/graphql/resolvers/ci/runner_jobs_resolver_spec.rb'
+ - 'spec/graphql/resolvers/group_members/notification_email_resolver_spec.rb'
+ - 'spec/graphql/resolvers/project_jobs_resolver_spec.rb'
+ - 'spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb'
+ - 'spec/graphql/resolvers/projects_resolver_spec.rb'
+ - 'spec/graphql/types/ci/job_token_scope_type_spec.rb'
+ - 'spec/graphql/types/issue_type_spec.rb'
+ - 'spec/graphql/types/user_type_spec.rb'
+ - 'spec/helpers/application_settings_helper_spec.rb'
+ - 'spec/helpers/blob_helper_spec.rb'
+ - 'spec/helpers/gitlab_script_tag_helper_spec.rb'
+ - 'spec/helpers/issuables_helper_spec.rb'
+ - 'spec/helpers/projects/pipeline_helper_spec.rb'
+ - 'spec/helpers/routing/pseudonymization_helper_spec.rb'
+ - 'spec/helpers/search_helper_spec.rb'
+ - 'spec/helpers/wiki_page_version_helper_spec.rb'
+ - 'spec/initializers/carrierwave_patch_spec.rb'
+ - 'spec/initializers/trusted_proxies_spec.rb'
+ - 'spec/lib/api/entities/ci/job_request/image_spec.rb'
+ - 'spec/lib/api/entities/ci/job_request/port_spec.rb'
+ - 'spec/lib/api/helpers/sse_helpers_spec.rb'
+ - 'spec/lib/api/helpers_spec.rb'
+ - 'spec/lib/banzai/cross_project_reference_spec.rb'
+ - 'spec/lib/banzai/filter/broadcast_message_placeholders_filter_spec.rb'
+ - 'spec/lib/banzai/filter/commit_trailers_filter_spec.rb'
+ - 'spec/lib/banzai/pipeline/plain_markdown_pipeline_spec.rb'
+ - 'spec/lib/banzai/renderer_spec.rb'
+ - 'spec/lib/bitbucket_server/connection_spec.rb'
+ - 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb'
+ - 'spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb'
+ - 'spec/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline_spec.rb'
+ - 'spec/lib/feature/definition_spec.rb'
+ - 'spec/lib/feature_spec.rb'
+ - 'spec/lib/gitlab/application_context_spec.rb'
+ - 'spec/lib/gitlab/asciidoc_spec.rb'
+ - 'spec/lib/gitlab/audit/ci_runner_token_author_spec.rb'
+ - 'spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb'
+ - 'spec/lib/gitlab/batch_pop_queueing_spec.rb'
+ - 'spec/lib/gitlab/chat_name_token_spec.rb'
+ - 'spec/lib/gitlab/ci/ansi2html_spec.rb'
+ - 'spec/lib/gitlab/ci/ansi2json_spec.rb'
+ - 'spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/processable_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/release_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/tags_spec.rb'
+ - 'spec/lib/gitlab/ci/config/external/file/base_spec.rb'
+ - 'spec/lib/gitlab/ci/config/external/file/local_spec.rb'
+ - 'spec/lib/gitlab/ci/config/external/file/remote_spec.rb'
+ - 'spec/lib/gitlab/ci/config/normalizer_spec.rb'
+ - 'spec/lib/gitlab/ci/cron_parser_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/chain/seed_block_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb'
+ - 'spec/lib/gitlab/ci/reports/security/reports_spec.rb'
+ - 'spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb'
+ - 'spec/lib/gitlab/ci/reports/test_suite_spec.rb'
+ - 'spec/lib/gitlab/ci/status/build/canceled_spec.rb'
+ - 'spec/lib/gitlab/ci/status/build/created_spec.rb'
+ - 'spec/lib/gitlab/ci/status/build/manual_spec.rb'
+ - 'spec/lib/gitlab/ci/status/build/pending_spec.rb'
+ - 'spec/lib/gitlab/ci/status/build/skipped_spec.rb'
+ - 'spec/lib/gitlab/ci/status/processable/waiting_for_resource_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/trace/remote_checksum_spec.rb'
+ - 'spec/lib/gitlab/ci/yaml_processor_spec.rb'
+ - 'spec/lib/gitlab/composer/cache_spec.rb'
+ - 'spec/lib/gitlab/data_builder/build_spec.rb'
+ - 'spec/lib/gitlab/data_builder/pipeline_spec.rb'
+ - 'spec/lib/gitlab/database/background_migration/batched_migration_spec.rb'
+ - 'spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb'
+ - 'spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb'
+ - 'spec/lib/gitlab/database/migration_helpers/v2_spec.rb'
+ - 'spec/lib/gitlab/database/migration_helpers_spec.rb'
+ - 'spec/lib/gitlab/database/migrations/lock_retry_mixin_spec.rb'
+ - 'spec/lib/gitlab/database/migrations/runner_spec.rb'
+ - 'spec/lib/gitlab/database/partitioning_spec.rb'
+ - 'spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb'
+ - 'spec/lib/gitlab/database/with_lock_retries_outside_transaction_spec.rb'
+ - 'spec/lib/gitlab/database/with_lock_retries_spec.rb'
+ - 'spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb'
+ - 'spec/lib/gitlab/database_spec.rb'
+ - 'spec/lib/gitlab/elasticsearch/logs/lines_spec.rb'
+ - 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
+ - 'spec/lib/gitlab/email/handler/service_desk_handler_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/admin_verify_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/experience_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/team_short_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/trial_short_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb'
+ - 'spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb'
+ - 'spec/lib/gitlab/error_tracking/processor/sidekiq_processor_spec.rb'
+ - 'spec/lib/gitlab/exclusive_lease_helpers_spec.rb'
+ - 'spec/lib/gitlab/file_markdown_link_builder_spec.rb'
+ - 'spec/lib/gitlab/git/blob_spec.rb'
+ - 'spec/lib/gitlab/git/commit_spec.rb'
+ - 'spec/lib/gitlab/git/diff_collection_spec.rb'
+ - 'spec/lib/gitlab/git/raw_diff_change_spec.rb'
+ - 'spec/lib/gitlab/git/repository_spec.rb'
+ - 'spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb'
+ - 'spec/lib/gitlab/gitaly_client/commit_service_spec.rb'
+ - 'spec/lib/gitlab/github_import/client_spec.rb'
+ - 'spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb'
+ - 'spec/lib/gitlab/gpg_spec.rb'
+ - 'spec/lib/gitlab/graphql/markdown_field_spec.rb'
+ - 'spec/lib/gitlab/graphql/pagination/keyset/connection_generic_keyset_spec.rb'
+ - 'spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb'
+ - 'spec/lib/gitlab/graphs/commits_spec.rb'
+ - 'spec/lib/gitlab/highlight_spec.rb'
+ - 'spec/lib/gitlab/import_export/import_test_coverage_spec.rb'
+ - 'spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb'
+ - 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
+ - 'spec/lib/gitlab/import_export/version_checker_spec.rb'
+ - 'spec/lib/gitlab/jira/dvcs_spec.rb'
+ - 'spec/lib/gitlab/kubernetes/rollout_status_spec.rb'
+ - 'spec/lib/gitlab/metrics/background_transaction_spec.rb'
+ - 'spec/lib/gitlab/metrics/web_transaction_spec.rb'
+ - 'spec/lib/gitlab/middleware/compressed_json_spec.rb'
+ - 'spec/lib/gitlab/middleware/sidekiq_web_static_spec.rb'
+ - 'spec/lib/gitlab/otp_key_rotator_spec.rb'
+ - 'spec/lib/gitlab/pagination/keyset_spec.rb'
+ - 'spec/lib/gitlab/phabricator_import/conduit/response_spec.rb'
+ - 'spec/lib/gitlab/prometheus_client_spec.rb'
+ - 'spec/lib/gitlab/quick_actions/command_definition_spec.rb'
+ - 'spec/lib/gitlab/quick_actions/extractor_spec.rb'
+ - 'spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb'
+ - 'spec/lib/gitlab/rack_attack/user_allowlist_spec.rb'
+ - 'spec/lib/gitlab/redis/hll_spec.rb'
+ - 'spec/lib/gitlab/reference_counter_spec.rb'
+ - 'spec/lib/gitlab/regex_spec.rb'
+ - 'spec/lib/gitlab/search/abuse_detection_spec.rb'
+ - 'spec/lib/gitlab/search_context/builder_spec.rb'
+ - 'spec/lib/gitlab/session_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb'
+ - 'spec/lib/gitlab/spamcheck/client_spec.rb'
+ - 'spec/lib/gitlab/suggestions/file_suggestion_spec.rb'
+ - 'spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb'
+ - 'spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb'
+ - 'spec/lib/gitlab/utils/sanitize_node_link_spec.rb'
+ - 'spec/lib/gitlab/utils/usage_data_spec.rb'
+ - 'spec/lib/gitlab/utils_spec.rb'
+ - 'spec/lib/gitlab/verify/uploads_spec.rb'
+ - 'spec/lib/gitlab/version_info_spec.rb'
+ - 'spec/lib/json_web_token/rsa_token_spec.rb'
+ - 'spec/lib/marginalia_spec.rb'
+ - 'spec/lib/mattermost/session_spec.rb'
+ - 'spec/lib/microsoft_teams/notifier_spec.rb'
+ - 'spec/lib/sidebars/groups/menus/group_information_menu_spec.rb'
+ - 'spec/lib/sidebars/menu_spec.rb'
+ - 'spec/mailers/emails/service_desk_spec.rb'
+ - 'spec/migrations/20210812013042_remove_duplicate_project_authorizations_spec.rb'
+ - 'spec/migrations/20210910194952_update_report_type_for_existing_approval_project_rules_spec.rb'
+ - 'spec/migrations/confirm_support_bot_user_spec.rb'
+ - 'spec/migrations/reset_job_token_scope_enabled_again_spec.rb'
+ - 'spec/migrations/reset_job_token_scope_enabled_spec.rb'
+ - 'spec/migrations/reset_severity_levels_to_new_default_spec.rb'
+ - 'spec/migrations/schedule_copy_ci_builds_columns_to_security_scans2_spec.rb'
+ - 'spec/models/active_session_spec.rb'
+ - 'spec/models/aws/role_spec.rb'
+ - 'spec/models/ci/build_dependencies_spec.rb'
+ - 'spec/models/ci/build_runner_session_spec.rb'
+ - 'spec/models/ci/build_spec.rb'
+ - 'spec/models/ci/daily_build_group_report_result_spec.rb'
+ - 'spec/models/ci/job_artifact_spec.rb'
+ - 'spec/models/ci/pipeline_schedule_spec.rb'
+ - 'spec/models/ci/pipeline_spec.rb'
+ - 'spec/models/ci/runner_spec.rb'
+ - 'spec/models/clusters/applications/elastic_stack_spec.rb'
+ - 'spec/models/clusters/cluster_spec.rb'
+ - 'spec/models/commit_status_spec.rb'
+ - 'spec/models/concerns/chronic_duration_attribute_spec.rb'
+ - 'spec/models/concerns/counter_attribute_spec.rb'
+ - 'spec/models/concerns/nullify_if_blank_spec.rb'
+ - 'spec/models/concerns/reactive_caching_spec.rb'
+ - 'spec/models/concerns/token_authenticatable_spec.rb'
+ - 'spec/models/container_expiration_policy_spec.rb'
+ - 'spec/models/container_repository_spec.rb'
+ - 'spec/models/environment_spec.rb'
+ - 'spec/models/event_spec.rb'
+ - 'spec/models/group_spec.rb'
+ - 'spec/models/hooks/web_hook_log_spec.rb'
+ - 'spec/models/integrations/chat_message/wiki_page_message_spec.rb'
+ - 'spec/models/issue_spec.rb'
+ - 'spec/models/jira_import_state_spec.rb'
+ - 'spec/models/merge_request_spec.rb'
+ - 'spec/models/namespace/root_storage_statistics_spec.rb'
+ - 'spec/models/namespace_spec.rb'
+ - 'spec/models/note_spec.rb'
+ - 'spec/models/onboarding_progress_spec.rb'
+ - 'spec/models/packages/conan/metadatum_spec.rb'
+ - 'spec/models/packages/package_file_spec.rb'
+ - 'spec/models/packages/package_spec.rb'
+ - 'spec/models/postgresql/replication_slot_spec.rb'
+ - 'spec/models/preloaders/labels_preloader_spec.rb'
+ - 'spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb'
+ - 'spec/models/project_spec.rb'
+ - 'spec/models/release_spec.rb'
+ - 'spec/models/releases/link_spec.rb'
+ - 'spec/models/remote_mirror_spec.rb'
+ - 'spec/models/repository_spec.rb'
+ - 'spec/models/snippet_input_action_collection_spec.rb'
+ - 'spec/models/snippet_spec.rb'
+ - 'spec/models/user_spec.rb'
+ - 'spec/models/users/calloutable_spec.rb'
+ - 'spec/models/wiki_page/meta_spec.rb'
+ - 'spec/policies/clusters/agent_policy_spec.rb'
+ - 'spec/policies/group_member_policy_spec.rb'
+ - 'spec/policies/issue_policy_spec.rb'
+ - 'spec/policies/project_policy_spec.rb'
+ - 'spec/policies/terraform/state_policy_spec.rb'
+ - 'spec/policies/terraform/state_version_policy_spec.rb'
+ - 'spec/presenters/packages/composer/packages_presenter_spec.rb'
+ - 'spec/presenters/packages/conan/package_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/packages_metadata_presenter_spec.rb'
+ - 'spec/presenters/packages/pypi/package_presenter_spec.rb'
+ - 'spec/presenters/project_presenter_spec.rb'
+ - 'spec/requests/api/branches_spec.rb'
+ - 'spec/requests/api/ci/jobs_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_trace_spec.rb'
+ - 'spec/requests/api/ci/secure_files_spec.rb'
+ - 'spec/requests/api/ci/triggers_spec.rb'
+ - 'spec/requests/api/ci/variables_spec.rb'
+ - 'spec/requests/api/commits_spec.rb'
+ - 'spec/requests/api/conan_instance_packages_spec.rb'
+ - 'spec/requests/api/conan_project_packages_spec.rb'
+ - 'spec/requests/api/dependency_proxy_spec.rb'
+ - 'spec/requests/api/go_proxy_spec.rb'
+ - 'spec/requests/api/graphql/boards/board_list_issues_query_spec.rb'
+ - 'spec/requests/api/graphql/boards/board_lists_query_spec.rb'
+ - 'spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb'
+ - 'spec/requests/api/graphql/mutations/award_emojis/add_spec.rb'
+ - 'spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb'
+ - 'spec/requests/api/graphql/mutations/releases/create_spec.rb'
+ - 'spec/requests/api/graphql/mutations/releases/update_spec.rb'
+ - 'spec/requests/api/graphql/mutations/snippets/create_spec.rb'
+ - 'spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb'
+ - 'spec/requests/api/graphql/packages/conan_spec.rb'
+ - 'spec/requests/api/graphql/packages/helm_spec.rb'
+ - 'spec/requests/api/graphql/packages/package_spec.rb'
+ - 'spec/requests/api/graphql/project/base_service_spec.rb'
+ - 'spec/requests/api/graphql/project/jira_import_spec.rb'
+ - 'spec/requests/api/group_variables_spec.rb'
+ - 'spec/requests/api/groups_spec.rb'
+ - 'spec/requests/api/helpers_spec.rb'
+ - 'spec/requests/api/internal/base_spec.rb'
+ - 'spec/requests/api/markdown_spec.rb'
+ - 'spec/requests/api/maven_packages_spec.rb'
+ - 'spec/requests/api/metrics/dashboard/annotations_spec.rb'
+ - 'spec/requests/api/notes_spec.rb'
+ - 'spec/requests/api/npm_project_packages_spec.rb'
+ - 'spec/requests/api/nuget_group_packages_spec.rb'
+ - 'spec/requests/api/pages/pages_spec.rb'
+ - 'spec/requests/api/pages_domains_spec.rb'
+ - 'spec/requests/api/personal_access_tokens_spec.rb'
+ - 'spec/requests/api/project_hooks_spec.rb'
+ - 'spec/requests/api/project_templates_spec.rb'
+ - 'spec/requests/api/projects_spec.rb'
+ - 'spec/requests/api/pypi_packages_spec.rb'
+ - 'spec/requests/api/release/links_spec.rb'
+ - 'spec/requests/api/releases_spec.rb'
+ - 'spec/requests/api/snippets_spec.rb'
+ - 'spec/requests/api/unleash_spec.rb'
+ - 'spec/requests/git_http_spec.rb'
+ - 'spec/requests/groups/milestones_controller_spec.rb'
+ - 'spec/requests/lfs_http_spec.rb'
+ - 'spec/requests/oauth/tokens_controller_spec.rb'
+ - 'spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb'
+ - 'spec/serializers/cluster_entity_spec.rb'
+ - 'spec/serializers/deploy_key_entity_spec.rb'
+ - 'spec/serializers/import/provider_repo_serializer_spec.rb'
+ - 'spec/services/auto_merge/base_service_spec.rb'
+ - 'spec/services/auto_merge_service_spec.rb'
+ - 'spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb'
+ - 'spec/services/ci/parse_dotenv_artifact_service_spec.rb'
+ - 'spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb'
+ - 'spec/services/ci/process_build_service_spec.rb'
+ - 'spec/services/ci/runners/register_runner_service_spec.rb'
+ - 'spec/services/ci/runners/update_runner_service_spec.rb'
+ - 'spec/services/ci/stuck_builds/drop_pending_service_spec.rb'
+ - 'spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb'
+ - 'spec/services/clusters/integrations/create_service_spec.rb'
+ - 'spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb'
+ - 'spec/services/deployments/create_for_build_service_spec.rb'
+ - 'spec/services/git/branch_push_service_spec.rb'
+ - 'spec/services/groups/destroy_service_spec.rb'
+ - 'spec/services/groups/merge_requests_count_service_spec.rb'
+ - 'spec/services/groups/update_service_spec.rb'
+ - 'spec/services/groups/update_statistics_service_spec.rb'
+ - 'spec/services/import/validate_remote_git_endpoint_service_spec.rb'
+ - 'spec/services/issues/referenced_merge_requests_service_spec.rb'
+ - 'spec/services/jira_import/start_import_service_spec.rb'
+ - 'spec/services/lfs/push_service_spec.rb'
+ - 'spec/services/members/invite_service_spec.rb'
+ - 'spec/services/merge_requests/push_options_handler_service_spec.rb'
+ - 'spec/services/merge_requests/refresh_service_spec.rb'
+ - 'spec/services/merge_requests/update_service_spec.rb'
+ - 'spec/services/milestones/transfer_service_spec.rb'
+ - 'spec/services/notes/copy_service_spec.rb'
+ - 'spec/services/notification_service_spec.rb'
+ - 'spec/services/packages/composer/create_package_service_spec.rb'
+ - 'spec/services/packages/create_dependency_service_spec.rb'
+ - 'spec/services/packages/debian/extract_deb_metadata_service_spec.rb'
+ - 'spec/services/packages/debian/parse_debian822_service_spec.rb'
+ - 'spec/services/packages/debian/sign_distribution_service_spec.rb'
+ - 'spec/services/packages/helm/process_file_service_spec.rb'
+ - 'spec/services/packages/npm/create_package_service_spec.rb'
+ - 'spec/services/packages/rubygems/dependency_resolver_service_spec.rb'
+ - 'spec/services/pages/delete_service_spec.rb'
+ - 'spec/services/projects/container_repository/third_party/delete_tags_service_spec.rb'
+ - 'spec/services/projects/enable_deploy_key_service_spec.rb'
+ - 'spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb'
+ - 'spec/services/projects/lfs_pointers/lfs_download_service_spec.rb'
+ - 'spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb'
+ - 'spec/services/projects/participants_service_spec.rb'
+ - 'spec/services/projects/update_statistics_service_spec.rb'
+ - 'spec/services/quick_actions/interpret_service_spec.rb'
+ - 'spec/services/releases/destroy_service_spec.rb'
+ - 'spec/services/releases/update_service_spec.rb'
+ - 'spec/services/resource_access_tokens/create_service_spec.rb'
+ - 'spec/services/search/group_service_spec.rb'
+ - 'spec/services/snippets/update_service_spec.rb'
+ - 'spec/services/suggestions/apply_service_spec.rb'
+ - 'spec/services/system_notes/merge_requests_service_spec.rb'
+ - 'spec/services/terraform/remote_state_handler_spec.rb'
+ - 'spec/services/todo_service_spec.rb'
+ - 'spec/services/todos/destroy/design_service_spec.rb'
+ - 'spec/services/todos/destroy/entity_leave_service_spec.rb'
+ - 'spec/services/web_hook_service_spec.rb'
+ - 'spec/support/helpers/cycle_analytics_helpers.rb'
+ - 'spec/support/redis/redis_shared_examples.rb'
+ - 'spec/support/shared_contexts/features/integrations/integrations_shared_context.rb'
+ - 'spec/support/shared_contexts/graphql/requests/packages_shared_context.rb'
+ - 'spec/support/shared_contexts/markdown_golden_master_shared_examples.rb'
+ - 'spec/support/shared_contexts/requests/api/conan_packages_shared_context.rb'
+ - 'spec/support/shared_examples/controllers/error_tracking_shared_examples.rb'
+ - 'spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb'
+ - 'spec/support/shared_examples/features/board_sidebar_labels_examples.rb'
+ - 'spec/support/shared_examples/features/snippets_shared_examples.rb'
+ - 'spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb'
+ - 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
+ - 'spec/support/shared_examples/lib/gitlab/sql/set_operator_shared_examples.rb'
+ - 'spec/support/shared_examples/models/cluster_application_core_shared_examples.rb'
+ - 'spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb'
+ - 'spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb'
+ - 'spec/support/shared_examples/models/concerns/incident_management/escalatable_shared_examples.rb'
+ - 'spec/support/shared_examples/models/label_note_shared_examples.rb'
+ - 'spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb'
+ - 'spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/labels_api_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/repository_storage_moves_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/lfs_http_shared_examples.rb'
+ - 'spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb'
+ - 'spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb'
+ - 'spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb'
+ - 'spec/support/shared_examples/services/merge_request_shared_examples.rb'
+ - 'spec/support/shared_examples/uploaders/object_storage_shared_examples.rb'
+ - 'spec/tasks/gitlab/snippets_rake_spec.rb'
+ - 'spec/uploaders/packages/debian/distribution_release_file_uploader_spec.rb'
+ - 'spec/validators/addressable_url_validator_spec.rb'
+ - 'spec/views/help/instance_configuration.html.haml_spec.rb'
+ - 'spec/views/layouts/_header_search.html.haml_spec.rb'
+ - 'spec/views/layouts/_published_experiments.html.haml_spec.rb'
+ - 'spec/views/shared/runners/_runner_details.html.haml_spec.rb'
+ - 'spec/workers/bulk_imports/export_request_worker_spec.rb'
+ - 'spec/workers/clusters/cleanup/project_namespace_worker_spec.rb'
+ - 'spec/workers/packages/helm/extraction_worker_spec.rb'
+ - 'spec/workers/pages_worker_spec.rb'
+ - 'spec/workers/purge_dependency_proxy_cache_worker_spec.rb'
+ - 'spec/workers/releases/manage_evidence_worker_spec.rb'
+ - 'spec/workers/repository_remove_remote_worker_spec.rb'
diff --git a/.rubocop_todo/lint/binary_operator_with_identical_operands.yml b/.rubocop_todo/lint/binary_operator_with_identical_operands.yml
new file mode 100644
index 00000000000..90c3a76d3b1
--- /dev/null
+++ b/.rubocop_todo/lint/binary_operator_with_identical_operands.yml
@@ -0,0 +1,15 @@
+---
+Lint/BinaryOperatorWithIdenticalOperands:
+ Exclude:
+ - 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
+ - 'spec/helpers/visibility_level_helper_spec.rb'
+ - 'spec/lib/gitlab/conan_token_spec.rb'
+ - 'spec/lib/gitlab/git/conflict/parser_spec.rb'
+ - 'spec/lib/gitlab/graphql/lazy_spec.rb'
+ - 'spec/models/ci/build_trace_chunk_spec.rb'
+ - 'spec/models/clusters/platforms/kubernetes_spec.rb'
+ - 'spec/models/concerns/where_composite_spec.rb'
+ - 'spec/models/metrics/dashboard/annotation_spec.rb'
+ - 'spec/models/repository_spec.rb'
+ - 'spec/models/ssh_host_key_spec.rb'
+ - 'spec/tooling/danger/sidekiq_queues_spec.rb'
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index 27ea2e7a608..1d6a71aca47 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -4,7 +4,7 @@ import { sortBy } from 'lodash';
import Draggable from 'vuedraggable';
import { mapState, mapGetters, mapActions } from 'vuex';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
-import defaultSortableConfig from '~/sortable/sortable_config';
+import { defaultSortableOptions } from '~/sortable/constants';
import { DraggableItemTypes } from '../constants';
import BoardColumn from './board_column.vue';
@@ -43,7 +43,7 @@ export default {
},
draggableOptions() {
const options = {
- ...defaultSortableConfig,
+ ...defaultSortableOptions,
disabled: this.disabled,
draggable: '.is-draggable',
fallbackOnBody: false,
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 858cd368b12..47f25f34d0c 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -2,9 +2,9 @@
import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
import Draggable from 'vuedraggable';
import { mapActions, mapGetters, mapState } from 'vuex';
-import { sortableStart, sortableEnd } from '~/boards/mixins/sortable_default_options';
import { sprintf, __ } from '~/locale';
-import defaultSortableConfig from '~/sortable/sortable_config';
+import { defaultSortableOptions } from '~/sortable/constants';
+import { sortableStart, sortableEnd } from '~/sortable/utils';
import Tracking from '~/tracking';
import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
import { toggleFormEventPrefix, DraggableItemTypes } from '../constants';
@@ -121,7 +121,7 @@ export default {
},
treeRootOptions() {
const options = {
- ...defaultSortableConfig,
+ ...defaultSortableOptions,
fallbackOnBody: false,
group: 'board-list',
tag: 'ul',
diff --git a/app/assets/javascripts/boards/components/issuable_title.vue b/app/assets/javascripts/boards/components/issuable_title.vue
deleted file mode 100644
index 40627a9fab8..00000000000
--- a/app/assets/javascripts/boards/components/issuable_title.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-<script>
-export default {
- props: {
- title: {
- type: String,
- required: true,
- },
- refPath: {
- type: String,
- required: true,
- },
- },
-};
-</script>
-
-<template>
- <div data-testid="issue-title">
- <p class="gl-font-weight-bold">{{ title }}</p>
- <p class="gl-mb-0">{{ refPath }}</p>
- </div>
-</template>
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index 8d0f6079f8f..8f8712365be 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -130,7 +130,7 @@ export default {
:link-href="authorUrl"
:img-src="authorAvatar"
:img-alt="authorName"
- :img-size="40"
+ :img-size="32"
class="avatar-cell d-none d-sm-block"
/>
</div>
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue
index 516e48ed531..661299920c7 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_form.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue
@@ -167,6 +167,9 @@ export default {
this.integrationActive = integrationActive;
},
},
+ descriptionHtmlConfig: {
+ ADD_ATTR: ['target'], // allow external links, can be removed after https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427 is implemented
+ },
helpHtmlConfig: {
ADD_ATTR: ['target'], // allow external links, can be removed after https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427 is implemented
ADD_TAGS: ['use'], // to support icon SVGs
@@ -212,7 +215,7 @@ export default {
<div class="row">
<div class="col-lg-4">
<h4 class="gl-mt-0">{{ section.title }}</h4>
- <p v-safe-html="section.description"></p>
+ <p v-safe-html:[$options.descriptionHtmlConfig]="section.description"></p>
</div>
<div class="col-lg-8">
diff --git a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
index 4503bb8e3c8..f00339c92fa 100644
--- a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
@@ -1,5 +1,5 @@
<script>
-import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
+import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mapGetters } from 'vuex';
import { s__, __ } from '~/locale';
import JiraUpgradeCta from './jira_upgrade_cta.vue';
@@ -10,8 +10,6 @@ export default {
GlFormGroup,
GlFormCheckbox,
GlFormInput,
- GlSprintf,
- GlLink,
JiraUpgradeCta,
JiraIssueCreationVulnerabilities: () =>
import('ee_component/integrations/edit/components/jira_issue_creation_vulnerabilities.vue'),
@@ -47,21 +45,11 @@ export default {
required: false,
default: null,
},
- gitlabIssuesEnabled: {
- type: Boolean,
- required: false,
- default: true,
- },
upgradePlanPath: {
type: String,
required: false,
default: '',
},
- editProjectPath: {
- type: String,
- required: false,
- default: '',
- },
isValidated: {
type: Boolean,
required: false,
@@ -91,9 +79,6 @@ export default {
projectKeyLabel: s__('JiraService|Jira project key'),
projectKeyPlaceholder: s__('JiraService|For example, AB'),
requiredFieldFeedback: __('This field is required.'),
- issueTrackerConflictWarning: s__(
- 'JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used.',
- ),
},
};
</script>
@@ -112,12 +97,34 @@ export default {
{{ $options.i18n.enableCheckboxHelp }}
</template>
</gl-form-checkbox>
- <template v-if="enableJiraIssues">
+
+ <div v-if="enableJiraIssues" class="gl-pl-6 gl-mt-3">
+ <gl-form-group
+ :label="$options.i18n.projectKeyLabel"
+ label-for="service_project_key"
+ :invalid-feedback="$options.i18n.requiredFieldFeedback"
+ :state="validProjectKey"
+ class="gl-max-w-26"
+ data-testid="project-key-form-group"
+ >
+ <gl-form-input
+ id="service_project_key"
+ v-model="projectKey"
+ name="service[project_key]"
+ data-qa-selector="service_jira_project_key_field"
+ :placeholder="$options.i18n.projectKeyPlaceholder"
+ :required="enableJiraIssues"
+ :state="validProjectKey"
+ :readonly="isInheriting"
+ />
+ </gl-form-group>
+
<jira-issue-creation-vulnerabilities
:project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-issue-type-id="initialVulnerabilitiesIssuetype"
:show-full-feature="showJiraVulnerabilitiesIntegration"
+ class="gl-mt-6"
data-testid="jira-for-vulnerabilities"
@request-jira-issue-types="$emit('request-jira-issue-types')"
/>
@@ -128,43 +135,14 @@ export default {
show-ultimate-message
:upgrade-plan-path="upgradePlanPath"
/>
- </template>
+ </div>
</template>
+
<jira-upgrade-cta
v-else
- class="gl-mt-2"
data-testid="premium-upgrade-cta"
show-premium-message
:upgrade-plan-path="upgradePlanPath"
/>
-
- <template v-if="showJiraIssuesIntegration">
- <gl-form-group
- :label="$options.i18n.projectKeyLabel"
- label-for="service_project_key"
- :invalid-feedback="$options.i18n.requiredFieldFeedback"
- :state="validProjectKey"
- data-testid="project-key-form-group"
- >
- <gl-form-input
- id="service_project_key"
- v-model="projectKey"
- name="service[project_key]"
- data-qa-selector="service_jira_project_key_field"
- :placeholder="$options.i18n.projectKeyPlaceholder"
- :required="enableJiraIssues"
- :state="validProjectKey"
- :disabled="!enableJiraIssues"
- :readonly="isInheriting"
- />
- </gl-form-group>
- <p v-if="gitlabIssuesEnabled" data-testid="conflict-warning-text">
- <gl-sprintf :message="$options.i18n.issueTrackerConflictWarning">
- <template #link="{ content }">
- <gl-link :href="editProjectPath" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </template>
</div>
</template>
diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js
index 4860b288b0f..9a9aae36657 100644
--- a/app/assets/javascripts/integrations/edit/index.js
+++ b/app/assets/javascripts/integrations/edit/index.js
@@ -22,7 +22,6 @@ function parseDatasetToProps(data) {
commentDetail,
projectKey,
upgradePlanPath,
- editProjectPath,
learnMorePath,
triggerEvents,
sections,
@@ -52,7 +51,6 @@ function parseDatasetToProps(data) {
showJiraVulnerabilitiesIntegration,
enableJiraIssues,
enableJiraVulnerabilities,
- gitlabIssuesEnabled,
} = parseBooleanInData(booleanAttributes);
return {
@@ -81,9 +79,7 @@ function parseDatasetToProps(data) {
initialEnableJiraVulnerabilities: enableJiraVulnerabilities,
initialVulnerabilitiesIssuetype: vulnerabilitiesIssuetype,
initialProjectKey: projectKey,
- gitlabIssuesEnabled,
upgradePlanPath,
- editProjectPath,
},
learnMorePath,
triggerEvents: JSON.parse(triggerEvents),
diff --git a/app/assets/javascripts/issues/manual_ordering.js b/app/assets/javascripts/issues/manual_ordering.js
index 8fb891f62f7..bc1cffef943 100644
--- a/app/assets/javascripts/issues/manual_ordering.js
+++ b/app/assets/javascripts/issues/manual_ordering.js
@@ -1,11 +1,8 @@
import Sortable from 'sortablejs';
-import {
- getBoardSortableDefaultOptions,
- sortableStart,
-} from '~/boards/mixins/sortable_default_options';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
+import { getSortableDefaultOptions, sortableStart } from '~/sortable/utils';
const updateIssue = (url, { move_before_id, move_after_id }) =>
axios
@@ -28,7 +25,7 @@ const initManualOrdering = () => {
Sortable.create(
issueList,
- getBoardSortableDefaultOptions({
+ getSortableDefaultOptions({
scroll: true,
fallbackTolerance: 1,
dataIdAttr: 'data-id',
diff --git a/app/assets/javascripts/related_issues/components/related_issues_list.vue b/app/assets/javascripts/related_issues/components/related_issues_list.vue
index 174049b15fe..9ed895e90fb 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_list.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_list.vue
@@ -1,8 +1,8 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import Sortable from 'sortablejs';
-import sortableConfig from '~/sortable/sortable_config';
import RelatedIssuableItem from '~/issuable/components/related_issuable_item.vue';
+import { defaultSortableOptions } from '~/sortable/constants';
export default {
name: 'RelatedIssuesList',
@@ -53,7 +53,7 @@ export default {
mounted() {
if (this.canReorder) {
this.sortable = Sortable.create(this.$refs.list, {
- ...sortableConfig,
+ ...defaultSortableOptions,
onStart: this.addDraggingCursor,
onEnd: this.reordered,
});
diff --git a/app/assets/javascripts/sortable/constants.js b/app/assets/javascripts/sortable/constants.js
new file mode 100644
index 00000000000..7fddac00ab2
--- /dev/null
+++ b/app/assets/javascripts/sortable/constants.js
@@ -0,0 +1,19 @@
+/**
+ * Default config options for sortablejs.
+ * @type {object}
+ *
+ * @example
+ * import Sortable from 'sortablejs';
+ *
+ * const sortable = Sortable.create(el, {
+ * ...defaultSortableOptions,
+ * });
+ */
+export const defaultSortableOptions = {
+ animation: 200,
+ forceFallback: true,
+ fallbackClass: 'is-dragging',
+ fallbackOnBody: true,
+ ghostClass: 'is-ghost',
+ fallbackTolerance: 1,
+};
diff --git a/app/assets/javascripts/sortable/sortable_config.js b/app/assets/javascripts/sortable/sortable_config.js
deleted file mode 100644
index a4c4cb7f101..00000000000
--- a/app/assets/javascripts/sortable/sortable_config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default {
- animation: 200,
- forceFallback: true,
- fallbackClass: 'is-dragging',
- fallbackOnBody: true,
- ghostClass: 'is-ghost',
- fallbackTolerance: 1,
-};
diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/sortable/utils.js
index 1bb0ee5b7e3..c2c8fb03b58 100644
--- a/app/assets/javascripts/boards/mixins/sortable_default_options.js
+++ b/app/assets/javascripts/sortable/utils.js
@@ -1,6 +1,6 @@
/* global DocumentTouch */
-import sortableConfig from '~/sortable/sortable_config';
+import { defaultSortableOptions } from './constants';
export function sortableStart() {
document.body.classList.add('is-dragging');
@@ -10,12 +10,12 @@ export function sortableEnd() {
document.body.classList.remove('is-dragging');
}
-export function getBoardSortableDefaultOptions(obj) {
+export function getSortableDefaultOptions(options) {
const touchEnabled =
'ontouchstart' in window || (window.DocumentTouch && document instanceof DocumentTouch);
const defaultSortOptions = {
- ...sortableConfig,
+ ...defaultSortableOptions,
filter: '.no-drag',
delay: touchEnabled ? 100 : 0,
scrollSensitivity: touchEnabled ? 60 : 100,
@@ -24,8 +24,8 @@ export function getBoardSortableDefaultOptions(obj) {
onEnd: sortableEnd,
};
- Object.keys(obj).forEach((key) => {
- defaultSortOptions[key] = obj[key];
- });
- return defaultSortOptions;
+ return {
+ ...defaultSortOptions,
+ ...options,
+ };
}
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index e1020ce656b..179ac2fc57f 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -376,6 +376,7 @@ export default {
<div
v-if="referencedCommands && previewMarkdown && !markdownPreviewLoading"
class="referenced-commands"
+ data-testid="referenced-commands"
v-html="referencedCommands /* eslint-disable-line vue/no-v-html */"
></div>
<div v-if="shouldShowReferencedUsers" class="referenced-users">
diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss
index 27ddff181c5..598ef70297c 100644
--- a/app/assets/stylesheets/bootstrap_migration.scss
+++ b/app/assets/stylesheets/bootstrap_migration.scss
@@ -1,318 +1,6 @@
-$text-color: $gl-text-color;
-
-$brand-primary: $blue-500;
-$brand-success: $green-500;
-$brand-info: $blue-500;
-$brand-warning: $orange-500;
-$brand-danger: $red-500;
-
-$border-radius-base: $gl-border-radius-base;
-
-$modal-body-bg: $white;
-$input-border: $border-color;
-
-$padding-base-vertical: $gl-vert-padding;
-$padding-base-horizontal: $gl-padding;
-
-/*
- * Scss to help with bootstrap 3 to 4 migration
- */
-body,
-.form-control,
-.search form {
- // Override default font size used in non-csslab UI
- // Use rem to keep default font-size at 14px on body so 1rem still
- // fits 8px grid, but also allow users to change browser font size
- font-size: 0.875rem;
-}
-
-legend {
- border-bottom: 1px solid $border-color;
- margin-bottom: 20px;
-}
-
-button,
-html [type='button'],
-[type='reset'],
-[type='submit'],
-[role='button'] {
- // Override bootstrap reboot
- /* stylelint-disable-next-line property-no-vendor-prefix */
- -webkit-appearance: inherit;
- cursor: pointer;
-}
-
-h1,
-.h1,
-h2,
-.h2,
-h3,
-.h3 {
- margin-top: 20px;
- margin-bottom: 10px;
-}
-
-h4,
-.h4,
-h5,
-.h5,
-h6,
-.h6 {
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
-/* Our adjustments to hx & .hx above add unnecessary margins to modal-title
- and page-title in modals, so we set them to 0 in order to have properly
- formatted modal headers. */
-.modal-header {
- .modal-title,
- .page-title {
- margin-top: 0;
- margin-bottom: 0;
- }
-}
-
-h5,
-.h5 {
- font-size: $gl-font-size;
-}
-
-input[type='file'] {
- // Bootstrap 4 file input height is taller by default
- // which makes them look ugly
- line-height: 1;
-}
-
-b,
-strong {
- font-weight: bold;
-}
-
-a {
- color: $blue-600;
-}
-
-hr {
- overflow: hidden;
-}
-
-.form-group.row .col-form-label {
- // Bootstrap 4 aligns labels to the left
- // for horizontal forms
- @include media-breakpoint-up(md) {
- text-align: right;
- }
-}
-
-code {
- padding: 2px 4px;
- color: $code-color;
- background-color: $gray-50;
- border-radius: $border-radius-default;
-
- .code > &,
- .build-log & {
- background-color: inherit;
- padding: unset;
- }
-}
-
-table {
- // Remove any table border lines
- border-spacing: 0;
-}
-
-@each $breakpoint in map-keys($grid-breakpoints) {
- @include media-breakpoint-up($breakpoint) {
- $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
-
- .d#{$infix}-table-header-group {
- display: table-header-group !important;
- }
- }
-}
-
-.text-secondary {
- // Override Bootstrap's light secondary color
- // We have to use !important because bootstrap has that set as well
- color: $gl-text-color-secondary !important;
-}
-
-.bg-success,
-.bg-primary,
-.bg-info,
-.bg-danger,
-.bg-warning {
- .card-header {
- color: $white;
- }
-}
-
-// Polyfill deprecated selectors
-
-.hidden {
- display: none !important;
- visibility: hidden !important;
-}
-
-.hide {
- display: none;
-}
-
-.dropdown-toggle::after,
-.dropright .dropdown-menu-toggle::after {
- // Remove bootstrap's dropdown caret
- display: none;
-}
-
-// Add to .label so that old system notes that are saved to the db
-// will still receive the correct styling
-.badge:not(.gl-badge),
-.label {
- padding: 4px 5px;
- font-size: 12px;
- font-style: normal;
- font-weight: $gl-font-weight-normal;
- display: inline-block;
-
- &.badge-gray {
- background-color: $label-gray-bg;
- color: $gl-text-color;
- text-shadow: none;
- }
-
- &.badge-inverse {
- background-color: $label-inverse-bg;
- }
-}
-
-.divider {
- // copied rules from node_modules/bootstrap/scss/_dropdown.scss:116
- // this might be safe to just remove instead
- // most places that use divider add overrides to undo these things
- // there is also a probably-unintentional use in deprecated_dropdown_divider.scss
- // so we would end up with .gl-dropdown .dropdown-divider
- height: 0;
- margin: 4px 0;
- overflow: hidden;
- border-top: 1px solid $border-color;
-}
-
-.info-well {
- background: $gray-10;
- color: $gl-text-color;
- border: 1px solid $border-color;
- border-radius: 4px;
- margin-bottom: 16px;
-
- .well-segment {
- padding: 16px;
-
- &:not(:last-of-type) {
- border-bottom: 1px solid $well-inner-border;
- }
-
- p,
- ol,
- ul,
- .form-group {
- &:last-of-type {
- margin-bottom: 0;
- }
- }
- }
-
- .badge.badge-gray {
- background-color: $well-expand-item;
- }
-}
-
-.card {
- &.card-without-border,
- &.bg-light {
- border: 0 !important;
- }
-}
-
-.nav-tabs {
- // Override bootstrap's default border
- border-bottom: 0;
-
- .nav-link {
- border-top: 0;
- border-left: 0;
- border-right: 0;
- }
-
- .nav-item {
- margin-bottom: 0;
- }
-}
-
-pre code {
- white-space: pre-wrap;
-}
-
-.alert {
- border-radius: 0;
-}
-
-.alert-success {
- background-color: $green-500;
- border-color: $green-500;
-}
-
-.alert-info {
- background-color: $blue-500;
- border-color: $blue-500;
-}
-
-.alert-warning {
- background-color: $orange-500;
- border-color: $orange-500;
-}
-
-.alert-danger {
- background-color: $red-500;
- border-color: $red-500;
-}
-
-.alert-success,
-.alert-info,
-.alert-warning,
-.alert-danger {
- color: $white;
-
- h4,
- .alert-link {
- color: $white;
- }
-}
-
-input[type=color].form-control {
- height: $input-height;
-}
-
-.toggle-sidebar-button {
- .collapse-text,
- .icon-chevron-double-lg-left,
- .icon-chevron-double-lg-right {
- color: $gl-text-color-secondary;
- }
-}
-
-.project-templates-buttons {
- .btn {
- vertical-align: unset;
- }
-}
-
-/*
- Bootstrap 4.1.2 introduced a new default vertical alignment which breaks our icons,
- so we need to reset the vertical alignment to the default value. See:
- - https://gitlab.com/gitlab-org/gitlab-foss/issues/51362
- */
-svg {
- vertical-align: baseline;
-}
+// ---
+// Scss to help with bootstrap 3 to 4 migration
+// ---
+@import 'bootstrap_migration_variables';
+@import 'bootstrap_migration_reset';
+@import 'bootstrap_migration_components';
diff --git a/app/assets/stylesheets/bootstrap_migration_components.scss b/app/assets/stylesheets/bootstrap_migration_components.scss
new file mode 100644
index 00000000000..b6cecbe5806
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap_migration_components.scss
@@ -0,0 +1,216 @@
+// ---
+// Scss to help with bootstrap 3 to 4 migration of bootstrap components
+// ---
+.form-control,
+.search form {
+ // Override default font size used in non-csslab UI
+ // Use rem to keep default font-size at 14px on body so 1rem still
+ // fits 8px grid, but also allow users to change browser font size
+ font-size: 0.875rem;
+}
+
+/* Our adjustments to hx & .hx above add unnecessary margins to modal-title
+ and page-title in modals, so we set them to 0 in order to have properly
+ formatted modal headers. */
+.modal-header {
+ .modal-title,
+ .page-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+}
+
+input[type='file'] {
+ // Bootstrap 4 file input height is taller by default
+ // which makes them look ugly
+ line-height: 1;
+}
+
+.form-group.row .col-form-label {
+ // Bootstrap 4 aligns labels to the left
+ // for horizontal forms
+ @include media-breakpoint-up(md) {
+ text-align: right;
+ }
+}
+
+@each $breakpoint in map-keys($grid-breakpoints) {
+ @include media-breakpoint-up($breakpoint) {
+ $infix: breakpoint-infix($breakpoint, $grid-breakpoints);
+
+ .d#{$infix}-table-header-group {
+ display: table-header-group !important;
+ }
+ }
+}
+
+.text-secondary {
+ // Override Bootstrap's light secondary color
+ // We have to use !important because bootstrap has that set as well
+ color: $gl-text-color-secondary !important;
+}
+
+.bg-success,
+.bg-primary,
+.bg-info,
+.bg-danger,
+.bg-warning {
+ .card-header {
+ color: $white;
+ }
+}
+
+// Polyfill deprecated selectors
+
+.hidden {
+ display: none !important;
+ visibility: hidden !important;
+}
+
+.hide {
+ display: none;
+}
+
+.dropdown-toggle::after,
+.dropright .dropdown-menu-toggle::after {
+ // Remove bootstrap's dropdown caret
+ display: none;
+}
+
+// Add to .label so that old system notes that are saved to the db
+// will still receive the correct styling
+.badge:not(.gl-badge),
+.label {
+ padding: 4px 5px;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: $gl-font-weight-normal;
+ display: inline-block;
+
+ &.badge-gray {
+ background-color: $label-gray-bg;
+ color: $gl-text-color;
+ text-shadow: none;
+ }
+
+ &.badge-inverse {
+ background-color: $label-inverse-bg;
+ }
+}
+
+.divider {
+ // copied rules from node_modules/bootstrap/scss/_dropdown.scss:116
+ // this might be safe to just remove instead
+ // most places that use divider add overrides to undo these things
+ // there is also a probably-unintentional use in deprecated_dropdown_divider.scss
+ // so we would end up with .gl-dropdown .dropdown-divider
+ height: 0;
+ margin: 4px 0;
+ overflow: hidden;
+ border-top: 1px solid $border-color;
+}
+
+.info-well {
+ background: $gray-10;
+ color: $gl-text-color;
+ border: 1px solid $border-color;
+ border-radius: 4px;
+ margin-bottom: 16px;
+
+ .well-segment {
+ padding: 16px;
+
+ &:not(:last-of-type) {
+ border-bottom: 1px solid $well-inner-border;
+ }
+
+ p,
+ ol,
+ ul,
+ .form-group {
+ &:last-of-type {
+ margin-bottom: 0;
+ }
+ }
+ }
+
+ .badge.badge-gray {
+ background-color: $well-expand-item;
+ }
+}
+
+.card {
+ &.card-without-border,
+ &.bg-light {
+ border: 0 !important;
+ }
+}
+
+.nav-tabs {
+ // Override bootstrap's default border
+ border-bottom: 0;
+
+ .nav-link {
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ }
+
+ .nav-item {
+ margin-bottom: 0;
+ }
+}
+
+.alert {
+ border-radius: 0;
+}
+
+.alert-success {
+ background-color: $green-500;
+ border-color: $green-500;
+}
+
+.alert-info {
+ background-color: $blue-500;
+ border-color: $blue-500;
+}
+
+.alert-warning {
+ background-color: $orange-500;
+ border-color: $orange-500;
+}
+
+.alert-danger {
+ background-color: $red-500;
+ border-color: $red-500;
+}
+
+.alert-success,
+.alert-info,
+.alert-warning,
+.alert-danger {
+ color: $white;
+
+ h4,
+ .alert-link {
+ color: $white;
+ }
+}
+
+input[type=color].form-control {
+ height: $input-height;
+}
+
+.toggle-sidebar-button {
+ .collapse-text,
+ .icon-chevron-double-lg-left,
+ .icon-chevron-double-lg-right {
+ color: $gl-text-color-secondary;
+ }
+}
+
+.project-templates-buttons {
+ .btn {
+ vertical-align: unset;
+ }
+}
diff --git a/app/assets/stylesheets/bootstrap_migration_reset.scss b/app/assets/stylesheets/bootstrap_migration_reset.scss
new file mode 100644
index 00000000000..ad315c4ada1
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap_migration_reset.scss
@@ -0,0 +1,94 @@
+// ---
+// Scss to help with bootstrap 3 to 4 migration of core elements
+// ---
+body {
+ // Override default font size used in non-csslab UI
+ // Use rem to keep default font-size at 14px on body so 1rem still
+ // fits 8px grid, but also allow users to change browser font size
+ font-size: 0.875rem;
+}
+
+legend {
+ border-bottom: 1px solid $border-color;
+ margin-bottom: 20px;
+}
+
+button,
+html [type='button'],
+[type='reset'],
+[type='submit'],
+[role='button'] {
+ // Override bootstrap reboot
+ /* stylelint-disable-next-line property-no-vendor-prefix */
+ -webkit-appearance: inherit;
+ cursor: pointer;
+}
+
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+h5,
+.h5 {
+ font-size: $gl-font-size;
+}
+
+b,
+strong {
+ font-weight: bold;
+}
+
+a {
+ color: $blue-600;
+}
+
+hr {
+ overflow: hidden;
+}
+
+code {
+ padding: 2px 4px;
+ color: $code-color;
+ background-color: $gray-50;
+ border-radius: $border-radius-default;
+
+ .code > &,
+ .build-log & {
+ background-color: inherit;
+ padding: unset;
+ }
+}
+
+table {
+ // Remove any table border lines
+ border-spacing: 0;
+}
+
+pre code {
+ white-space: pre-wrap;
+}
+
+/*
+ Bootstrap 4.1.2 introduced a new default vertical alignment which breaks our icons,
+ so we need to reset the vertical alignment to the default value. See:
+ - https://gitlab.com/gitlab-org/gitlab-foss/issues/51362
+ */
+svg {
+ vertical-align: baseline;
+}
diff --git a/app/assets/stylesheets/bootstrap_migration_variables.scss b/app/assets/stylesheets/bootstrap_migration_variables.scss
new file mode 100644
index 00000000000..f3888de4ed8
--- /dev/null
+++ b/app/assets/stylesheets/bootstrap_migration_variables.scss
@@ -0,0 +1,15 @@
+$text-color: $gl-text-color;
+
+$brand-primary: $blue-500;
+$brand-success: $green-500;
+$brand-info: $blue-500;
+$brand-warning: $orange-500;
+$brand-danger: $red-500;
+
+$border-radius-base: $gl-border-radius-base;
+
+$modal-body-bg: $white;
+$input-border: $border-color;
+
+$padding-base-vertical: $gl-vert-padding;
+$padding-base-horizontal: $gl-padding;
diff --git a/app/assets/stylesheets/notify_base.scss b/app/assets/stylesheets/notify_base.scss
index 8c6f9a27077..0ca1398c609 100644
--- a/app/assets/stylesheets/notify_base.scss
+++ b/app/assets/stylesheets/notify_base.scss
@@ -1,5 +1,6 @@
-@import 'framework/mixins';
@import 'framework/variables';
+@import 'framework/variables_overrides';
+@import 'framework/mixins';
img {
max-width: 100%;
diff --git a/app/assets/stylesheets/notify_enhanced.scss b/app/assets/stylesheets/notify_enhanced.scss
index 5aa0fd3cd00..a366498ea03 100644
--- a/app/assets/stylesheets/notify_enhanced.scss
+++ b/app/assets/stylesheets/notify_enhanced.scss
@@ -2,20 +2,30 @@
// keep parts that affect elements that can appear in emails;
// omit Bootstrap Reboot since it adds unnecessary styles to every element.
@import 'notify_base';
+
+// bootstrap variables, mixins, functions
@import 'bootstrap/scss/functions';
@import 'bootstrap/scss/variables';
@import 'bootstrap/scss/mixins';
+
+// bootstrap styles
@import 'bootstrap/scss/code';
+
+// @gitlab/ui variables, mixins, functions
@import '@gitlab/ui/src/scss/variables';
@import '@gitlab/ui/src/scss/utility-mixins/index';
-@import '@gitlab/ui/src/scss/components';
-@import 'bootstrap_migration';
-@import 'framework/common';
+
+// @gitlab/ui styles
+@import '@gitlab/ui/src/components/base/icon/icon';
+@import '@gitlab/ui/src/components/base/label/label';
+
+// gitlab styles
+@import 'bootstrap_migration_variables';
+@import 'bootstrap_migration_reset';
@import 'framework/gfm';
@import 'framework/kbd';
@import 'framework/tables';
@import 'framework/typography';
-@import 'framework/emojis';
body {
font-family: $regular-font;
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index 1b76f41a7be..a3b21caa69d 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -543,9 +543,7 @@ a.gl-badge.badge-warning:active {
padding-right: 2rem;
padding-left: 1.75rem;
}
-body,
-.form-control,
-.search form {
+body {
font-size: 0.875rem;
}
button,
@@ -563,6 +561,13 @@ strong {
a {
color: #63a6e9;
}
+svg {
+ vertical-align: baseline;
+}
+.form-control,
+.search form {
+ font-size: 0.875rem;
+}
.hidden {
display: none !important;
visibility: hidden !important;
@@ -587,9 +592,6 @@ a {
.toggle-sidebar-button .icon-chevron-double-lg-left {
color: #999;
}
-svg {
- vertical-align: baseline;
-}
html {
overflow-y: scroll;
}
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index 6d66e207bdc..c0a7dbc5deb 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -529,9 +529,7 @@ a.gl-badge.badge-warning:active {
padding-right: 2rem;
padding-left: 1.75rem;
}
-body,
-.form-control,
-.search form {
+body {
font-size: 0.875rem;
}
button,
@@ -549,6 +547,13 @@ strong {
a {
color: #1068bf;
}
+svg {
+ vertical-align: baseline;
+}
+.form-control,
+.search form {
+ font-size: 0.875rem;
+}
.hidden {
display: none !important;
visibility: hidden !important;
@@ -573,9 +578,6 @@ a {
.toggle-sidebar-button .icon-chevron-double-lg-left {
color: #666;
}
-svg {
- vertical-align: baseline;
-}
html {
overflow-y: scroll;
}
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 213d1c013a0..00913fa1fdc 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -369,8 +369,7 @@ fieldset:disabled a.btn {
outline: none;
background-color: #0b5cad;
}
-body,
-.form-control {
+body {
font-size: 0.875rem;
}
[type="submit"] {
@@ -387,6 +386,12 @@ a {
hr {
overflow: hidden;
}
+svg {
+ vertical-align: baseline;
+}
+.form-control {
+ font-size: 0.875rem;
+}
.hidden {
display: none !important;
visibility: hidden !important;
@@ -394,9 +399,6 @@ hr {
.hide {
display: none;
}
-svg {
- vertical-align: baseline;
-}
html {
overflow-y: scroll;
}
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index ec1f8ca5f00..98eca3785e7 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -233,7 +233,7 @@ module IssuablesHelper
canUpdate: can?(current_user, :"update_#{issuable.to_ability_name}", issuable),
canDestroy: can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable),
issuableRef: issuable.to_reference,
- markdownPreviewPath: preview_markdown_path(parent),
+ markdownPreviewPath: preview_markdown_path(parent, target_type: issuable.model_name, target_id: issuable.iid),
markdownDocsPath: help_page_path('user/markdown'),
lockVersion: issuable.lock_version,
issuableTemplateNamesPath: template_names_path(parent, issuable),
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index 74ece57000f..b20efa55529 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -143,7 +143,7 @@ module Integrations
end
def help
- jira_doc_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('integration/jira/index.html') }
+ jira_doc_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('integration/jira/index') }
s_("JiraService|You must configure Jira before enabling this integration. %{jira_doc_link_start}Learn more.%{link_end}") % { jira_doc_link_start: jira_doc_link_start, link_end: '</a>'.html_safe }
end
@@ -160,8 +160,6 @@ module Integrations
end
def sections
- jira_issues_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('integration/jira/issues.html') }
-
sections = [
{
type: SECTION_TYPE_CONNECTION,
@@ -180,7 +178,7 @@ module Integrations
sections.push({
type: SECTION_TYPE_JIRA_ISSUES,
title: _('Issues'),
- description: s_('JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues. %{jira_issues_link_start}Learn more.%{link_end}') % { jira_issues_link_start: jira_issues_link_start, link_end: '</a>'.html_safe }
+ description: jira_issues_section_description
})
end
@@ -610,6 +608,19 @@ module Integrations
data_fields.deployment_server!
end
end
+
+ def jira_issues_section_description
+ jira_issues_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('integration/jira/issues') }
+ description = s_('JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues. %{jira_issues_link_start}Learn more.%{link_end}') % { jira_issues_link_start: jira_issues_link_start, link_end: '</a>'.html_safe }
+
+ if project&.issues_enabled?
+ gitlab_issues_link_start = '<a href="%{url}">'.html_safe % { url: edit_project_path(project, anchor: 'js-shared-permissions') }
+ description += '<br><br>'.html_safe
+ description += s_("JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{gitlab_issues_link_start}disabling GitLab issues%{link_end} if they won't otherwise be used.") % { gitlab_issues_link_start: gitlab_issues_link_start, link_end: '</a>'.html_safe }
+ end
+
+ description
+ end
end
end
diff --git a/app/services/bulk_imports/relation_export_service.rb b/app/services/bulk_imports/relation_export_service.rb
index 14f073120c5..c43f0d8cb4f 100644
--- a/app/services/bulk_imports/relation_export_service.rb
+++ b/app/services/bulk_imports/relation_export_service.rb
@@ -4,6 +4,8 @@ module BulkImports
class RelationExportService
include Gitlab::ImportExport::CommandLineUtil
+ EXISTING_EXPORT_TTL = 3.minutes
+
def initialize(user, portable, relation, jid)
@user = user
@portable = portable
@@ -31,6 +33,9 @@ module BulkImports
validate_user_permissions!
export = portable.bulk_import_exports.safe_find_or_create_by!(relation: relation)
+
+ return export if export.finished? && export.updated_at > EXISTING_EXPORT_TTL.ago
+
export.update!(status_event: 'start', jid: jid)
yield export
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 17dccae44b5..2ea5890be2c 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -5,9 +5,8 @@
= form_tag admin_groups_path, method: :get, class: 'js-search-form' do |f|
= hidden_field_tag :sort, @sort
.search-holder
- - project_name = params[:name].present? ? params[:name] : nil
.search-field-holder
- = search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' }
+ = search_field_tag :name, params[:name].presence, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' }
= sprite_icon('search', css_class: 'search-icon')
= render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
= link_to new_admin_group_path, class: "gl-button btn btn-confirm" do
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 9ae7acab925..d1d9a220068 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -11,7 +11,7 @@
.gl-alert-body
= s_('ExternalIssueIntegration|Only one issue tracker integration can be active at a time. Please disable the active tracker first and try again.')
-%h3.page-title
+%h2.gl-mb-4
= integration.title
- if integration.operating?
= sprite_icon('check', css_class: 'gl-text-green-500')
diff --git a/app/views/shared/integrations/edit.html.haml b/app/views/shared/integrations/edit.html.haml
index f2a31400698..0ae0eea59d8 100644
--- a/app/views/shared/integrations/edit.html.haml
+++ b/app/views/shared/integrations/edit.html.haml
@@ -3,7 +3,7 @@
- page_title @integration.title, _('Integrations')
- @content_class = 'limit-container-width' unless fluid_layout
-%h3.page-title
+%h2.gl-mb-4
= @integration.title
= render 'shared/integrations/tabs', integration: @integration, active_tab: 'edit' do
diff --git a/app/workers/bulk_imports/relation_export_worker.rb b/app/workers/bulk_imports/relation_export_worker.rb
index 9324b79cc75..dcac841b3b2 100644
--- a/app/workers/bulk_imports/relation_export_worker.rb
+++ b/app/workers/bulk_imports/relation_export_worker.rb
@@ -3,12 +3,12 @@
module BulkImports
class RelationExportWorker
include ApplicationWorker
-
- data_consistency :always
include ExceptionBacktrace
idempotent!
+ deduplicate :until_executed
loggable_arguments 2, 3
+ data_consistency :always
feature_category :importers
sidekiq_options status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
diff --git a/data/deprecations/14-10-manual-iteration-management.yml b/data/deprecations/14-10-manual-iteration-management.yml
new file mode 100644
index 00000000000..f677f4fe668
--- /dev/null
+++ b/data/deprecations/14-10-manual-iteration-management.yml
@@ -0,0 +1,34 @@
+- name: "Manual iteration management" # The name of the feature to be deprecated
+ announcement_milestone: "14.10" # The milestone when this feature was first announced as deprecated.
+ announcement_date: "2022-04-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_milestone: "16.0" # The milestone when this feature is planned to be removed
+ removal_date: "2023-04-22" # The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ breaking_change: true # If this deprecation is a breaking change, set this value to true
+ reporter: mcelicalderonG # GitLab username of the person reporting the deprecation
+ body: | # Do not modify this line, instead modify the lines below.
+ Manual iteration management is deprecated and only automatic iteration cadences will be supported in the future.
+
+ Creating and deleting iterations will be fully removed in 16.0. Updating all iteration fields except for
+ `description` will also be removed.
+
+ On the GraphQL API the following mutations will be removed:
+
+ 1. `iterationCreate`
+ 1. `iterationDelete`
+
+ The update `updateIteration` mutation will only allow updating the iteration's `description`. The following
+ arguments will be removed:
+
+ 1. `title`
+ 1. `dueDate`
+ 1. `startDate`
+
+ For more information about iteration cadences, you can refer to
+ [the documentation of the feature](https://docs.gitlab.com/ee/user/group/iterations/#iteration-cadences).
+# The following items are not published on the docs page, but may be used in the future.
+ stage: Plan
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356069
+ documentation_url: # (optional) This is a link to the current documentation page
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/doc/administration/package_information/postgresql_versions.md b/doc/administration/package_information/postgresql_versions.md
index e707cb70187..c80437221c4 100644
--- a/doc/administration/package_information/postgresql_versions.md
+++ b/doc/administration/package_information/postgresql_versions.md
@@ -26,8 +26,8 @@ Read more about update policies and warnings in the PostgreSQL
| GitLab version | PostgreSQL versions | Default version for fresh installs | Default version for upgrades | Notes |
| -------------- | --------------------- | ---------------------------------- | ---------------------------- | ----- |
-| 14.1 | 12.6, 13.3 | 12.6 | 12.6 | PostgreSQL 13 available for fresh installations if not using [Geo](../geo/index.md#requirements-for-running-geo) or [Patroni](../postgresql/index.md#postgresql-replication-and-failover-with-omnibus-gitlab).
-| 14.0 | 12.6 | 12.6 | 12.6 | HA installations with repmgr are no longer supported and will be prevented from upgrading to Omnibus GitLab 14.0 |
+| 14.1 | 12.7, 13.3 | 12.7 | 12.7 | PostgreSQL 13 available for fresh installations if not using [Geo](../geo/index.md#requirements-for-running-geo) or [Patroni](../postgresql/index.md#postgresql-replication-and-failover-with-omnibus-gitlab).
+| 14.0 | 12.7 | 12.7 | 12.7 | HA installations with repmgr are no longer supported and will be prevented from upgrading to Omnibus GitLab 14.0 |
| 13.8 | 11.9, 12.4 | 12.4 | 12.4 | Package upgrades automatically performed PostgreSQL upgrade for nodes that are not part of a Geo or HA cluster.). |
| 13.7 | 11.9, 12.4 | 12.4 | 11.9 | For upgrades users can manually upgrade to 12.4 following the [upgrade docs](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-133-and-later). |
| 13.4 | 11.9, 12.4 | 11.9 | 11.9 | Package upgrades aborted if users not running PostgreSQL 11 already |
diff --git a/doc/administration/package_information/supported_os.md b/doc/administration/package_information/supported_os.md
index cda5f5a5928..16038b9ebf5 100644
--- a/doc/administration/package_information/supported_os.md
+++ b/doc/administration/package_information/supported_os.md
@@ -28,10 +28,10 @@ The following lists the currently supported OSs and their possible EOL dates.
| Ubuntu 18.04 | GitLab CE / GitLab EE 10.7.0 | amd64 | April 2023 | <https://wiki.ubuntu.com/Releases> |
| Ubuntu 20.04 | GitLab CE / GitLab EE 13.2.0 | amd64, arm64 | April 2025 | <https://wiki.ubuntu.com/Releases> |
| Amazon Linux 2 | GitLab CE / GitLab EE 14.9.0 | amd64, arm64 | June 2023 | <https://aws.amazon.com/amazon-linux-2/faqs/> |
-| Raspbian Buster | GitLab CE 12.2.0 | armhf | 2022 | <https://wiki.debian.org/DebianReleases#Production_Releases> |
+| Raspberry Pi OS (Buster) (formerly known as Raspbian Buster) | GitLab CE 12.2.0 | armhf | 2024 | <https://www.raspberrypi.com/news/new-old-functionality-with-raspberry-pi-os-legacy/> |
NOTE:
-CentOS 8 will be EOL on December 31, 2021. In GitLab 14.5 and later,
+CentOS 8 was EOL on December 31, 2021. In GitLab 14.5 and later,
[CentOS builds work in AlmaLinux](https://gitlab.com/gitlab-org/distribution/team-tasks/-/issues/954#note_730198505).
We will officially support all distributions that are binary compatible with Red Hat Enterprise Linux.
This gives users a path forward for their CentOS 8 builds at its end of life.
@@ -78,7 +78,7 @@ release for them can be found below:
| Ubuntu 14.04 | [April 2019](https://ubuntu.com/info/release-end-of-life) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_11.10&dist=ubuntu%2Ftrusty) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_11.10&dist=ubuntu%2Ftrusty) 11.10 |
| OpenSUSE 42.3 | [July 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.1&dist=opensuse%2F42.3) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.1&dist=opensuse%2F42.3) 12.1 |
| OpenSUSE 15.0 | [December 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.5&dist=opensuse%2F15.0) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.5&dist=opensuse%2F15.0) 12.5 |
-| Raspbian Stretch | [June 2020](https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_13.2&dist=raspbian%2Fstretch) 13.3 |
+| Raspbian Stretch | [June 2020](https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_13.3&dist=raspbian%2Fstretch) 13.3 |
| Debian Jessie | [June 2020](https://www.debian.org/News/2020/20200709) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_13.2&dist=debian%2Fjessie) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_13.2&dist=debian%2Fjessie) 13.3 |
| CentOS 6 | [November 2020](https://wiki.centos.org/About/Product) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=13.6&filter=all&filter=all&dist=el%2F6) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=13.6&filter=all&filter=all&dist=el%2F6) 13.6 |
| OpenSUSE 15.1 | [November 2020](https://en.opensuse.org/Lifetime#Discontinued_distributions) | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-13.12&dist=opensuse%2F15.1) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-13.12&dist=opensuse%2F15.1) 13.12 |
diff --git a/doc/api/runners.md b/doc/api/runners.md
index c450efe8c3f..304f2494f70 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -448,7 +448,7 @@ Example response:
## List project's runners
-List all runners available in the project, including from ancestor groups and [any allowed shared runners](../ci/runners/runners_scope.md#enable-shared-runners).
+List all runners available in the project, including from ancestor groups and [any allowed shared runners](../ci/runners/runners_scope.md#enable-shared-runners-for-a-project).
```plaintext
GET /projects/:id/runners
@@ -566,7 +566,7 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
## List group's runners
-List all runners available in the group as well as its ancestor groups, including [any allowed shared runners](../ci/runners/runners_scope.md#enable-shared-runners).
+List all runners available in the group as well as its ancestor groups, including [any allowed shared runners](../ci/runners/runners_scope.md#enable-shared-runners-for-a-group).
```plaintext
GET /groups/:id/runners
diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index fb5395076b0..6082a17d001 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -37,22 +37,31 @@ If you are using GitLab.com:
- The shared runners consume the [CI/CD minutes](../pipelines/cicd_minutes.md)
included with your account.
-### Enable shared runners
+### Enable shared runners for a project
On GitLab.com, [shared runners](index.md) are enabled in all projects by
default.
-On self-managed instances of GitLab, an administrator must [install](https://docs.gitlab.com/runner/install/index.html)
-and [register](https://docs.gitlab.com/runner/register/index.html) them.
+On self-managed instances of GitLab, an administrator can
+[enable them for all new projects](../../user/admin_area/settings/continuous_integration.md#enable-shared-runners-for-new-projects).
-You can also enable shared runners for individual projects.
+For existing projects, an administrator must
+[install](https://docs.gitlab.com/runner/install/index.html) and
+[register](https://docs.gitlab.com/runner/register/index.html) them.
-To enable shared runners:
+To enable shared runners for a project:
1. Go to the project's **Settings > CI/CD** and expand the **Runners** section.
1. Select **Enable shared runners for this project**.
-### Disable shared runners
+### Enable shared runners for a group
+
+To enable shared runners for a group:
+
+1. Go to the group's **Settings > CI/CD** and expand the **Runners** section.
+1. Select **Enable shared runners for this group**.
+
+### Disable shared runners for a project
You can disable shared runners for individual projects or for groups.
You must have the Owner role for the project
@@ -68,6 +77,8 @@ Shared runners are automatically disabled for a project:
- If the shared runners setting for the parent group is disabled, and
- If overriding this setting is not permitted at the project level.
+### Disable shared runners for a group
+
To disable shared runners for a group:
1. Go to the group's **Settings > CI/CD** and expand the **Runners** section.
@@ -78,7 +89,7 @@ To disable shared runners for a group:
NOTE:
To re-enable the shared runners for a group, turn on the
**Enable shared runners for this group** toggle.
-Then, an owner or maintainer must explicitly change this setting
+Then, a user with the Owner or Maintainer role must explicitly change this setting
for each project subgroup or project.
### How shared runners pick jobs
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index 1e4698ff867..fb58851e93f 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -19,8 +19,29 @@ must be documented. For context, see the
When you document feature flags, you must:
-- [Add a note at the start of the topic](#use-a-note-to-describe-the-state-of-the-feature-flag).
- [Add version history text](#add-version-history-text).
+- [Add a note at the start of the topic](#use-a-note-to-describe-the-state-of-the-feature-flag).
+
+## Add version history text
+
+When the state of a flag changes (for example, disabled by default to enabled by default), add the change to the version history.
+
+Possible version history entries are:
+
+```markdown
+> - [Introduced](issue-link) in GitLab X.X [with a flag](../../administration/feature_flags.md) named <flag name>. Disabled by default.
+> - [Enabled on GitLab.com](issue-link) in GitLab X.X.
+> - [Enabled on GitLab.com](issue-link) in GitLab X.X. Available to GitLab.com administrators only.
+> - [Enabled on self-managed](issue-link) in GitLab X.X.
+> - [Generally available](issue-link) in GitLab X.Y. [Feature flag <flag name>](issue-link) removed.
+```
+
+You can combine entries if they happened in the same release:
+
+```markdown
+> - Introduced in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ci_include_rules`. Disabled by default.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/337507) in GitLab 14.3.
+```
## Use a note to describe the state of the feature flag
@@ -30,7 +51,8 @@ The note has three parts, and follows this structure:
```markdown
FLAG:
-<Self-managed GitLab availability information.> <GitLab.com availability information.>
+<Self-managed GitLab availability information.>
+<GitLab.com availability information.>
<This feature is not ready for production use.>
```
@@ -61,27 +83,6 @@ If needed, you can add this sentence:
`The feature is not ready for production use.`
-## Add version history text
-
-When the state of a flag changes (for example, disabled by default to enabled by default), add the change to the version history.
-
-Possible version history entries are:
-
-```markdown
-> - [Introduced](issue-link) in GitLab X.X [with a flag](../../administration/feature_flags.md) named <flag name>. Disabled by default.
-> - [Enabled on GitLab.com](issue-link) in GitLab X.X.
-> - [Enabled on GitLab.com](issue-link) in GitLab X.X. Available to GitLab.com administrators only.
-> - [Enabled on self-managed](issue-link) in GitLab X.X.
-> - [Generally available](issue-link) in GitLab X.Y. [Feature flag <flag name>](issue-link) removed.
-```
-
-You can combine entries if they happened in the same release:
-
-```markdown
-> - Introduced in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ci_include_rules`. Disabled by default.
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/337507) in GitLab 14.3.
-```
-
## Feature flag documentation examples
The following examples show the progression of a feature flag.
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
index 25e841e113b..ca4a0158051 100644
--- a/doc/development/service_ping/implement.md
+++ b/doc/development/service_ping/implement.md
@@ -760,7 +760,7 @@ To set up Service Ping locally, you must:
1. Clone and start [Versions Application](https://gitlab.com/gitlab-services/version-gitlab-com).
Make sure you run `docker-compose up` to start a PostgreSQL and Redis instance.
1. Point GitLab to the Versions Application endpoint instead of the default endpoint:
- 1. Open [service_ping/submit_service.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb#L5) in your local and modified `PRODUCTION_URL`.
+ 1. Open [service_ping/submit_service.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb#L5) locally and modify `STAGING_BASE_URL`.
1. Set it to the local Versions Application URL: `http://localhost:3000/usage_data`.
### Test local setup
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 752e05a8cd4..0bbaf677a75 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -42,6 +42,38 @@ Each deprecation has a **planned removal milestone** and indicates whether it is
Most of the deprecations are **planned for removal in 15.0**, and many of them are **breaking changes**.
+## 14.10
+
+### Manual iteration management
+
+WARNING:
+This feature will be changed or removed in 16.0
+as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
+Before updating GitLab, review the details carefully to determine if you need to make any
+changes to your code, settings, or workflow.
+
+Manual iteration management is deprecated and only automatic iteration cadences will be supported in the future.
+
+Creating and deleting iterations will be fully removed in 16.0. Updating all iteration fields except for
+`description` will also be removed.
+
+On the GraphQL API the following mutations will be removed:
+
+ 1. `iterationCreate`
+ 1. `iterationDelete`
+
+The update `updateIteration` mutation will only allow updating the iteration's `description`. The following
+arguments will be removed:
+
+ 1. `title`
+ 1. `dueDate`
+ 1. `startDate`
+
+For more information about iteration cadences, you can refer to
+[the documentation of the feature](https://docs.gitlab.com/ee/user/group/iterations/#iteration-cadences).
+
+**Planned removal milestone: 16.0 (2023-04-22)**
+
## 14.9
### Background upload for object storage
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index 0330d89aedc..7d968ff5e86 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -28,7 +28,18 @@ From now on, every existing project and newly created ones that don't have a
If you want to disable it for a specific project, you can do so in
[its settings](../../../topics/autodevops/index.md#enable-or-disable-auto-devops).
-## Shared runner details
+## Enable shared runners for new projects
+
+You can set all new projects to have the instance's shared runners available by default.
+
+1. On the top bar, select **Menu > Admin**.
+1. On the left sidebar, select **Settings > CI/CD**.
+1. Expand **Continuous Integration and Deployment**.
+1. Select the **Enable shared runners for new projects** checkbox.
+
+Any time a new project is created, the shared runners are available.
+
+## Add a message for shared runners
To display details about the instance's shared runners in all projects'
runner settings:
@@ -36,16 +47,17 @@ runner settings:
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
-1. Enter your shared runner details in the **Shared runner details** field.
+1. Enter text, including Markdown if you want, in the **Shared runner details** field. For example:
+
+ ![Shared runner details input](img/continuous_integration_shared_runner_details_input_v14_10.png)
-You can use [Markdown](../../markdown.md) for improved formatting. To see the rendered
-details:
+To view the rendered details:
1. On the top bar, select **Menu > Project** and select any group or project.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Runners**.
-![Shared runner details example](img/continuous_integration_shared_runner_details_v14_0.png)
+![Shared runner details example](img/continuous_integration_shared_runner_details_v14_10.png)
## Maximum artifacts size
diff --git a/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_input_v14_10.png b/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_input_v14_10.png
new file mode 100644
index 00000000000..08451f36962
--- /dev/null
+++ b/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_input_v14_10.png
Binary files differ
diff --git a/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_0.png b/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_0.png
deleted file mode 100644
index d8bc3deccd4..00000000000
--- a/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_10.png b/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_10.png
new file mode 100644
index 00000000000..64bd9cf6911
--- /dev/null
+++ b/doc/user/admin_area/settings/img/continuous_integration_shared_runner_details_v14_10.png
Binary files differ
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index 999d4b15cb0..8453c5cf4bd 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -45,7 +45,7 @@ From there you can create a new iteration or select an iteration to get a more d
WARNING:
Manual iteration management is in its end-of-life process. Creating an iteration is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/356069)
-for use in GitLab 14.10, and is planned for removal in GitLab 15.6.
+for use in GitLab 14.10, and is planned for removal in GitLab 16.0.
Prerequisites:
@@ -66,7 +66,7 @@ To create an iteration:
WARNING:
Editing all attributes, with the exception of `description` is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/356069)
-for use in GitLab 14.10, and is planned for removal in GitLab 15.6.
+for use in GitLab 14.10, and is planned for removal in GitLab 16.0.
In the future only editing an iteration's `description` will be allowed.
Prerequisites:
@@ -82,7 +82,7 @@ To edit an iteration, select the three-dot menu (**{ellipsis_v}**) > **Edit**.
WARNING:
Manual iteration management is in its end-of-life process. Deleting an iteration is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/356069)
-for use in GitLab 14.10, and is planned for removal in GitLab 15.6.
+for use in GitLab 14.10, and is planned for removal in GitLab 16.0.
Prerequisites:
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 5d7c480143a..a98a032078d 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -525,6 +525,7 @@ GitLab Flavored Markdown recognizes the following:
| merge request | `!123` | `namespace/project!123` | `project!123` |
| snippet | `$123` | `namespace/project$123` | `project$123` |
| [epic](group/epics/index.md) | `&123` | `group1/subgroup&123` | |
+| [iteration](group/iterations/index.md) | `*iteration:"iteration title"`| | |
| [vulnerability](application_security/vulnerabilities/index.md) <sup>1</sup> | `[vulnerability:123]` | `[vulnerability:namespace/project/123]` | `[vulnerability:project/123]` |
| feature flag | `[feature_flag:123]` | `[feature_flag:namespace/project/123]` | `[feature_flag:project/123]` |
| label by ID | `~123` | `namespace/project~123` | `project~123` |
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 4fe12320f77..30261ed5082 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -238,7 +238,7 @@ and the exports between them are compatible.
### Project fails to import due to mismatch
-If the [shared runners enablement](../../../ci/runners/runners_scope.md#enable-shared-runners)
+If the [shared runners enablement](../../../ci/runners/runners_scope.md#enable-shared-runners-for-a-project)
does not match between the exported project, and the project import, the project fails to import.
Review [issue 276930](https://gitlab.com/gitlab-org/gitlab/-/issues/276930), and either:
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
index e807f251da1..e5285d63cf4 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -101,6 +101,12 @@ These shortcuts are available when viewing issues and [merge requests](project/m
| <kbd>b</kbd> | Copy source branch name (merge requests only). |
| <kbd>.</kbd> | Open the [Web IDE](project/web_ide/index.md). |
+Merge requests additionally support the following shortcuts:
+
+| macOS shortcut | Windows shortcut | Description |
+|---------------------------------|---------------------|-------------|
+| <kbd>Command</kbd> + <kbd>p</kbd> | <kbd>Control</kbd> + <kbd>p</kbd> | Search for, and then jump to a file for review. |
+
### Project files
These shortcuts are available when browsing the files in a project (go to
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ed6931385af..cba3c316a32 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -21400,7 +21400,7 @@ msgstr ""
msgid "JiraService|Define the type of Jira issue to create from a vulnerability."
msgstr ""
-msgid "JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used."
+msgid "JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{gitlab_issues_link_start}disabling GitLab issues%{link_end} if they won't otherwise be used."
msgstr ""
msgid "JiraService|Enable Jira issue creation from vulnerabilities"
@@ -21451,9 +21451,6 @@ msgstr ""
msgid "JiraService|Jira comments are created when an issue is referenced in a merge request."
msgstr ""
-msgid "JiraService|Jira issue type"
-msgstr ""
-
msgid "JiraService|Jira issues"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/multi-project_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/multi-project_pipelines_spec.rb
index 76c2cdadfd9..9c852f836c8 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/multi-project_pipelines_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/multi-project_pipelines_spec.rb
@@ -43,7 +43,10 @@ module QA
[upstream_project, downstream_project].each(&:remove_via_api!)
end
- it 'creates a multi-project pipeline', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348032' do
+ it(
+ 'creates a multi-project pipeline',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358064'
+ ) do
Page::Project::Pipeline::Show.perform do |show|
expect(show).to have_passed
expect(show).not_to have_job(downstream_job_name)
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
index 6841d4d19ba..2cab467249f 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
@@ -25,7 +25,10 @@ module QA
runner.remove_via_api!
end
- it 'parent pipelines passes if child passes', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348092' do
+ it(
+ 'parent pipelines passes if child passes',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358062'
+ ) do
add_ci_files(success_child_ci_file)
Flow::Pipeline.visit_latest_pipeline
@@ -35,7 +38,10 @@ module QA
end
end
- it 'parent pipeline fails if child fails', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348091' do
+ it(
+ 'parent pipeline fails if child fails',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358063'
+ ) do
add_ci_files(fail_child_ci_file)
Flow::Pipeline.visit_latest_pipeline
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
index fe46590c8f2..51212b8e54a 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
@@ -25,7 +25,10 @@ module QA
runner.remove_via_api!
end
- it 'parent pipelines passes if child passes', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348093' do
+ it(
+ 'parent pipelines passes if child passes',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358059'
+ ) do
add_ci_files(success_child_ci_file)
Flow::Pipeline.visit_latest_pipeline
@@ -35,7 +38,10 @@ module QA
end
end
- it 'parent pipeline passes even if child fails', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348094' do
+ it(
+ 'parent pipeline passes even if child fails',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358060'
+ ) do
add_ci_files(fail_child_ci_file)
Flow::Pipeline.visit_latest_pipeline
diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb
index f5d39e1cdd5..b81c41bb79c 100644
--- a/qa/spec/spec_helper.rb
+++ b/qa/spec/spec_helper.rb
@@ -79,7 +79,11 @@ RSpec.configure do |config|
# If any tests failed, leave the resources behind to help troubleshoot, otherwise remove them.
# Do not remove the shared resource on live environments
begin
- QA::Resource::ReusableCollection.remove_all_via_api! if !suite.reporter.failed_examples.present? && !QA::Runtime::Env.running_on_dot_com?
+ next if suite.reporter.failed_examples.present?
+ next unless QA::Runtime::Scenario.attributes.include?(:gitlab_address)
+ next if QA::Runtime::Env.running_on_dot_com?
+
+ QA::Resource::ReusableCollection.remove_all_via_api!
rescue QA::Resource::Errors::InternalServerError => e
# Temporarily prevent this error from failing jobs while the cause is investigated
# See https://gitlab.com/gitlab-org/gitlab/-/issues/354387
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 0837664dcc3..96e1f558255 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe "Admin Runners" do
include StubENV
- include Spec::Support::Helpers::ModalHelpers
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
@@ -15,7 +14,7 @@ RSpec.describe "Admin Runners" do
wait_for_requests
end
- describe "Runners page", :js do
+ describe "Admin Runners page", :js do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:namespace) { create(:namespace) }
@@ -486,63 +485,14 @@ RSpec.describe "Admin Runners" do
end
end
- describe 'runners registration' do
- let!(:token) { Gitlab::CurrentSettings.runners_registration_token }
-
+ describe "runners registration" do
before do
visit admin_runners_path
-
- click_on 'Register an instance runner'
end
- describe 'show registration instructions' do
- before do
- click_on 'Show runner installation and registration instructions'
-
- wait_for_requests
- end
-
- it 'opens runner installation modal' do
- expect(page).to have_text "Install a runner"
-
- expect(page).to have_text "Environment"
- expect(page).to have_text "Architecture"
- expect(page).to have_text "Download and install binary"
- end
-
- it 'dismisses runner installation modal' do
- within_modal do
- click_button('Close', match: :first)
- end
-
- expect(page).not_to have_text "Install a runner"
- end
- end
-
- it 'has a registration token' do
- click_on 'Click to reveal'
- expect(page.find('[data-testid="token-value"]')).to have_content(token)
- end
-
- describe 'reset registration token' do
- let(:page_token) { find('[data-testid="token-value"]').text }
-
- before do
- click_on 'Reset registration token'
-
- within_modal do
- click_button('Reset token', match: :first)
- end
-
- wait_for_requests
- end
-
- it 'changes registration token' do
- click_on 'Register an instance runner'
-
- click_on 'Click to reveal'
- expect(page_token).not_to eq token
- end
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { 'Register an instance runner' }
+ let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
end
end
end
diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb
new file mode 100644
index 00000000000..beb465cd3a5
--- /dev/null
+++ b/spec/features/groups/group_runners_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Group Runners" do
+ let_it_be(:group_owner) { create(:user) }
+ let_it_be(:group) { create(:group) }
+
+ let!(:group_registration_token) { group.runners_token }
+
+ before do
+ group.add_owner(group_owner)
+ sign_in(group_owner)
+ end
+
+ describe "Group runners page", :js do
+ describe "runners registration" do
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { 'Register a group runner' }
+ let(:registration_token) { group_registration_token }
+ end
+ end
+ end
+end
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 446f13dc4d0..8a5e33ba18c 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -71,6 +71,12 @@ RSpec.describe "User creates issue" do
expect(preview).to have_css("gl-emoji")
expect(textarea).not_to be_visible
+
+ click_button("Write")
+ fill_in("Description", with: "/confidential")
+ click_button("Preview")
+
+ expect(form).to have_content('Makes this issue confidential.')
end
end
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index 8c906e6a27c..3b440002cb5 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -35,6 +35,12 @@ RSpec.describe "Issues > User edits issue", :js do
end
expect(form).to have_button("Write")
+
+ click_button("Write")
+ fill_in("Description", with: "/confidential")
+ click_button("Preview")
+
+ expect(form).to have_content('Makes this issue confidential.')
end
it 'allows user to select unassigned' do
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 0dceb92db94..9f273ce5ba3 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -158,33 +158,32 @@ describe('Api', () => {
});
describe('group', () => {
- it('fetches a group', (done) => {
+ it('fetches a group', () => {
const groupId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}`;
mock.onGet(expectedUrl).reply(httpStatus.OK, {
name: 'test',
});
- Api.group(groupId, (response) => {
- expect(response.name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.group(groupId, (response) => {
+ expect(response.name).toBe('test');
+ resolve();
+ });
});
});
});
describe('groupMembers', () => {
- it('fetches group members', (done) => {
+ it('fetches group members', () => {
const groupId = '54321';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/members`;
const expectedData = [{ id: 7 }];
mock.onGet(expectedUrl).reply(httpStatus.OK, expectedData);
- Api.groupMembers(groupId)
- .then(({ data }) => {
- expect(data).toEqual(expectedData);
- })
- .then(done)
- .catch(done.fail);
+ return Api.groupMembers(groupId).then(({ data }) => {
+ expect(data).toEqual(expectedData);
+ });
});
});
@@ -233,7 +232,7 @@ describe('Api', () => {
});
describe('groupMilestones', () => {
- it('fetches group milestones', (done) => {
+ it('fetches group milestones', () => {
const groupId = '16';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/milestones`;
const expectedData = [
@@ -253,17 +252,14 @@ describe('Api', () => {
];
mock.onGet(expectedUrl).reply(httpStatus.OK, expectedData);
- Api.groupMilestones(groupId)
- .then(({ data }) => {
- expect(data).toEqual(expectedData);
- })
- .then(done)
- .catch(done.fail);
+ return Api.groupMilestones(groupId).then(({ data }) => {
+ expect(data).toEqual(expectedData);
+ });
});
});
describe('groups', () => {
- it('fetches groups', (done) => {
+ it('fetches groups', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups.json`;
@@ -273,16 +269,18 @@ describe('Api', () => {
},
]);
- Api.groups(query, options, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.groups(query, options, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
});
describe('groupLabels', () => {
- it('fetches group labels', (done) => {
+ it('fetches group labels', () => {
const options = { params: { search: 'foo' } };
const expectedGroup = 'gitlab-org';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${expectedGroup}/labels`;
@@ -293,18 +291,15 @@ describe('Api', () => {
},
]);
- Api.groupLabels(expectedGroup, options)
- .then((res) => {
- expect(res.length).toBe(1);
- expect(res[0].name).toBe('Foo Label');
- })
- .then(done)
- .catch(done.fail);
+ return Api.groupLabels(expectedGroup, options).then((res) => {
+ expect(res.length).toBe(1);
+ expect(res[0].name).toBe('Foo Label');
+ });
});
});
describe('namespaces', () => {
- it('fetches namespaces', (done) => {
+ it('fetches namespaces', () => {
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/namespaces.json`;
mock.onGet(expectedUrl).reply(httpStatus.OK, [
@@ -313,16 +308,18 @@ describe('Api', () => {
},
]);
- Api.namespaces(query, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.namespaces(query, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
});
describe('projects', () => {
- it('fetches projects with membership when logged in', (done) => {
+ it('fetches projects with membership when logged in', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
@@ -333,14 +330,16 @@ describe('Api', () => {
},
]);
- Api.projects(query, options, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.projects(query, options, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
- it('fetches projects without membership when not logged in', (done) => {
+ it('fetches projects without membership when not logged in', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
@@ -350,31 +349,30 @@ describe('Api', () => {
},
]);
- Api.projects(query, options, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.projects(query, options, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
});
describe('updateProject', () => {
- it('update a project with the given payload', (done) => {
+ it('update a project with the given payload', () => {
const projectPath = 'foo';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}`;
mock.onPut(expectedUrl).reply(httpStatus.OK, { foo: 'bar' });
- Api.updateProject(projectPath, { foo: 'bar' })
- .then(({ data }) => {
- expect(data.foo).toBe('bar');
- done();
- })
- .catch(done.fail);
+ return Api.updateProject(projectPath, { foo: 'bar' }).then(({ data }) => {
+ expect(data.foo).toBe('bar');
+ });
});
});
describe('projectUsers', () => {
- it('fetches all users of a particular project', (done) => {
+ it('fetches all users of a particular project', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const projectPath = 'gitlab-org%2Fgitlab-ce';
@@ -385,13 +383,10 @@ describe('Api', () => {
},
]);
- Api.projectUsers('gitlab-org/gitlab-ce', query, options)
- .then((response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectUsers('gitlab-org/gitlab-ce', query, options).then((response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ });
});
});
@@ -399,38 +394,32 @@ describe('Api', () => {
const projectPath = 'abc';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests`;
- it('fetches all merge requests for a project', (done) => {
+ it('fetches all merge requests for a project', () => {
const mockData = [{ source_branch: 'foo' }, { source_branch: 'bar' }];
mock.onGet(expectedUrl).reply(httpStatus.OK, mockData);
- Api.projectMergeRequests(projectPath)
- .then(({ data }) => {
- expect(data.length).toEqual(2);
- expect(data[0].source_branch).toBe('foo');
- expect(data[1].source_branch).toBe('bar');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMergeRequests(projectPath).then(({ data }) => {
+ expect(data.length).toEqual(2);
+ expect(data[0].source_branch).toBe('foo');
+ expect(data[1].source_branch).toBe('bar');
+ });
});
- it('fetches merge requests filtered with passed params', (done) => {
+ it('fetches merge requests filtered with passed params', () => {
const params = {
source_branch: 'bar',
};
const mockData = [{ source_branch: 'bar' }];
mock.onGet(expectedUrl, { params }).reply(httpStatus.OK, mockData);
- Api.projectMergeRequests(projectPath, params)
- .then(({ data }) => {
- expect(data.length).toEqual(1);
- expect(data[0].source_branch).toBe('bar');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMergeRequests(projectPath, params).then(({ data }) => {
+ expect(data.length).toEqual(1);
+ expect(data[0].source_branch).toBe('bar');
+ });
});
});
describe('projectMergeRequest', () => {
- it('fetches a merge request', (done) => {
+ it('fetches a merge request', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}`;
@@ -438,17 +427,14 @@ describe('Api', () => {
title: 'test',
});
- Api.projectMergeRequest(projectPath, mergeRequestId)
- .then(({ data }) => {
- expect(data.title).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMergeRequest(projectPath, mergeRequestId).then(({ data }) => {
+ expect(data.title).toBe('test');
+ });
});
});
describe('projectMergeRequestChanges', () => {
- it('fetches the changes of a merge request', (done) => {
+ it('fetches the changes of a merge request', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}/changes`;
@@ -456,17 +442,14 @@ describe('Api', () => {
title: 'test',
});
- Api.projectMergeRequestChanges(projectPath, mergeRequestId)
- .then(({ data }) => {
- expect(data.title).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMergeRequestChanges(projectPath, mergeRequestId).then(({ data }) => {
+ expect(data.title).toBe('test');
+ });
});
});
describe('projectMergeRequestVersions', () => {
- it('fetches the versions of a merge request', (done) => {
+ it('fetches the versions of a merge request', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}/versions`;
@@ -476,30 +459,24 @@ describe('Api', () => {
},
]);
- Api.projectMergeRequestVersions(projectPath, mergeRequestId)
- .then(({ data }) => {
- expect(data.length).toBe(1);
- expect(data[0].id).toBe(123);
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMergeRequestVersions(projectPath, mergeRequestId).then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].id).toBe(123);
+ });
});
});
describe('projectRunners', () => {
- it('fetches the runners of a project', (done) => {
+ it('fetches the runners of a project', () => {
const projectPath = 7;
const params = { scope: 'active' };
const mockData = [{ id: 4 }];
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/runners`;
mock.onGet(expectedUrl, { params }).reply(httpStatus.OK, mockData);
- Api.projectRunners(projectPath, { params })
- .then(({ data }) => {
- expect(data).toEqual(mockData);
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectRunners(projectPath, { params }).then(({ data }) => {
+ expect(data).toEqual(mockData);
+ });
});
});
@@ -528,7 +505,7 @@ describe('Api', () => {
});
describe('projectMilestones', () => {
- it('fetches project milestones', (done) => {
+ it('fetches project milestones', () => {
const projectId = 1;
const options = { state: 'active' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/1/milestones`;
@@ -540,13 +517,10 @@ describe('Api', () => {
},
]);
- Api.projectMilestones(projectId, options)
- .then(({ data }) => {
- expect(data.length).toBe(1);
- expect(data[0].title).toBe('milestone1');
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectMilestones(projectId, options).then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].title).toBe('milestone1');
+ });
});
});
@@ -614,7 +588,7 @@ describe('Api', () => {
});
describe('newLabel', () => {
- it('creates a new project label', (done) => {
+ it('creates a new project label', () => {
const namespace = 'some namespace';
const project = 'some project';
const labelData = { some: 'data' };
@@ -633,13 +607,15 @@ describe('Api', () => {
];
});
- Api.newLabel(namespace, project, labelData, (response) => {
- expect(response.name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.newLabel(namespace, project, labelData, (response) => {
+ expect(response.name).toBe('test');
+ resolve();
+ });
});
});
- it('creates a new group label', (done) => {
+ it('creates a new group label', () => {
const namespace = 'group/subgroup';
const labelData = { name: 'Foo', color: '#000000' };
const expectedUrl = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespace);
@@ -654,15 +630,17 @@ describe('Api', () => {
];
});
- Api.newLabel(namespace, undefined, labelData, (response) => {
- expect(response.name).toBe('Foo');
- done();
+ return new Promise((resolve) => {
+ Api.newLabel(namespace, undefined, labelData, (response) => {
+ expect(response.name).toBe('Foo');
+ resolve();
+ });
});
});
});
describe('groupProjects', () => {
- it('fetches group projects', (done) => {
+ it('fetches group projects', () => {
const groupId = '123456';
const query = 'dummy query';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/projects.json`;
@@ -672,10 +650,12 @@ describe('Api', () => {
},
]);
- Api.groupProjects(groupId, query, {}, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.groupProjects(groupId, query, {}, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
@@ -764,12 +744,14 @@ describe('Api', () => {
templateKey,
)}`;
- it('fetches an issue template', (done) => {
+ it('fetches an issue template', () => {
mock.onGet(expectedUrl).reply(httpStatus.OK, 'test');
- Api.issueTemplate(namespace, project, templateKey, templateType, (error, response) => {
- expect(response).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.issueTemplate(namespace, project, templateKey, templateType, (_, response) => {
+ expect(response).toBe('test');
+ resolve();
+ });
});
});
@@ -777,8 +759,11 @@ describe('Api', () => {
it('rejects the Promise', () => {
mock.onGet(expectedUrl).replyOnce(httpStatus.INTERNAL_SERVER_ERROR);
- Api.issueTemplate(namespace, project, templateKey, templateType, () => {
- expect(mock.history.get).toHaveLength(1);
+ return new Promise((resolve) => {
+ Api.issueTemplate(namespace, project, templateKey, templateType, () => {
+ expect(mock.history.get).toHaveLength(1);
+ resolve();
+ });
});
});
});
@@ -790,19 +775,21 @@ describe('Api', () => {
const templateType = 'template type';
const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}`;
- it('fetches all templates by type', (done) => {
+ it('fetches all templates by type', () => {
const expectedData = [
{ key: 'Template1', name: 'Template 1', content: 'This is template 1!' },
];
mock.onGet(expectedUrl).reply(httpStatus.OK, expectedData);
- Api.issueTemplates(namespace, project, templateType, (error, response) => {
- expect(response.length).toBe(1);
- const { key, name, content } = response[0];
- expect(key).toBe('Template1');
- expect(name).toBe('Template 1');
- expect(content).toBe('This is template 1!');
- done();
+ return new Promise((resolve) => {
+ Api.issueTemplates(namespace, project, templateType, (_, response) => {
+ expect(response.length).toBe(1);
+ const { key, name, content } = response[0];
+ expect(key).toBe('Template1');
+ expect(name).toBe('Template 1');
+ expect(content).toBe('This is template 1!');
+ resolve();
+ });
});
});
@@ -818,34 +805,44 @@ describe('Api', () => {
});
describe('projectTemplates', () => {
- it('fetches a list of templates', (done) => {
+ it('fetches a list of templates', () => {
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/gitlab-org%2Fgitlab-ce/templates/licenses`;
mock.onGet(expectedUrl).reply(httpStatus.OK, 'test');
- Api.projectTemplates('gitlab-org/gitlab-ce', 'licenses', {}, (response) => {
- expect(response).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.projectTemplates('gitlab-org/gitlab-ce', 'licenses', {}, (response) => {
+ expect(response).toBe('test');
+ resolve();
+ });
});
});
});
describe('projectTemplate', () => {
- it('fetches a single template', (done) => {
+ it('fetches a single template', () => {
const data = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/gitlab-org%2Fgitlab-ce/templates/licenses/test%20license`;
mock.onGet(expectedUrl).reply(httpStatus.OK, 'test');
- Api.projectTemplate('gitlab-org/gitlab-ce', 'licenses', 'test license', data, (response) => {
- expect(response).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.projectTemplate(
+ 'gitlab-org/gitlab-ce',
+ 'licenses',
+ 'test license',
+ data,
+ (response) => {
+ expect(response).toBe('test');
+ resolve();
+ },
+ );
});
});
});
describe('users', () => {
- it('fetches users', (done) => {
+ it('fetches users', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users.json`;
@@ -855,68 +852,56 @@ describe('Api', () => {
},
]);
- Api.users(query, options)
- .then(({ data }) => {
- expect(data.length).toBe(1);
- expect(data[0].name).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.users(query, options).then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ });
});
});
describe('user', () => {
- it('fetches single user', (done) => {
+ it('fetches single user', () => {
const userId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users/${userId}`;
mock.onGet(expectedUrl).reply(httpStatus.OK, {
name: 'testuser',
});
- Api.user(userId)
- .then(({ data }) => {
- expect(data.name).toBe('testuser');
- })
- .then(done)
- .catch(done.fail);
+ return Api.user(userId).then(({ data }) => {
+ expect(data.name).toBe('testuser');
+ });
});
});
describe('user counts', () => {
- it('fetches single user counts', (done) => {
+ it('fetches single user counts', () => {
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/user_counts`;
mock.onGet(expectedUrl).reply(httpStatus.OK, {
merge_requests: 4,
});
- Api.userCounts()
- .then(({ data }) => {
- expect(data.merge_requests).toBe(4);
- })
- .then(done)
- .catch(done.fail);
+ return Api.userCounts().then(({ data }) => {
+ expect(data.merge_requests).toBe(4);
+ });
});
});
describe('user status', () => {
- it('fetches single user status', (done) => {
+ it('fetches single user status', () => {
const userId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users/${userId}/status`;
mock.onGet(expectedUrl).reply(httpStatus.OK, {
message: 'testmessage',
});
- Api.userStatus(userId)
- .then(({ data }) => {
- expect(data.message).toBe('testmessage');
- })
- .then(done)
- .catch(done.fail);
+ return Api.userStatus(userId).then(({ data }) => {
+ expect(data.message).toBe('testmessage');
+ });
});
});
describe('user projects', () => {
- it('fetches all projects that belong to a particular user', (done) => {
+ it('fetches all projects that belong to a particular user', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const userId = '123456';
@@ -927,16 +912,18 @@ describe('Api', () => {
},
]);
- Api.userProjects(userId, query, options, (response) => {
- expect(response.length).toBe(1);
- expect(response[0].name).toBe('test');
- done();
+ return new Promise((resolve) => {
+ Api.userProjects(userId, query, options, (response) => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ resolve();
+ });
});
});
});
describe('commitPipelines', () => {
- it('fetches pipelines for a given commit', (done) => {
+ it('fetches pipelines for a given commit', () => {
const projectId = 'example/foobar';
const commitSha = 'abc123def';
const expectedUrl = `${dummyUrlRoot}/${projectId}/commit/${commitSha}/pipelines`;
@@ -946,13 +933,10 @@ describe('Api', () => {
},
]);
- Api.commitPipelines(projectId, commitSha)
- .then(({ data }) => {
- expect(data.length).toBe(1);
- expect(data[0].name).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.commitPipelines(projectId, commitSha).then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ });
});
});
@@ -977,7 +961,7 @@ describe('Api', () => {
});
describe('createBranch', () => {
- it('creates new branch', (done) => {
+ it('creates new branch', () => {
const ref = 'main';
const branch = 'new-branch-name';
const dummyProjectPath = 'gitlab-org/gitlab-ce';
@@ -991,18 +975,15 @@ describe('Api', () => {
name: branch,
});
- Api.createBranch(dummyProjectPath, { ref, branch })
- .then(({ data }) => {
- expect(data.name).toBe(branch);
- expect(axios.post).toHaveBeenCalledWith(expectedUrl, { ref, branch });
- })
- .then(done)
- .catch(done.fail);
+ return Api.createBranch(dummyProjectPath, { ref, branch }).then(({ data }) => {
+ expect(data.name).toBe(branch);
+ expect(axios.post).toHaveBeenCalledWith(expectedUrl, { ref, branch });
+ });
});
});
describe('projectForks', () => {
- it('gets forked projects', (done) => {
+ it('gets forked projects', () => {
const dummyProjectPath = 'gitlab-org/gitlab-ce';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${encodeURIComponent(
dummyProjectPath,
@@ -1012,20 +993,17 @@ describe('Api', () => {
mock.onGet(expectedUrl).replyOnce(httpStatus.OK, ['fork']);
- Api.projectForks(dummyProjectPath, { visibility: 'private' })
- .then(({ data }) => {
- expect(data).toEqual(['fork']);
- expect(axios.get).toHaveBeenCalledWith(expectedUrl, {
- params: { visibility: 'private' },
- });
- })
- .then(done)
- .catch(done.fail);
+ return Api.projectForks(dummyProjectPath, { visibility: 'private' }).then(({ data }) => {
+ expect(data).toEqual(['fork']);
+ expect(axios.get).toHaveBeenCalledWith(expectedUrl, {
+ params: { visibility: 'private' },
+ });
+ });
});
});
describe('createContextCommits', () => {
- it('creates a new context commit', (done) => {
+ it('creates a new context commit', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const commitsData = ['abcdefg'];
@@ -1044,17 +1022,16 @@ describe('Api', () => {
},
]);
- Api.createContextCommits(projectPath, mergeRequestId, expectedData)
- .then(({ data }) => {
+ return Api.createContextCommits(projectPath, mergeRequestId, expectedData).then(
+ ({ data }) => {
expect(data[0].title).toBe('Dummy commit');
- })
- .then(done)
- .catch(done.fail);
+ },
+ );
});
});
describe('allContextCommits', () => {
- it('gets all context commits', (done) => {
+ it('gets all context commits', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}/context_commits`;
@@ -1065,17 +1042,14 @@ describe('Api', () => {
.onGet(expectedUrl)
.replyOnce(200, [{ id: 'abcdef', short_id: 'abcdefghi', title: 'Dummy commit title' }]);
- Api.allContextCommits(projectPath, mergeRequestId)
- .then(({ data }) => {
- expect(data[0].title).toBe('Dummy commit title');
- })
- .then(done)
- .catch(done.fail);
+ return Api.allContextCommits(projectPath, mergeRequestId).then(({ data }) => {
+ expect(data[0].title).toBe('Dummy commit title');
+ });
});
});
describe('removeContextCommits', () => {
- it('removes context commits', (done) => {
+ it('removes context commits', () => {
const projectPath = 'abc';
const mergeRequestId = '123456';
const commitsData = ['abcdefg'];
@@ -1088,12 +1062,9 @@ describe('Api', () => {
mock.onDelete(expectedUrl).replyOnce(204);
- Api.removeContextCommits(projectPath, mergeRequestId, expectedData)
- .then(() => {
- expect(axios.delete).toHaveBeenCalledWith(expectedUrl, { data: expectedData });
- })
- .then(done)
- .catch(done.fail);
+ return Api.removeContextCommits(projectPath, mergeRequestId, expectedData).then(() => {
+ expect(axios.delete).toHaveBeenCalledWith(expectedUrl, { data: expectedData });
+ });
});
});
@@ -1336,41 +1307,37 @@ describe('Api', () => {
});
describe('updateIssue', () => {
- it('update an issue with the given payload', (done) => {
+ it('update an issue with the given payload', () => {
const projectId = 8;
const issue = 1;
const expectedArray = [1, 2, 3];
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectId}/issues/${issue}`;
mock.onPut(expectedUrl).reply(httpStatus.OK, { assigneeIds: expectedArray });
- Api.updateIssue(projectId, issue, { assigneeIds: expectedArray })
- .then(({ data }) => {
- expect(data.assigneeIds).toEqual(expectedArray);
- done();
- })
- .catch(done.fail);
+ return Api.updateIssue(projectId, issue, { assigneeIds: expectedArray }).then(({ data }) => {
+ expect(data.assigneeIds).toEqual(expectedArray);
+ });
});
});
describe('updateMergeRequest', () => {
- it('update an issue with the given payload', (done) => {
+ it('update an issue with the given payload', () => {
const projectId = 8;
const mergeRequest = 1;
const expectedArray = [1, 2, 3];
const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectId}/merge_requests/${mergeRequest}`;
mock.onPut(expectedUrl).reply(httpStatus.OK, { assigneeIds: expectedArray });
- Api.updateMergeRequest(projectId, mergeRequest, { assigneeIds: expectedArray })
- .then(({ data }) => {
+ return Api.updateMergeRequest(projectId, mergeRequest, { assigneeIds: expectedArray }).then(
+ ({ data }) => {
expect(data.assigneeIds).toEqual(expectedArray);
- done();
- })
- .catch(done.fail);
+ },
+ );
});
});
describe('tags', () => {
- it('fetches all tags of a particular project', (done) => {
+ it('fetches all tags of a particular project', () => {
const query = 'dummy query';
const options = { unused: 'option' };
const projectId = 8;
@@ -1381,13 +1348,10 @@ describe('Api', () => {
},
]);
- Api.tags(projectId, query, options)
- .then(({ data }) => {
- expect(data.length).toBe(1);
- expect(data[0].name).toBe('test');
- })
- .then(done)
- .catch(done.fail);
+ return Api.tags(projectId, query, options).then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ });
});
});
diff --git a/spec/frontend/boards/components/issuable_title_spec.js b/spec/frontend/boards/components/issuable_title_spec.js
deleted file mode 100644
index 4b7f491b998..00000000000
--- a/spec/frontend/boards/components/issuable_title_spec.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import IssuableTitle from '~/boards/components/issuable_title.vue';
-
-describe('IssuableTitle', () => {
- let wrapper;
- const defaultProps = {
- title: 'One',
- refPath: 'path',
- };
- const createComponent = () => {
- wrapper = shallowMount(IssuableTitle, {
- propsData: { ...defaultProps },
- });
- };
- const findIssueContent = () => wrapper.find('[data-testid="issue-title"]');
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('renders a title of an issue in the sidebar', () => {
- expect(findIssueContent().text()).toContain('One');
- });
-
- it('renders a referencePath of an issue in the sidebar', () => {
- expect(findIssueContent().text()).toContain('path');
- });
-});
diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js
index b3d0781fde5..fbcc5ecefb3 100644
--- a/spec/frontend/diffs/components/commit_item_spec.js
+++ b/spec/frontend/diffs/components/commit_item_spec.js
@@ -80,7 +80,7 @@ describe('diffs/components/commit_item', () => {
const imgElement = avatarElement.find('img');
expect(avatarElement.attributes('href')).toBe(commit.author.web_url);
- expect(imgElement.classes()).toContain('s40');
+ expect(imgElement.classes()).toContain('s32');
expect(imgElement.attributes('alt')).toBe(commit.author.name);
expect(imgElement.attributes('src')).toBe(commit.author.avatar_url);
});
diff --git a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
index 33fd08a5959..94e370a485f 100644
--- a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
@@ -10,7 +10,6 @@ describe('JiraIssuesFields', () => {
let wrapper;
const defaultProps = {
- editProjectPath: '/edit',
showJiraIssuesIntegration: true,
showJiraVulnerabilitiesIntegration: true,
upgradePlanPath: 'https://gitlab.com',
@@ -46,7 +45,6 @@ describe('JiraIssuesFields', () => {
const findPremiumUpgradeCTA = () => wrapper.findByTestId('premium-upgrade-cta');
const findUltimateUpgradeCTA = () => wrapper.findByTestId('ultimate-upgrade-cta');
const findJiraForVulnerabilities = () => wrapper.findByTestId('jira-for-vulnerabilities');
- const findConflictWarning = () => wrapper.findByTestId('conflict-warning-text');
const setEnableCheckbox = async (isEnabled = true) =>
findEnableCheckbox().vm.$emit('input', isEnabled);
@@ -75,10 +73,9 @@ describe('JiraIssuesFields', () => {
});
if (showJiraIssuesIntegration) {
- it('renders checkbox and input field', () => {
+ it('renders enable checkbox', () => {
expect(findEnableCheckbox().exists()).toBe(true);
expect(findEnableCheckboxDisabled()).toBeUndefined();
- expect(findProjectKey().exists()).toBe(true);
});
it('does not render the Premium CTA', () => {
@@ -98,9 +95,8 @@ describe('JiraIssuesFields', () => {
});
}
} else {
- it('does not render checkbox and input field', () => {
+ it('does not render enable checkbox', () => {
expect(findEnableCheckbox().exists()).toBe(false);
- expect(findProjectKey().exists()).toBe(false);
});
it('renders the Premium CTA', () => {
@@ -122,12 +118,8 @@ describe('JiraIssuesFields', () => {
createComponent({ props: { initialProjectKey: '' } });
});
- it('renders disabled project_key input', () => {
- const projectKey = findProjectKey();
-
- expect(projectKey.exists()).toBe(true);
- expect(projectKey.attributes('disabled')).toBe('disabled');
- expect(projectKey.attributes('required')).toBeUndefined();
+ it('does not render project_key input', () => {
+ expect(findProjectKey().exists()).toBe(false);
});
// As per https://vuejs.org/v2/guide/forms.html#Checkbox-1,
@@ -137,45 +129,23 @@ describe('JiraIssuesFields', () => {
});
describe('when isInheriting = true', () => {
- it('disables checkbox and sets input as readonly', () => {
+ it('disables checkbox', () => {
createComponent({ isInheriting: true });
expect(findEnableCheckboxDisabled()).toBe('disabled');
- expect(findProjectKey().attributes('readonly')).toBe('readonly');
});
});
describe('on enable issues', () => {
- it('enables project_key input as required', async () => {
+ it('renders project_key input as required', async () => {
await setEnableCheckbox(true);
- expect(findProjectKey().attributes('disabled')).toBeUndefined();
+ expect(findProjectKey().exists()).toBe(true);
expect(findProjectKey().attributes('required')).toBe('required');
});
});
});
- it('contains link to editProjectPath', () => {
- createComponent();
-
- expect(wrapper.find(`a[href="${defaultProps.editProjectPath}"]`).exists()).toBe(true);
- });
-
- describe('GitLab issues warning', () => {
- it.each`
- gitlabIssuesEnabled | scenario
- ${true} | ${'displays conflict warning'}
- ${false} | ${'does not display conflict warning'}
- `(
- '$scenario when `gitlabIssuesEnabled` is `$gitlabIssuesEnabled`',
- ({ gitlabIssuesEnabled }) => {
- createComponent({ props: { gitlabIssuesEnabled } });
-
- expect(findConflictWarning().exists()).toBe(gitlabIssuesEnabled);
- },
- );
- });
-
describe('Vulnerabilities creation', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js
index b5daa389fc6..cf98630c654 100644
--- a/spec/frontend/vue_shared/components/markdown/field_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_spec.js
@@ -101,6 +101,21 @@ describe('Markdown field component', () => {
expect(subject.find('.zen-backdrop textarea').element).not.toBeNull();
});
+ it('renders referenced commands on markdown preview', async () => {
+ axiosMock
+ .onPost(markdownPreviewPath)
+ .reply(200, { references: { users: [], commands: 'test command' } });
+
+ previewLink = getPreviewLink();
+ previewLink.vm.$emit('click', { target: {} });
+
+ await axios.waitFor(markdownPreviewPath);
+ const referencedCommands = subject.find('[data-testid="referenced-commands"]');
+
+ expect(referencedCommands.exists()).toBe(true);
+ expect(referencedCommands.text()).toContain('test command');
+ });
+
describe('markdown preview', () => {
beforeEach(() => {
axiosMock.onPost(markdownPreviewPath).reply(200, { body: previewHTML });
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index ed50a4daae8..ee5b0145d13 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -288,7 +288,7 @@ RSpec.describe IssuablesHelper do
canUpdate: true,
canDestroy: true,
issuableRef: "##{issue.iid}",
- markdownPreviewPath: "/#{@project.full_path}/preview_markdown",
+ markdownPreviewPath: "/#{@project.full_path}/preview_markdown?target_id=#{issue.iid}&target_type=Issue",
markdownDocsPath: '/help/user/markdown',
lockVersion: issue.lock_version,
projectPath: @project.path,
diff --git a/spec/services/bulk_imports/relation_export_service_spec.rb b/spec/services/bulk_imports/relation_export_service_spec.rb
index 27a6ca60515..f0f85217d2e 100644
--- a/spec/services/bulk_imports/relation_export_service_spec.rb
+++ b/spec/services/bulk_imports/relation_export_service_spec.rb
@@ -88,6 +88,18 @@ RSpec.describe BulkImports::RelationExportService do
subject.execute
end
+
+ context 'when export is recently finished' do
+ it 'returns recently finished export instead of re-exporting' do
+ updated_at = 5.seconds.ago
+ export.update!(status: 1, updated_at: updated_at)
+
+ expect { subject.execute }.not_to change { export.updated_at }
+
+ expect(export.status).to eq(1)
+ expect(export.updated_at).to eq(updated_at)
+ end
+ end
end
context 'when exception occurs during export' do
diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb
new file mode 100644
index 00000000000..133f3ff5fb6
--- /dev/null
+++ b/spec/support/shared_examples/features/runners_shared_examples.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'shows and resets runner registration token' do
+ include Spec::Support::Helpers::ModalHelpers
+
+ before do
+ click_on dropdown_text
+ end
+
+ describe 'shows registration instructions' do
+ before do
+ click_on 'Show runner installation and registration instructions'
+
+ wait_for_requests
+ end
+
+ it 'opens runner installation modal', :aggregate_failures do
+ within_modal do
+ expect(page).to have_text "Install a runner"
+ expect(page).to have_text "Environment"
+ expect(page).to have_text "Architecture"
+ expect(page).to have_text "Download and install binary"
+ end
+ end
+
+ it 'dismisses runner installation modal' do
+ within_modal do
+ click_button('Close', match: :first)
+ end
+
+ expect(page).not_to have_text "Install a runner"
+ end
+ end
+
+ it 'has a registration token' do
+ click_on 'Click to reveal'
+ expect(page.find('[data-testid="token-value"]')).to have_content(registration_token)
+ end
+
+ describe 'reset registration token' do
+ let!(:old_registration_token) { find('[data-testid="token-value"]').text }
+
+ before do
+ click_on 'Reset registration token'
+
+ within_modal do
+ click_button('Reset token', match: :first)
+ end
+
+ wait_for_requests
+ end
+
+ it 'changes registration token' do
+ expect(find('.gl-toast')).to have_content('New registration token generated!')
+
+ click_on dropdown_text
+ click_on 'Click to reveal'
+
+ expect(old_registration_token).not_to eq registration_token
+ end
+ end
+end