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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-08 15:08:48 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-08 15:08:48 +0300
commit88bacc889f129f8d95af34f1781dd66769ec27cc (patch)
tree28174e332bfc9ebd2dad2305a8f5300e7a656ca3
parentae6b82598ff1a9844c132e53799c252225b2c4c1 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo.yml18
-rw-r--r--.rubocop_todo/layout/multiline_operation_indentation.yml106
-rw-r--r--.rubocop_todo/layout/space_inside_parens.yml440
-rw-r--r--.rubocop_todo/lint/constant_definition_in_block.yml53
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js2
-rw-r--r--app/assets/javascripts/blob/pdf/pdf_viewer.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue2
-rw-r--r--app/assets/javascripts/code_navigation/components/app.vue2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue6
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussions.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue11
-rw-r--r--app/assets/javascripts/diffs/store/actions.js2
-rw-r--r--app/assets/javascripts/diffs/utils/performance.js2
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_bundle.js2
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue4
-rw-r--r--app/assets/javascripts/image_diff/helpers/init_image_diff.js2
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/index.js2
-rw-r--r--app/assets/javascripts/mr_popover/components/mr_popover.vue4
-rw-r--r--app/assets/javascripts/notes/components/diff_discussion_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_edited_text.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue2
-rw-r--r--app/assets/javascripts/pages/admin/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/project.js2
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue8
-rw-r--r--app/assets/javascripts/serverless/components/url.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/awards_list.vue2
-rw-r--r--app/controllers/groups/releases_controller.rb4
-rw-r--r--app/finders/releases/group_releases_finder.rb8
-rw-r--r--app/helpers/wiki_helper.rb4
-rw-r--r--app/models/ci/namespace_mirror.rb20
-rw-r--r--app/models/ci/secure_file.rb7
-rw-r--r--app/models/concerns/from_set_operator.rb7
-rw-r--r--app/models/user.rb23
-rw-r--r--app/models/wiki.rb53
-rw-r--r--app/models/wiki_page.rb4
-rw-r--r--app/services/event_create_service.rb5
-rw-r--r--app/uploaders/ci/secure_file_uploader.rb2
-rw-r--r--app/views/errors/_footer.html.haml4
-rw-r--r--app/views/layouts/errors.html.haml4
-rw-r--r--app/views/projects/forks/index.html.haml13
-rw-r--r--app/views/shared/wikis/_form.html.haml2
-rw-r--r--config/feature_flags/development/ci_owned_runners_unnest_index.yml8
-rw-r--r--db/migrate/20220324175325_add_key_data_to_secure_files.rb17
-rw-r--r--db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb25
-rw-r--r--db/schema_migrations/202203241753251
-rw-r--r--db/schema_migrations/202203291106301
-rw-r--r--db/structure.sql6
-rw-r--r--doc/administration/reference_architectures/25k_users.md6
-rw-r--r--doc/administration/reference_architectures/index.md28
-rw-r--r--doc/api/api_resources.md1
-rw-r--r--doc/api/group_releases.md77
-rw-r--r--doc/api/releases/index.md8
-rw-r--r--doc/architecture/blueprints/container_registry_metadata_database/index.md2
-rw-r--r--doc/development/code_review.md4
-rw-r--r--doc/development/database/add_foreign_key_to_existing_column.md2
-rw-r--r--doc/development/database/avoiding_downtime_in_migrations.md (renamed from doc/development/avoiding_downtime_in_migrations.md)12
-rw-r--r--doc/development/database/background_migrations.md (renamed from doc/development/background_migrations.md)16
-rw-r--r--doc/development/database/database_reviewer_guidelines.md2
-rw-r--r--doc/development/database/deleting_migrations.md (renamed from doc/development/deleting_migrations.md)0
-rw-r--r--doc/development/database/index.md8
-rw-r--r--doc/development/database/loose_foreign_keys.md4
-rw-r--r--doc/development/database/not_null_constraints.md2
-rw-r--r--doc/development/database/post_deployment_migrations.md (renamed from doc/development/post_deployment_migrations.md)0
-rw-r--r--doc/development/database/rename_database_tables.md2
-rw-r--r--doc/development/database/strings_and_the_text_data_type.md4
-rw-r--r--doc/development/database/table_partitioning.md2
-rw-r--r--doc/development/database_review.md10
-rw-r--r--doc/development/iterating_tables_in_batches.md2
-rw-r--r--doc/development/merge_request_performance_guidelines.md2
-rw-r--r--doc/development/migration_style_guide.md18
-rw-r--r--doc/development/scalability.md2
-rw-r--r--doc/development/service_ping/metrics_dictionary.md2
-rw-r--r--doc/development/service_ping/metrics_lifecycle.md2
-rw-r--r--doc/development/sidekiq/compatibility_across_updates.md2
-rw-r--r--doc/raketasks/backup_restore.md2
-rw-r--r--doc/raketasks/migrate_snippets.md2
-rw-r--r--doc/update/zero_downtime.md2
-rw-r--r--lib/api/entities/basic_release_details.rb16
-rw-r--r--lib/api/entities/release.rb8
-rw-r--r--lib/api/releases.rb58
-rw-r--r--lib/api/wikis.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/template_usage.rb2
-rw-r--r--lib/gitlab/pagination/offset_pagination.rb8
-rw-r--r--lib/gitlab/usage_data_counters/ci_template_unique_counter.rb9
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb22
-rw-r--r--spec/factories/ci/builds.rb4
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json1
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb44
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb30
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb28
-rw-r--r--spec/lib/gitlab/config/loader/yaml_spec.rb10
-rw-r--r--spec/lib/gitlab/path_regex_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb44
-rw-r--r--spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb4
-rw-r--r--spec/lib/gitlab/web_ide/config_spec.rb4
-rw-r--r--spec/models/ci/build_spec.rb4
-rw-r--r--spec/models/ci/namespace_mirror_spec.rb47
-rw-r--r--spec/models/preloaders/environments/deployment_preloader_spec.rb10
-rw-r--r--spec/models/user_spec.rb8
-rw-r--r--spec/models/web_ide_terminal_spec.rb6
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb2
-rw-r--r--spec/requests/api/lint_spec.rb6
-rw-r--r--spec/requests/api/releases_spec.rb78
-rw-r--r--spec/serializers/environment_serializer_spec.rb28
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb10
-rw-r--r--spec/services/ci/create_web_ide_terminal_service_spec.rb2
-rw-r--r--spec/services/event_create_service_spec.rb5
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci.yml2
-rw-r--r--spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb11
-rw-r--r--spec/uploaders/ci/secure_file_uploader_spec.rb4
127 files changed, 1395 insertions, 369 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index d30728c1596..6303568cad1 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -11,13 +11,6 @@ Gitlab/PolicyRuleBoolean:
Exclude:
- 'ee/app/policies/ee/identity_provider_policy.rb'
-# Offense count: 170
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle, IndentationWidth.
-# SupportedStyles: aligned, indented
-Layout/MultilineOperationIndentation:
- Enabled: false
-
# Offense count: 754
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
@@ -25,17 +18,6 @@ Layout/MultilineOperationIndentation:
Layout/SpaceInLambdaLiteral:
Enabled: false
-# Offense count: 585
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: space, no_space
-Layout/SpaceInsideParens:
- Enabled: false
-
-# Offense count: 84
-Lint/ConstantDefinitionInBlock:
- Enabled: false
-
# Offense count: 2
# Configuration parameters: AllowComments.
Lint/EmptyFile:
diff --git a/.rubocop_todo/layout/multiline_operation_indentation.yml b/.rubocop_todo/layout/multiline_operation_indentation.yml
new file mode 100644
index 00000000000..0f2404ee3cc
--- /dev/null
+++ b/.rubocop_todo/layout/multiline_operation_indentation.yml
@@ -0,0 +1,106 @@
+---
+# Cop supports --auto-correct.
+Layout/MultilineOperationIndentation:
+ # Offense count: 252
+ # Temporarily disabled due to too many offenses
+ Enabled: false
+ Exclude:
+ - 'app/controllers/projects/application_controller.rb'
+ - 'app/controllers/repositories/git_http_client_controller.rb'
+ - 'app/controllers/sent_notifications_controller.rb'
+ - 'app/graphql/types/ci/stage_type.rb'
+ - 'app/helpers/application_settings_helper.rb'
+ - 'app/helpers/auth_helper.rb'
+ - 'app/helpers/issuables_helper.rb'
+ - 'app/helpers/mirror_helper.rb'
+ - 'app/helpers/packages_helper.rb'
+ - 'app/helpers/projects_helper.rb'
+ - 'app/helpers/storage_helper.rb'
+ - 'app/helpers/visibility_level_helper.rb'
+ - 'app/helpers/whats_new_helper.rb'
+ - 'app/models/concerns/admin_changed_password_notifier.rb'
+ - 'app/models/integrations/prometheus.rb'
+ - 'app/models/namespaces/traversal/linear_scopes.rb'
+ - 'app/models/packages/conan/metadatum.rb'
+ - 'app/models/packages/sem_ver.rb'
+ - 'app/models/project.rb'
+ - 'app/models/project_statistics.rb'
+ - 'app/models/user.rb'
+ - 'app/services/ci/create_downstream_pipeline_service.rb'
+ - 'app/services/ci/create_pipeline_service.rb'
+ - 'app/services/git/branch_hooks_service.rb'
+ - 'app/services/groups/group_links/create_service.rb'
+ - 'app/services/groups/transfer_service.rb'
+ - 'app/services/issues/update_service.rb'
+ - 'app/services/labels/promote_service.rb'
+ - 'app/services/labels/transfer_service.rb'
+ - 'app/services/projects/container_repository/cleanup_tags_service.rb'
+ - 'app/services/webauthn/authenticate_service.rb'
+ - 'app/validators/feature_flag_strategies_validator.rb'
+ - 'app/workers/container_expiration_policies/cleanup_container_repository_worker.rb'
+ - 'config/initializers/devise_dynamic_password_length_validation.rb'
+ - 'danger/utility_css/Dangerfile'
+ - 'ee/app/controllers/smartcard_controller.rb'
+ - 'ee/app/graphql/resolvers/boards/epic_lists_resolver.rb'
+ - 'ee/app/helpers/ee/application_settings_helper.rb'
+ - 'ee/app/helpers/ee/boards_helper.rb'
+ - 'ee/app/helpers/groups/security_features_helper.rb'
+ - 'ee/app/helpers/groups/sso_helper.rb'
+ - 'ee/app/models/ee/namespace.rb'
+ - 'ee/app/models/ee/namespace/root_storage_size.rb'
+ - 'ee/app/models/ee/project.rb'
+ - 'ee/app/models/ee/user.rb'
+ - 'ee/app/models/vulnerabilities/finding_signature.rb'
+ - 'ee/app/policies/ee/base_policy.rb'
+ - 'ee/app/services/analytics/cycle_analytics/value_streams/update_service.rb'
+ - 'ee/app/services/ee/merge_requests/build_service.rb'
+ - 'ee/app/services/ee/projects/operations/update_service.rb'
+ - 'ee/lib/ee/api/entities/group.rb'
+ - 'ee/lib/ee/api/helpers.rb'
+ - 'ee/lib/ee/gitlab/middleware/read_only/controller.rb'
+ - 'ee/lib/ee/gitlab/quick_actions/issue_actions.rb'
+ - 'ee/lib/ee/sidebars/projects/menus/ci_cd_menu.rb'
+ - 'ee/lib/ee/sidebars/projects/menus/issues_menu.rb'
+ - 'ee/lib/elastic/latest/issue_class_proxy.rb'
+ - 'ee/lib/sidebars/groups/menus/analytics_menu.rb'
+ - 'ee/lib/sidebars/groups/menus/security_compliance_menu.rb'
+ - 'ee/spec/services/ci/create_pipeline_service/dast_configuration_spec.rb'
+ - 'lib/api/maven_packages.rb'
+ - 'lib/api/users.rb'
+ - 'lib/api/validations/validators/array_none_any.rb'
+ - 'lib/gitlab/ci/reports/security/finding_key.rb'
+ - 'lib/gitlab/database/load_balancing/connection_proxy.rb'
+ - 'lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb'
+ - 'lib/gitlab/elasticsearch/logs/lines.rb'
+ - 'lib/gitlab/form_builders/gitlab_ui_form_builder.rb'
+ - 'lib/gitlab/git_access.rb'
+ - 'lib/gitlab/gl_repository/repo_type.rb'
+ - 'lib/gitlab/jwt_token.rb'
+ - 'lib/gitlab/kubernetes/helm/v2/install_command.rb'
+ - 'lib/gitlab/kubernetes/helm/v2/patch_command.rb'
+ - 'lib/gitlab/kubernetes/helm/v3/install_command.rb'
+ - 'lib/gitlab/kubernetes/helm/v3/patch_command.rb'
+ - 'lib/gitlab/pagination/cursor_based_keyset.rb'
+ - 'lib/gitlab/quick_actions/issue_and_merge_request_actions.rb'
+ - 'lib/gitlab/rack_attack/request.rb'
+ - 'lib/gitlab/x509/signature.rb'
+ - 'lib/gitlab_edition.rb'
+ - 'lib/kramdown/converter/commonmark.rb'
+ - 'lib/sidebars/groups/menus/packages_registries_menu.rb'
+ - 'lib/sidebars/projects/menus/analytics_menu.rb'
+ - 'lib/sidebars/projects/menus/deployments_menu.rb'
+ - 'lib/sidebars/projects/menus/hidden_menu.rb'
+ - 'lib/sidebars/projects/menus/monitor_menu.rb'
+ - 'lib/sidebars/projects/menus/settings_menu.rb'
+ - 'qa/qa/ee/page/group/roadmap.rb'
+ - 'qa/qa/page/component/snippet.rb'
+ - 'qa/qa/runtime/api/repository_storage_moves.rb'
+ - 'rubocop/cop/gitlab/keys_first_and_values_first.rb'
+ - 'rubocop/cop/migration/hash_index.rb'
+ - 'rubocop/migration_helpers.rb'
+ - 'spec/frontend/fixtures/tabs.rb'
+ - 'spec/lib/gitlab/ci/pipeline/seed/build_spec.rb'
+ - 'spec/services/ci/create_pipeline_service_spec.rb'
+ - 'spec/services/projects/import_export/export_service_spec.rb'
+ - 'spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb'
+ - 'spec/support/shared_examples/models/with_debian_distributions_shared_examples.rb'
diff --git a/.rubocop_todo/layout/space_inside_parens.yml b/.rubocop_todo/layout/space_inside_parens.yml
new file mode 100644
index 00000000000..62d33391a25
--- /dev/null
+++ b/.rubocop_todo/layout/space_inside_parens.yml
@@ -0,0 +1,440 @@
+---
+# Cop supports --auto-correct.
+Layout/SpaceInsideParens:
+ # Offense count: 701
+ # Temporarily disabled due to too many offenses
+ Enabled: false
+ Exclude:
+ - 'app/controllers/projects/environments_controller.rb'
+ - 'app/controllers/projects/pipeline_schedules_controller.rb'
+ - 'app/graphql/mutations/ci/job/base.rb'
+ - 'app/helpers/icons_helper.rb'
+ - 'app/helpers/projects_helper.rb'
+ - 'app/helpers/reminder_emails_helper.rb'
+ - 'app/models/alert_management/alert.rb'
+ - 'app/models/ci/build_metadata.rb'
+ - 'app/models/concerns/milestoneable.rb'
+ - 'app/models/concerns/mirror_authentication.rb'
+ - 'app/models/concerns/protected_ref_access.rb'
+ - 'app/models/cycle_analytics/project_level_stage_adapter.rb'
+ - 'app/models/merge_request.rb'
+ - 'app/models/pages_domain.rb'
+ - 'app/models/project.rb'
+ - 'app/services/ci/archive_trace_service.rb'
+ - 'app/services/jira_import/start_import_service.rb'
+ - 'app/services/labels/transfer_service.rb'
+ - 'app/services/packages/debian/create_distribution_service.rb'
+ - 'app/services/packages/debian/update_distribution_service.rb'
+ - 'app/services/packages/npm/create_package_service.rb'
+ - 'app/services/personal_access_tokens/revoke_service.rb'
+ - 'app/services/snippets/create_service.rb'
+ - 'app/services/spam/spam_verdict_service.rb'
+ - 'config/initializers/wikicloth_redos_patch.rb'
+ - 'db/post_migrate/20210722042939_update_issuable_slas_where_issue_closed.rb'
+ - 'ee/app/graphql/resolvers/external_issue_resolver.rb'
+ - 'ee/app/helpers/billing_plans_helper.rb'
+ - 'ee/app/helpers/ee/boards_helper.rb'
+ - 'ee/app/models/ee/lfs_object.rb'
+ - 'ee/app/models/ee/merge_request_diff.rb'
+ - 'ee/app/models/ee/pages_deployment.rb'
+ - 'ee/app/models/ee/upload.rb'
+ - 'ee/app/models/requirements_management/requirement.rb'
+ - 'ee/app/models/resource_iteration_event.rb'
+ - 'ee/app/services/compliance_management/frameworks/create_service.rb'
+ - 'ee/app/services/compliance_management/frameworks/destroy_service.rb'
+ - 'ee/app/services/compliance_management/frameworks/update_service.rb'
+ - 'ee/app/services/elastic/cluster_reindexing_service.rb'
+ - 'ee/app/services/namespaces/check_storage_size_service.rb'
+ - 'ee/app/services/sitemap/create_service.rb'
+ - 'ee/lib/ee/gitlab/auth/ldap/access.rb'
+ - 'ee/lib/gitlab/auth/smartcard/session.rb'
+ - 'ee/spec/controllers/admin/licenses_controller_spec.rb'
+ - 'ee/spec/controllers/ee/groups_controller_spec.rb'
+ - 'ee/spec/controllers/groups/analytics/productivity_analytics_controller_spec.rb'
+ - 'ee/spec/controllers/projects/issues_controller_spec.rb'
+ - 'ee/spec/controllers/projects/merge_requests/creations_controller_spec.rb'
+ - 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
+ - 'ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb'
+ - 'ee/spec/controllers/projects/settings/operations_controller_spec.rb'
+ - 'ee/spec/features/account_recovery_regular_check_spec.rb'
+ - 'ee/spec/features/billings/billing_plans_spec.rb'
+ - 'ee/spec/features/boards/board_filters_spec.rb'
+ - 'ee/spec/features/boards/group_boards/board_deletion_spec.rb'
+ - 'ee/spec/features/boards/user_visits_board_spec.rb'
+ - 'ee/spec/features/groups/analytics/ci_cd_analytics_spec.rb'
+ - 'ee/spec/features/groups/issues_spec.rb'
+ - 'ee/spec/features/groups/iteration_spec.rb'
+ - 'ee/spec/features/groups/iterations/user_creates_iteration_in_cadence_spec.rb'
+ - 'ee/spec/features/groups/iterations/user_edits_iteration_cadence_spec.rb'
+ - 'ee/spec/features/groups/iterations/user_edits_iteration_spec.rb'
+ - 'ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_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/merge_trains/two_merge_requests_on_train_spec.rb'
+ - 'ee/spec/finders/ee/alert_management/alerts_finder_spec.rb'
+ - 'ee/spec/finders/ee/alert_management/http_integrations_finder_spec.rb'
+ - 'ee/spec/finders/epics_finder_spec.rb'
+ - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb'
+ - 'ee/spec/frontend/fixtures/analytics/devops_reports/devops_adoption/enabled_namespaces.rb'
+ - 'ee/spec/frontend/fixtures/epic.rb'
+ - 'ee/spec/frontend/fixtures/projects.rb'
+ - 'ee/spec/graphql/ee/resolvers/board_lists_resolver_spec.rb'
+ - 'ee/spec/graphql/mutations/app_sec/fuzzing/coverage/corpus/create_spec.rb'
+ - 'ee/spec/graphql/mutations/dast/profiles/create_spec.rb'
+ - 'ee/spec/graphql/resolvers/epics_resolver_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/drop_invalid_remediations_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/usage_data_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/auth_hash_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/dynamic_settings_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/group_lookup_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/smartcard/ldap_certificate_spec.rb'
+ - 'ee/spec/lib/gitlab/auth_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/cluster_image_scanning_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/coverage_fuzzing_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dast_api_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dast_api_latest_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dast_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dast_latest_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/dast_runner_validation_gitlab_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/templates/secure_binaries_ci_yaml_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/git_ssh_proxy_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/events/event_spec.rb'
+ - 'ee/spec/lib/gitlab/graphql/aggregations/epics/lazy_epic_aggregate_spec.rb'
+ - 'ee/spec/lib/gitlab/status_page/storage/s3_client_spec.rb'
+ - 'ee/spec/mailers/notify_spec.rb'
+ - 'ee/spec/migrations/add_non_null_constraint_for_escalation_rule_on_pending_alert_escalations_spec.rb'
+ - 'ee/spec/migrations/drop_invalid_remediations_spec.rb'
+ - 'ee/spec/models/allowed_email_domain_spec.rb'
+ - 'ee/spec/models/boards/epic_board_position_spec.rb'
+ - 'ee/spec/models/dora/change_failure_rate_metric_spec.rb'
+ - 'ee/spec/models/ee/integrations/jira_spec.rb'
+ - 'ee/spec/models/ee/iteration_spec.rb'
+ - 'ee/spec/models/ee/key_spec.rb'
+ - 'ee/spec/models/ee/system_note_metadata_spec.rb'
+ - 'ee/spec/models/geo/every_geo_event_spec.rb'
+ - 'ee/spec/models/incident_management/escalation_rule_spec.rb'
+ - 'ee/spec/models/ip_restriction_spec.rb'
+ - 'ee/spec/models/issue_spec.rb'
+ - 'ee/spec/models/ldap_group_link_spec.rb'
+ - 'ee/spec/models/license_spec.rb'
+ - 'ee/spec/models/member_spec.rb'
+ - 'ee/spec/models/project_spec.rb'
+ - 'ee/spec/models/release_highlight_spec.rb'
+ - 'ee/spec/models/security/orchestration_policy_configuration_spec.rb'
+ - 'ee/spec/models/vulnerabilities/feedback_spec.rb'
+ - 'ee/spec/requests/api/boards_spec.rb'
+ - 'ee/spec/requests/api/epics_spec.rb'
+ - 'ee/spec/requests/api/graphql/group/epics_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/iterations/update_spec.rb'
+ - 'ee/spec/requests/api/graphql/projects/compliance_frameworks_spec.rb'
+ - 'ee/spec/requests/api/group_boards_spec.rb'
+ - 'ee/spec/requests/api/iterations_spec.rb'
+ - 'ee/spec/requests/api/ldap_group_links_spec.rb'
+ - 'ee/spec/requests/api/project_milestones_spec.rb'
+ - 'ee/spec/requests/customers_dot/proxy_controller_spec.rb'
+ - 'ee/spec/requests/survey_responses_controller_spec.rb'
+ - 'ee/spec/serializers/member_user_entity_spec.rb'
+ - 'ee/spec/services/app_sec/dast/profiles/create_service_spec.rb'
+ - 'ee/spec/services/app_sec/dast/site_profile_secret_variables/create_or_update_service_spec.rb'
+ - 'ee/spec/services/app_sec/dast/site_validations/runner_service_spec.rb'
+ - 'ee/spec/services/app_sec/fuzzing/coverage/corpuses/create_service_spec.rb'
+ - 'ee/spec/services/ci_cd/github_integration_setup_service_spec.rb'
+ - 'ee/spec/services/ci_cd/github_setup_service_spec.rb'
+ - 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
+ - 'ee/spec/services/ee/notification_service_spec.rb'
+ - 'ee/spec/services/ee/users/update_service_spec.rb'
+ - 'ee/spec/services/epic_issues/update_service_spec.rb'
+ - 'ee/spec/services/geo/container_repository_sync_spec.rb'
+ - 'ee/spec/services/geo/replication_toggle_request_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/create_service_spec.rb'
+ - 'ee/spec/services/projects/update_mirror_service_spec.rb'
+ - 'ee/spec/services/search/group_service_spec.rb'
+ - 'ee/spec/services/search/project_service_spec.rb'
+ - 'ee/spec/services/security/merge_reports_service_spec.rb'
+ - 'ee/spec/services/vulnerability_exports/exporters/csv_service_spec.rb'
+ - 'ee/spec/support/shared_examples/services/geo/geo_request_service_shared_examples.rb'
+ - 'ee/spec/workers/elastic/migration_worker_spec.rb'
+ - 'ee/spec/workers/geo/container_repository_sync_dispatch_worker_spec.rb'
+ - 'ee/spec/workers/security/auto_fix_worker_spec.rb'
+ - 'ee/spec/workers/security/create_orchestration_policy_worker_spec.rb'
+ - 'lib/backup/files.rb'
+ - 'lib/gitlab/ci/reports/security/finding.rb'
+ - 'lib/gitlab/ci/runner_instructions.rb'
+ - 'lib/gitlab/database/partitioning/single_numeric_list_partition.rb'
+ - 'lib/gitlab/database/postgres_hll/buckets.rb'
+ - 'lib/gitlab/diff/parser.rb'
+ - 'lib/gitlab/diff/rendered/notebook/diff_file.rb'
+ - 'lib/gitlab/gitaly_client/commit_service.rb'
+ - 'lib/gitlab/prometheus_client.rb'
+ - 'lib/gitlab/sidekiq_daemon/memory_killer.rb'
+ - 'lib/gitlab/tracking/incident_management.rb'
+ - 'lib/gitlab/visibility_level.rb'
+ - 'lib/security/ci_configuration/sast_build_action.rb'
+ - 'qa/qa/page/group/settings/group_deploy_tokens.rb'
+ - 'qa/qa/page/merge_request/show.rb'
+ - 'qa/qa/tools/delete_subgroups.rb'
+ - 'qa/spec/runtime/feature_spec.rb'
+ - 'qa/spec/scenario/template_spec.rb'
+ - 'spec/controllers/boards/issues_controller_spec.rb'
+ - 'spec/controllers/groups/children_controller_spec.rb'
+ - 'spec/controllers/groups/registry/repositories_controller_spec.rb'
+ - 'spec/controllers/groups/releases_controller_spec.rb'
+ - 'spec/controllers/groups/runners_controller_spec.rb'
+ - 'spec/controllers/groups_controller_spec.rb'
+ - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
+ - 'spec/controllers/projects/environments_controller_spec.rb'
+ - 'spec/controllers/projects/issues_controller_spec.rb'
+ - 'spec/controllers/projects/registry/repositories_controller_spec.rb'
+ - 'spec/controllers/projects/runners_controller_spec.rb'
+ - 'spec/dependencies/omniauth_saml_spec.rb'
+ - 'spec/factories/usage_data.rb'
+ - 'spec/features/admin/admin_runners_spec.rb'
+ - 'spec/features/boards/board_filters_spec.rb'
+ - 'spec/features/boards/user_visits_board_spec.rb'
+ - 'spec/features/dashboard/datetime_on_tooltips_spec.rb'
+ - 'spec/features/graphql_known_operations_spec.rb'
+ - 'spec/features/groups/activity_spec.rb'
+ - 'spec/features/groups/board_sidebar_spec.rb'
+ - 'spec/features/groups/empty_states_spec.rb'
+ - 'spec/features/groups/issues_spec.rb'
+ - 'spec/features/groups/milestone_spec.rb'
+ - 'spec/features/groups/milestones_sorting_spec.rb'
+ - 'spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb'
+ - 'spec/features/merge_request/user_edits_assignees_sidebar_spec.rb'
+ - 'spec/features/profiles/two_factor_auths_spec.rb'
+ - 'spec/features/projects/branches/user_views_branches_spec.rb'
+ - 'spec/features/projects/fork_spec.rb'
+ - 'spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb'
+ - 'spec/features/projects/jobs_spec.rb'
+ - 'spec/features/projects/pipeline_schedules_spec.rb'
+ - 'spec/features/projects/releases/user_views_edit_release_spec.rb'
+ - 'spec/features/projects/releases/user_views_releases_spec.rb'
+ - 'spec/finders/alert_management/http_integrations_finder_spec.rb'
+ - 'spec/finders/events_finder_spec.rb'
+ - 'spec/finders/labels_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/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/todos/restore_many_spec.rb'
+ - 'spec/graphql/resolvers/board_list_issues_resolver_spec.rb'
+ - 'spec/graphql/resolvers/board_lists_resolver_spec.rb'
+ - 'spec/graphql/resolvers/board_resolver_spec.rb'
+ - 'spec/graphql/resolvers/boards_resolver_spec.rb'
+ - 'spec/graphql/resolvers/group_packages_resolver_spec.rb'
+ - 'spec/graphql/resolvers/projects_resolver_spec.rb'
+ - 'spec/graphql/resolvers/recent_boards_resolver_spec.rb'
+ - 'spec/graphql/resolvers/users_resolver_spec.rb'
+ - 'spec/helpers/badges_helper_spec.rb'
+ - 'spec/helpers/ci/builds_helper_spec.rb'
+ - 'spec/helpers/ci/runners_helper_spec.rb'
+ - 'spec/helpers/dev_ops_report_helper_spec.rb'
+ - 'spec/helpers/git_helper_spec.rb'
+ - 'spec/helpers/gitlab_routing_helper_spec.rb'
+ - 'spec/helpers/gitlab_script_tag_helper_spec.rb'
+ - 'spec/helpers/tab_helper_spec.rb'
+ - 'spec/initializers/carrierwave_patch_spec.rb'
+ - 'spec/initializers/rdoc_segfault_patch_spec.rb'
+ - 'spec/lib/api/entities/snippet_spec.rb'
+ - 'spec/lib/banzai/filter/references/alert_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/references/feature_flag_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/references/label_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/repository_link_filter_spec.rb'
+ - 'spec/lib/bitbucket_server/representation/comment_spec.rb'
+ - 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb'
+ - 'spec/lib/error_tracking/sentry_client/projects_spec.rb'
+ - 'spec/lib/error_tracking/sentry_client/repo_spec.rb'
+ - 'spec/lib/gitlab/app_text_logger_spec.rb'
+ - 'spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb'
+ - 'spec/lib/gitlab/auth/o_auth/user_spec.rb'
+ - 'spec/lib/gitlab/auth/saml/auth_hash_spec.rb'
+ - 'spec/lib/gitlab/ci/build/image_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/reports_spec.rb'
+ - 'spec/lib/gitlab/ci/config/entry/trigger_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers_spec.rb'
+ - 'spec/lib/gitlab/ci/pipeline/seed/build_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/templates/5_minute_production_app_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/managed_cluster_applications_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/npm_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb'
+ - 'spec/lib/gitlab/database/background_migration/batched_job_spec.rb'
+ - 'spec/lib/gitlab/database/migrations/runner_spec.rb'
+ - 'spec/lib/gitlab/database/reindexing/reindex_concurrently_spec.rb'
+ - 'spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb'
+ - 'spec/lib/gitlab/database_spec.rb'
+ - 'spec/lib/gitlab/diff/highlight_cache_spec.rb'
+ - 'spec/lib/gitlab/exclusive_lease_helpers_spec.rb'
+ - 'spec/lib/gitlab/git/blob_spec.rb'
+ - 'spec/lib/gitlab/git/commit_spec.rb'
+ - 'spec/lib/gitlab/git/diff_spec.rb'
+ - 'spec/lib/gitlab/git/repository_spec.rb'
+ - 'spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb'
+ - 'spec/lib/gitlab/graphql/lazy_spec.rb'
+ - 'spec/lib/gitlab/graphql/markdown_field_spec.rb'
+ - 'spec/lib/gitlab/health_checks/simple_check_shared.rb'
+ - 'spec/lib/gitlab/highlight_spec.rb'
+ - 'spec/lib/gitlab/import_export/attributes_permitter_spec.rb'
+ - 'spec/lib/gitlab/import_export/file_importer_spec.rb'
+ - 'spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb'
+ - 'spec/lib/gitlab/import_export/project/export_task_spec.rb'
+ - 'spec/lib/gitlab/import_export/project/tree_saver_spec.rb'
+ - 'spec/lib/gitlab/issuables_count_for_state_spec.rb'
+ - 'spec/lib/gitlab/kubernetes/rollout_status_spec.rb'
+ - 'spec/lib/gitlab/metrics/dashboard/processor_spec.rb'
+ - 'spec/lib/gitlab/middleware/same_site_cookies_spec.rb'
+ - 'spec/lib/gitlab/puma_logging/json_formatter_spec.rb'
+ - 'spec/lib/gitlab/rack_attack/instrumented_cache_store_spec.rb'
+ - 'spec/lib/gitlab/redis/cache_spec.rb'
+ - 'spec/lib/gitlab/redis/queues_spec.rb'
+ - 'spec/lib/gitlab/redis/shared_state_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing_spec.rb'
+ - 'spec/lib/gitlab/usage/metric_definition_spec.rb'
+ - 'spec/lib/gitlab/usage/metrics/instrumentations/generic_metric_spec.rb'
+ - 'spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb'
+ - 'spec/lib/gitlab/usage_data_spec.rb'
+ - 'spec/lib/gitlab/utils/delegator_override/validator_spec.rb'
+ - 'spec/lib/gitlab/utils/usage_data_spec.rb'
+ - 'spec/lib/security/ci_configuration/container_scanning_build_action_spec.rb'
+ - 'spec/lib/security/ci_configuration/sast_build_action_spec.rb'
+ - 'spec/lib/security/ci_configuration/sast_iac_build_action_spec.rb'
+ - 'spec/lib/security/ci_configuration/secret_detection_build_action_spec.rb'
+ - 'spec/mailers/emails/profile_spec.rb'
+ - 'spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb'
+ - 'spec/migrations/backfill_issues_upvotes_count_spec.rb'
+ - 'spec/migrations/schedule_copy_ci_builds_columns_to_security_scans2_spec.rb'
+ - 'spec/models/ci/build_spec.rb'
+ - 'spec/models/ci/build_trace_spec.rb'
+ - 'spec/models/ci/pipeline_spec.rb'
+ - 'spec/models/ci/trigger_request_spec.rb'
+ - 'spec/models/clusters/applications/prometheus_spec.rb'
+ - 'spec/models/deploy_token_spec.rb'
+ - 'spec/models/environment_spec.rb'
+ - 'spec/models/environment_status_spec.rb'
+ - 'spec/models/experiment_spec.rb'
+ - 'spec/models/exported_protected_branch_spec.rb'
+ - 'spec/models/group_spec.rb'
+ - 'spec/models/integrations/jira_spec.rb'
+ - 'spec/models/member_spec.rb'
+ - 'spec/models/metrics/dashboard/annotation_spec.rb'
+ - 'spec/models/namespace_setting_spec.rb'
+ - 'spec/models/namespace_spec.rb'
+ - 'spec/models/network/graph_spec.rb'
+ - 'spec/models/packages/package_spec.rb'
+ - 'spec/models/project_spec.rb'
+ - 'spec/models/repository_spec.rb'
+ - 'spec/models/users/calloutable_spec.rb'
+ - 'spec/policies/clusters/agent_policy_spec.rb'
+ - 'spec/presenters/ci/build_presenter_spec.rb'
+ - 'spec/presenters/packages/conan/package_presenter_spec.rb'
+ - 'spec/requests/api/boards_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_artifacts_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb'
+ - 'spec/requests/api/ci/runners_reset_registration_token_spec.rb'
+ - 'spec/requests/api/ci/runners_spec.rb'
+ - 'spec/requests/api/dependency_proxy_spec.rb'
+ - 'spec/requests/api/deployments_spec.rb'
+ - 'spec/requests/api/files_spec.rb'
+ - 'spec/requests/api/go_proxy_spec.rb'
+ - 'spec/requests/api/graphql/boards/board_list_issues_query_spec.rb'
+ - 'spec/requests/api/graphql/ci/jobs_spec.rb'
+ - 'spec/requests/api/graphql/ci/pipelines_spec.rb'
+ - 'spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb'
+ - 'spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb'
+ - 'spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb'
+ - 'spec/requests/api/group_boards_spec.rb'
+ - 'spec/requests/api/issues/issues_spec.rb'
+ - 'spec/requests/api/issues/post_projects_issues_spec.rb'
+ - 'spec/requests/api/labels_spec.rb'
+ - 'spec/requests/api/merge_requests_spec.rb'
+ - 'spec/requests/api/pages/pages_spec.rb'
+ - 'spec/requests/api/project_milestones_spec.rb'
+ - 'spec/requests/api/project_snippets_spec.rb'
+ - 'spec/requests/api/snippets_spec.rb'
+ - 'spec/requests/api/submodules_spec.rb'
+ - 'spec/requests/jwt_controller_spec.rb'
+ - 'spec/requests/projects/merge_requests/diffs_spec.rb'
+ - 'spec/requests/projects/merge_requests_spec.rb'
+ - 'spec/requests/projects/releases_controller_spec.rb'
+ - 'spec/requests/search_controller_spec.rb'
+ - 'spec/serializers/analytics_build_entity_spec.rb'
+ - 'spec/serializers/merge_request_user_entity_spec.rb'
+ - 'spec/services/authorized_project_update/project_create_service_spec.rb'
+ - 'spec/services/authorized_project_update/project_group_link_create_service_spec.rb'
+ - 'spec/services/boards/issues/list_service_spec.rb'
+ - 'spec/services/ci/compare_test_reports_service_spec.rb'
+ - 'spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb'
+ - 'spec/services/ci/retry_job_service_spec.rb'
+ - 'spec/services/clusters/gcp/provision_service_spec.rb'
+ - 'spec/services/clusters/gcp/verify_provision_status_service_spec.rb'
+ - 'spec/services/groups/destroy_service_spec.rb'
+ - 'spec/services/groups/update_shared_runners_service_spec.rb'
+ - 'spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb'
+ - 'spec/services/issues/export_csv_service_spec.rb'
+ - 'spec/services/labels/promote_service_spec.rb'
+ - 'spec/services/members/invite_service_spec.rb'
+ - 'spec/services/notes/update_service_spec.rb'
+ - 'spec/services/packages/composer/composer_json_service_spec.rb'
+ - 'spec/services/packages/npm/create_package_service_spec.rb'
+ - 'spec/services/projects/lfs_pointers/lfs_download_service_spec.rb'
+ - 'spec/services/search/group_service_spec.rb'
+ - 'spec/services/security/merge_reports_service_spec.rb'
+ - 'spec/services/suggestions/apply_service_spec.rb'
+ - 'spec/services/system_notes/issuables_service_spec.rb'
+ - 'spec/services/users/destroy_service_spec.rb'
+ - 'spec/services/x509_certificate_revoke_service_spec.rb'
+ - 'spec/support/helpers/database/partitioning_helpers.rb'
+ - 'spec/support/helpers/dependency_proxy_helpers.rb'
+ - 'spec/support/helpers/javascript_fixtures_helpers.rb'
+ - 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb'
+ - 'spec/support/shared_examples/ci/badge_template_shared_examples.rb'
+ - 'spec/support/shared_examples/controllers/destroy_hook_shared_examples.rb'
+ - 'spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb'
+ - 'spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb'
+ - 'spec/support/shared_examples/finders/packages/debian/distributions_finder_shared_examples.rb'
+ - 'spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb'
+ - 'spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb'
+ - 'spec/support/shared_examples/mailers/notify_shared_examples.rb'
+ - 'spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb'
+ - 'spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/releases_shared_examples.rb'
+ - 'spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb'
+ - 'spec/tasks/gitlab/backup_rake_spec.rb'
+ - 'spec/tasks/gitlab/db_rake_spec.rb'
+ - 'spec/validators/devise_email_validator_spec.rb'
+ - 'spec/views/shared/runners/_runner_details.html.haml_spec.rb'
+ - 'spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb'
+ - 'spec/workers/pipeline_schedule_worker_spec.rb'
+ - 'spec/workers/purge_dependency_proxy_cache_worker_spec.rb'
+ - 'spec/workers/releases/manage_evidence_worker_spec.rb'
+ - 'spec/workers/run_pipeline_schedule_worker_spec.rb'
diff --git a/.rubocop_todo/lint/constant_definition_in_block.yml b/.rubocop_todo/lint/constant_definition_in_block.yml
new file mode 100644
index 00000000000..1ffea85dfb0
--- /dev/null
+++ b/.rubocop_todo/lint/constant_definition_in_block.yml
@@ -0,0 +1,53 @@
+---
+Lint/ConstantDefinitionInBlock:
+ # Offense count: 105
+ # Temporarily disabled due to too many offenses
+ Enabled: false
+ Exclude:
+ - 'app/models/concerns/ignorable_columns.rb'
+ - 'app/models/concerns/partitioned_table.rb'
+ - 'app/workers/concerns/worker_context.rb'
+ - 'config/application.rb'
+ - 'config/initializers/direct_upload_support.rb'
+ - 'config/initializers/elastic_client_setup.rb'
+ - 'ee/app/models/concerns/ee/issuable_link.rb'
+ - 'ee/app/models/ee/application_setting.rb'
+ - 'ee/app/models/ee/ci/job_artifact.rb'
+ - 'ee/app/models/ee/ci/pipeline.rb'
+ - 'ee/app/models/ee/epic.rb'
+ - 'ee/app/models/ee/issue.rb'
+ - 'ee/app/models/ee/merge_request_diff.rb'
+ - 'ee/app/models/ee/plan.rb'
+ - 'ee/app/models/ee/project_import_state.rb'
+ - 'ee/app/models/ee/user.rb'
+ - 'ee/app/models/ee/vulnerability.rb'
+ - 'ee/app/presenters/ee/commit_status_presenter.rb'
+ - 'ee/app/services/ee/notes/quick_actions_service.rb'
+ - 'ee/lib/ee/api/search.rb'
+ - 'ee/lib/ee/gitlab/ci/status/build/failed.rb'
+ - 'ee/lib/gitlab/subscription_portal/clients/rest.rb'
+ - 'ee/lib/tasks/geo.rake'
+ - 'ee/spec/db/schema_support.rb'
+ - 'ee/spec/support/matchers/locked_schema.rb'
+ - 'lib/api/search.rb'
+ - 'lib/gitlab/quick_actions/issue_actions.rb'
+ - 'lib/tasks/cache.rake'
+ - 'lib/tasks/dev.rake'
+ - 'lib/tasks/gitlab/docs/compile_deprecations.rake'
+ - 'lib/tasks/gitlab/graphql.rake'
+ - 'lib/tasks/gitlab/refresh_project_statistics_build_artifacts_size.rake'
+ - 'lib/tasks/gitlab/snippets.rake'
+ - 'lib/tasks/gitlab/tw/codeowners.rake'
+ - 'lib/tasks/gitlab/update_templates.rake'
+ - 'lib/tasks/tanuki_emoji.rake'
+ - 'spec/db/schema_spec.rb'
+ - 'spec/lib/gitlab/quick_actions/dsl_spec.rb'
+ - 'spec/lib/marginalia_spec.rb'
+ - 'spec/mailers/notify_spec.rb'
+ - 'spec/models/concerns/batch_destroy_dependent_associations_spec.rb'
+ - 'spec/models/concerns/bulk_insert_safe_spec.rb'
+ - 'spec/models/concerns/bulk_insertable_associations_spec.rb'
+ - 'spec/models/concerns/triggerable_hooks_spec.rb'
+ - 'spec/models/repository_spec.rb'
+ - 'spec/services/clusters/applications/check_installation_progress_service_spec.rb'
+ - 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index 5079da9aa02..abda31679d8 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -24,7 +24,7 @@ $.fn.renderGFM = function renderGFM() {
const mrPopoverElements = this.find('.gfm-merge_request').get();
if (mrPopoverElements.length) {
- import(/* webpackChunkName: 'MrPopoverBundle' */ '../../mr_popover')
+ import(/* webpackChunkName: 'MrPopoverBundle' */ '~/mr_popover')
.then(({ default: initMRPopovers }) => {
initMRPopovers(mrPopoverElements);
})
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
index 16556252a64..6124befd3b6 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
@@ -4,7 +4,7 @@ import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard';
import { getSelectedFragment } from '~/lib/utils/common_utils';
import { isElementVisible } from '~/lib/utils/dom_utils';
import { DEBOUNCE_DROPDOWN_DELAY } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
-import Sidebar from '../../right_sidebar';
+import Sidebar from '~/right_sidebar';
import { CopyAsGFM } from '../markdown/copy_as_gfm';
import {
keysFor,
diff --git a/app/assets/javascripts/blob/pdf/pdf_viewer.vue b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
index a1a62abeb6f..e07e415d6cf 100644
--- a/app/assets/javascripts/blob/pdf/pdf_viewer.vue
+++ b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
-import PdfLab from '../../pdf/index.vue';
+import PdfLab from '~/pdf/index.vue';
export default {
components: {
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index 02b99e86fd3..814ff16efec 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -13,7 +13,7 @@ import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { sprintf, __, n__ } from '~/locale';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { ListType } from '../constants';
import BoardBlockedIcon from './board_blocked_icon.vue';
import IssueDueDate from './issue_due_date.vue';
diff --git a/app/assets/javascripts/code_navigation/components/app.vue b/app/assets/javascripts/code_navigation/components/app.vue
index 5c77f087d63..d65b9a71288 100644
--- a/app/assets/javascripts/code_navigation/components/app.vue
+++ b/app/assets/javascripts/code_navigation/components/app.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions, mapState } from 'vuex';
-import eventHub from '../../notes/event_hub';
+import eventHub from '~/notes/event_hub';
import Popover from './popover.vue';
export default {
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index b63d49da677..075e1b4071e 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -21,7 +21,7 @@ import MrWidgetHowToMergeModal from '~/vue_merge_request_widget/components/mr_wi
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import notesEventHub from '../../notes/event_hub';
+import notesEventHub from '~/notes/event_hub';
import {
TREE_LIST_WIDTH_STORAGE_KEY,
INITIAL_TREE_WIDTH,
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index cd441a613bd..b4bffdcb07f 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -9,9 +9,9 @@ import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import NoPreviewViewer from '~/vue_shared/components/diff_viewer/viewers/no_preview.vue';
import NotDiffableViewer from '~/vue_shared/components/diff_viewer/viewers/not_diffable.vue';
-import NoteForm from '../../notes/components/note_form.vue';
-import eventHub from '../../notes/event_hub';
-import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import NoteForm from '~/notes/components/note_form.vue';
+import eventHub from '~/notes/event_hub';
+import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { IMAGE_DIFF_POSITION_TYPE } from '../constants';
import { getDiffMode } from '../store/utils';
import DiffDiscussions from './diff_discussions.vue';
diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue
index 47a05ce11cc..b39b50c4cdc 100644
--- a/app/assets/javascripts/diffs/components/diff_discussions.vue
+++ b/app/assets/javascripts/diffs/components/diff_discussions.vue
@@ -2,7 +2,7 @@
import { GlIcon } from '@gitlab/ui';
import { mapActions } from 'vuex';
import DesignNotePin from '~/vue_shared/components/design_management/design_note_pin.vue';
-import noteableDiscussion from '../../notes/components/noteable_discussion.vue';
+import noteableDiscussion from '~/notes/components/noteable_discussion.vue';
export default {
components: {
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 4e77bf81c1e..d8f27a967df 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -17,7 +17,7 @@ import { diffViewerErrors } from '~/ide/constants';
import { scrollToElement } from '~/lib/utils/common_utils';
import { sprintf } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import notesEventHub from '../../notes/event_hub';
+import notesEventHub from '~/notes/event_hub';
import {
DIFF_FILE_AUTOMATIC_COLLAPSE,
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index 5ce6037fd9a..7a30740e31b 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -4,13 +4,10 @@ import { s__ } from '~/locale';
import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import MultilineCommentForm from '../../notes/components/multiline_comment_form.vue';
-import {
- commentLineOptions,
- formatLineRange,
-} from '../../notes/components/multiline_comment_utils';
-import noteForm from '../../notes/components/note_form.vue';
-import autosave from '../../notes/mixins/autosave';
+import MultilineCommentForm from '~/notes/components/multiline_comment_form.vue';
+import { commentLineOptions, formatLineRange } from '~/notes/components/multiline_comment_utils';
+import noteForm from '~/notes/components/note_form.vue';
+import autosave from '~/notes/mixins/autosave';
import {
DIFF_NOTE_TYPE,
INLINE_DIFF_LINES_KEY,
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index e967be23f42..7a30dc226a2 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -13,7 +13,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
-import notesEventHub from '../../notes/event_hub';
+import notesEventHub from '~/notes/event_hub';
import {
PARALLEL_DIFF_VIEW_TYPE,
INLINE_DIFF_VIEW_TYPE,
diff --git a/app/assets/javascripts/diffs/utils/performance.js b/app/assets/javascripts/diffs/utils/performance.js
index 50bf17001a6..ad768c333e2 100644
--- a/app/assets/javascripts/diffs/utils/performance.js
+++ b/app/assets/javascripts/diffs/utils/performance.js
@@ -7,7 +7,7 @@ import {
MR_DIFFS_MARK_DIFF_FILES_END,
MR_DIFFS_MEASURE_FILE_TREE_DONE,
MR_DIFFS_MEASURE_DIFF_FILES_DONE,
-} from '../../performance/constants';
+} from '~/performance/constants';
import {
EVT_PERF_MARK_FILE_TREE_START,
diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
index 206381e0b7e..4e5fe511f8a 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
-import Translate from '../../vue_shared/translate';
+import Translate from '~/vue_shared/translate';
import environmentsFolderApp from './environments_folder_view.vue';
Vue.use(Translate);
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index 28ca1b6750f..32f87cb0a92 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -3,8 +3,8 @@
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
import timeAgoMixin from '~/vue_shared/mixins/timeago';
-import CiIcon from '../../vue_shared/components/ci_icon.vue';
-import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { rightSidebarViews } from '../constants';
import IdeStatusList from './ide_status_list.vue';
import IdeStatusMr from './ide_status_mr.vue';
diff --git a/app/assets/javascripts/image_diff/helpers/init_image_diff.js b/app/assets/javascripts/image_diff/helpers/init_image_diff.js
index 51168b94e6d..55e1d802201 100644
--- a/app/assets/javascripts/image_diff/helpers/init_image_diff.js
+++ b/app/assets/javascripts/image_diff/helpers/init_image_diff.js
@@ -1,4 +1,4 @@
-import ImageFile from '../../commit/image_file';
+import ImageFile from '~/commit/image_file';
import ImageDiff from '../image_diff';
import ReplacedImageDiff from '../replaced_image_diff';
diff --git a/app/assets/javascripts/jira_connect/subscriptions/index.js b/app/assets/javascripts/jira_connect/subscriptions/index.js
index 39800ec5067..3b584b5fe98 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/index.js
+++ b/app/assets/javascripts/jira_connect/subscriptions/index.js
@@ -1,4 +1,4 @@
-import '../../webpack';
+import '~/webpack';
import setConfigs from '@gitlab/ui/dist/config';
import Vue from 'vue';
diff --git a/app/assets/javascripts/mr_popover/components/mr_popover.vue b/app/assets/javascripts/mr_popover/components/mr_popover.vue
index d99a3adb358..fef75b6d5d0 100644
--- a/app/assets/javascripts/mr_popover/components/mr_popover.vue
+++ b/app/assets/javascripts/mr_popover/components/mr_popover.vue
@@ -1,8 +1,8 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
import { GlPopover, GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
-import CiIcon from '../../vue_shared/components/ci_icon.vue';
-import timeagoMixin from '../../vue_shared/mixins/timeago';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
import { mrStates, humanMRStates } from '../constants';
import query from '../queries/merge_request.query.graphql';
diff --git a/app/assets/javascripts/notes/components/diff_discussion_header.vue b/app/assets/javascripts/notes/components/diff_discussion_header.vue
index 0ce1eb8191a..45d97f278dc 100644
--- a/app/assets/javascripts/notes/components/diff_discussion_header.vue
+++ b/app/assets/javascripts/notes/components/diff_discussion_header.vue
@@ -6,7 +6,7 @@ import { mapActions } from 'vuex';
import { truncateSha } from '~/lib/utils/text_utility';
import { s__, __, sprintf } from '~/locale';
-import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import noteEditedText from './note_edited_text.vue';
import noteHeader from './note_header.vue';
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index b4f7ba5f960..e2b0c7fee32 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -9,7 +9,7 @@ import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue';
import { getDiffMode } from '~/diffs/store/utils';
import { diffViewerModes } from '~/ide/constants';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
-import { isCollapsed } from '../../diffs/utils/diff_file';
+import { isCollapsed } from '~/diffs/utils/diff_file';
const FIRST_CHAR_REGEX = /^(\+|-| )/;
diff --git a/app/assets/javascripts/notes/components/note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue
index 7c052320c98..03cbdf45ddd 100644
--- a/app/assets/javascripts/notes/components/note_edited_text.vue
+++ b/app/assets/javascripts/notes/components/note_edited_text.vue
@@ -1,6 +1,6 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
-import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
+import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
name: 'EditedNoteText',
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index 044b1103086..11b427b9346 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -8,7 +8,7 @@ import {
import { mapActions } from 'vuex';
import { __, s__ } from '~/locale';
import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import UserNameWithStatus from '../../sidebar/components/assignees/user_name_with_status.vue';
+import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue';
import { NOTEABLE_TYPE_MAPPING } from '../constants';
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index dc980e7cc7e..000eb3bdff3 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -10,7 +10,7 @@ import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
import { s__, __ } from '~/locale';
import diffLineNoteFormMixin from '~/notes/mixins/diff_line_note_form';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
-import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../event_hub';
import noteable from '../mixins/noteable';
import resolvable from '../mixins/resolvable';
diff --git a/app/assets/javascripts/pages/admin/index.js b/app/assets/javascripts/pages/admin/index.js
index f0f85b82e2b..a249864fa36 100644
--- a/app/assets/javascripts/pages/admin/index.js
+++ b/app/assets/javascripts/pages/admin/index.js
@@ -1,6 +1,6 @@
import initGitlabVersionCheck from '~/gitlab_version_check';
-import initAdminStatisticsPanel from '../../admin/statistics_panel/index';
-import initVueAlerts from '../../vue_alerts';
+import initAdminStatisticsPanel from '~/admin/statistics_panel/index';
+import initVueAlerts from '~/vue_alerts';
import initAdmin from './admin';
initVueAlerts();
diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js
index 8ec6e5e66b3..7380055cbbf 100644
--- a/app/assets/javascripts/pages/projects/index.js
+++ b/app/assets/javascripts/pages/projects/index.js
@@ -1,5 +1,5 @@
-import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
-import initTerraformNotification from '../../projects/terraform_notification';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
+import initTerraformNotification from '~/projects/terraform_notification';
import { initSidebarTracking } from '../shared/nav/sidebar_tracking';
import Project from './project';
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 0c17bf2f344..4f57e1308df 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -9,7 +9,7 @@ import axios from '~/lib/utils/axios_utils';
import { serializeForm } from '~/lib/utils/forms';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
-import projectSelect from '../../project_select';
+import projectSelect from '~/project_select';
export default class Project {
constructor() {
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index c3d121505b6..6b5874c1e5b 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -10,10 +10,10 @@ import {
import defaultAvatarUrl from 'images/no_avatar.png';
import pathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
import { sprintf, s__ } from '~/locale';
-import CiIcon from '../../vue_shared/components/ci_icon.vue';
-import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
-import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
-import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import getRefMixin from '../mixins/get_ref';
import projectPathQuery from '../queries/project_path.query.graphql';
diff --git a/app/assets/javascripts/serverless/components/url.vue b/app/assets/javascripts/serverless/components/url.vue
index 79a1f39c7dd..b105f49e475 100644
--- a/app/assets/javascripts/serverless/components/url.vue
+++ b/app/assets/javascripts/serverless/components/url.vue
@@ -1,5 +1,5 @@
<script>
-import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default {
components: {
diff --git a/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue b/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
index 0d8cb8cb2b6..8528ad56ddb 100644
--- a/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
+++ b/app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
@@ -1,5 +1,5 @@
<script>
-import CopyableField from '../../vue_shared/components/sidebar/copyable_field.vue';
+import CopyableField from '~/vue_shared/components/sidebar/copyable_field.vue';
export default {
components: {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index 2e3a02b1712..9499603163b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import ciIcon from '../../vue_shared/components/ci_icon.vue';
+import ciIcon from '~/vue_shared/components/ci_icon.vue';
export default {
components: {
diff --git a/app/assets/javascripts/vue_shared/components/awards_list.vue b/app/assets/javascripts/vue_shared/components/awards_list.vue
index 2bdd2363e11..f5d8811e83c 100644
--- a/app/assets/javascripts/vue_shared/components/awards_list.vue
+++ b/app/assets/javascripts/vue_shared/components/awards_list.vue
@@ -4,7 +4,7 @@ import { groupBy } from 'lodash';
import EmojiPicker from '~/emoji/components/picker.vue';
import { __, sprintf } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { glEmojiTag } from '../../emoji';
+import { glEmojiTag } from '~/emoji';
// Internal constant, specific to this component, used when no `currentUserId` is given
const NO_USER_ID = -1;
diff --git a/app/controllers/groups/releases_controller.rb b/app/controllers/groups/releases_controller.rb
index db5385ecc71..e87135cc104 100644
--- a/app/controllers/groups/releases_controller.rb
+++ b/app/controllers/groups/releases_controller.rb
@@ -17,8 +17,10 @@ module Groups
def releases
if Feature.enabled?(:group_releases_finder_inoperator)
Releases::GroupReleasesFinder
- .new(@group, current_user, { include_subgroups: true, page: params[:page], per: 30 })
+ .new(@group, current_user)
.execute(preload: false)
+ .page(params[:page])
+ .per(30)
else
ReleasesFinder
.new(@group, current_user, { include_subgroups: true })
diff --git a/app/finders/releases/group_releases_finder.rb b/app/finders/releases/group_releases_finder.rb
index 39f44830ff5..8b1b0c552fd 100644
--- a/app/finders/releases/group_releases_finder.rb
+++ b/app/finders/releases/group_releases_finder.rb
@@ -15,10 +15,7 @@ module Releases
@current_user = current_user
@params = params
- params[:order_by] ||= 'released_at'
params[:sort] ||= 'desc'
- params[:page] ||= 0
- params[:per] ||= 30
end
def execute(preload: true)
@@ -26,7 +23,7 @@ module Releases
releases = get_releases
releases.preloaded if preload
- paginate_releases(releases)
+ releases
end
private
@@ -46,9 +43,6 @@ module Releases
Release.sort_by_attribute("released_at_#{params[:sort]}").order(id: params[:sort])
end
- def paginate_releases(releases)
- releases.page(params[:page].to_i).per(params[:per])
- end
# rubocop: enable CodeReuse/ActiveRecord
end
end
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 79c3e3a836b..53a7dbcd094 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -139,6 +139,10 @@ module WikiHelper
api_v4_projects_wikis_path(wiki_page_render_api_endpoint_params(page))
end
+ def wiki_markup_hash_by_name_id
+ Wiki::VALID_USER_MARKUPS.map { |key, value| { value[:name] => key } }.reduce({}, :merge)
+ end
+
private
def wiki_page_render_api_endpoint_params(page)
diff --git a/app/models/ci/namespace_mirror.rb b/app/models/ci/namespace_mirror.rb
index d5cbbb96134..e8f08db597f 100644
--- a/app/models/ci/namespace_mirror.rb
+++ b/app/models/ci/namespace_mirror.rb
@@ -4,6 +4,8 @@ module Ci
# This model represents a record in a shadow table of the main database's namespaces table.
# It allows us to navigate the namespace hierarchy on the ci database without resorting to a JOIN.
class NamespaceMirror < ApplicationRecord
+ include FromUnion
+
belongs_to :namespace
scope :by_group_and_descendants, -> (id) do
@@ -14,6 +16,24 @@ module Ci
where('traversal_ids && ARRAY[?]::int[]', ids)
end
+ scope :contains_traversal_ids, -> (traversal_ids) do
+ mirrors = []
+
+ traversal_ids.group_by(&:count).each do |columns_count, traversal_ids_group|
+ columns = Array.new(columns_count) { |i| "(traversal_ids[#{i + 1}])" }
+ pairs = traversal_ids_group.map do |ids|
+ ids = ids.map { |id| Arel::Nodes.build_quoted(id).to_sql }
+ "(#{ids.join(",")})"
+ end
+
+ # Create condition in format:
+ # ((traversal_ids[1]),(traversal_ids[2])) IN ((1,2),(2,3))
+ mirrors << Ci::NamespaceMirror.where("(#{columns.join(",")}) IN (#{pairs.join(",")})") # rubocop:disable GitlabSecurity/SqlInjection
+ end
+
+ self.from_union(mirrors)
+ end
+
scope :by_namespace_id, -> (namespace_id) { where(namespace_id: namespace_id) }
class << self
diff --git a/app/models/ci/secure_file.rb b/app/models/ci/secure_file.rb
index 18f0093ea41..1509344415d 100644
--- a/app/models/ci/secure_file.rb
+++ b/app/models/ci/secure_file.rb
@@ -16,6 +16,7 @@ module Ci
validates :file, presence: true, file_size: { maximum: FILE_SIZE_LIMIT }
validates :checksum, :file_store, :name, :permissions, :project_id, presence: true
+ after_initialize :generate_key_data
before_validation :assign_checksum
enum permissions: { read_only: 0, read_write: 1, execute: 2 }
@@ -33,5 +34,11 @@ module Ci
def assign_checksum
self.checksum = file.checksum if file.present? && file_changed?
end
+
+ def generate_key_data
+ return if key_data.present?
+
+ self.key_data = SecureRandom.hex(64)
+ end
end
end
diff --git a/app/models/concerns/from_set_operator.rb b/app/models/concerns/from_set_operator.rb
index c6d63631c84..ce3a83e9fa1 100644
--- a/app/models/concerns/from_set_operator.rb
+++ b/app/models/concerns/from_set_operator.rb
@@ -11,7 +11,12 @@ module FromSetOperator
raise "Trying to redefine method '#{method(method_name)}'" if methods.include?(method_name)
define_method(method_name) do |members, remove_duplicates: true, remove_order: true, alias_as: table_name|
- operator_sql = operator.new(members, remove_duplicates: remove_duplicates, remove_order: remove_order).to_sql
+ operator_sql =
+ if members.any?
+ operator.new(members, remove_duplicates: remove_duplicates, remove_order: remove_order).to_sql
+ else
+ where("1=0").to_sql
+ end
from(Arel.sql("(#{operator_sql}) #{alias_as}"))
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 5ebbf39be29..027ea70958c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -2286,17 +2286,20 @@ class User < ApplicationRecord
# to avoid querying descendants since they are already covered
# by ancestor namespaces. If the FF is not available fallback to
# inefficient search: https://gitlab.com/gitlab-org/gitlab/-/issues/336436
- namespace_ids =
- if Feature.enabled?(:use_traversal_ids, default_enabled: :yaml)
- Group.joins(:all_group_members)
- .merge(search_members)
- .shortest_traversal_ids_prefixes
- .map(&:last)
- else
- search_members.pluck(:source_id)
- end
+ unless Feature.enabled?(:use_traversal_ids, default_enabled: :yaml)
+ return Ci::NamespaceMirror.contains_any_of_namespaces(search_members.pluck(:source_id))
+ end
- Ci::NamespaceMirror.contains_any_of_namespaces(namespace_ids)
+ traversal_ids = Group.joins(:all_group_members)
+ .merge(search_members)
+ .shortest_traversal_ids_prefixes
+
+ # Use efficient btree index to perform search
+ if Feature.enabled?(:ci_owned_runners_unnest_index, self, default_enabled: :yaml)
+ Ci::NamespaceMirror.contains_traversal_ids(traversal_ids)
+ else
+ Ci::NamespaceMirror.contains_any_of_namespaces(traversal_ids.map(&:last))
+ end
end
end
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index cb572fb5971..b3f09b20463 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -10,18 +10,45 @@ class Wiki
extend ActiveModel::Naming
MARKUPS = { # rubocop:disable Style/MultilineIfModifier
- 'Markdown' => :markdown,
- 'RDoc' => :rdoc,
- 'AsciiDoc' => :asciidoc,
- 'Org' => :org
+ markdown: {
+ name: 'Markdown',
+ default_extension: :md,
+ created_by_user: true
+ },
+ rdoc: {
+ name: 'RDoc',
+ default_extension: :rdoc,
+ created_by_user: true
+ },
+ asciidoc: {
+ name: 'AsciiDoc',
+ default_extension: :asciidoc,
+ created_by_user: true
+ },
+ org: {
+ name: 'Org',
+ default_extension: :org,
+ created_by_user: true
+ },
+ textile: {
+ name: 'Textile',
+ default_extension: :textile
+ },
+ creole: {
+ name: 'Creole',
+ default_extension: :creole
+ },
+ rest: {
+ name: 'reStructuredText',
+ default_extension: :rst
+ },
+ mediawiki: {
+ name: 'MediaWiki',
+ default_extension: :mediawiki
+ }
}.freeze unless defined?(MARKUPS)
- DEFAULT_MARKUP_EXTENSIONS = { # rubocop:disable Style/MultilineIfModifier
- markdown: 'md',
- rdoc: 'rdoc',
- asciidoc: 'asciidoc',
- org: 'org'
- }.freeze unless defined?(DEFAULT_MARKUP_EXTENSIONS)
+ VALID_USER_MARKUPS = MARKUPS.select { |_, v| v[:created_by_user] }.freeze unless defined?(VALID_USER_MARKUPS)
CouldNotCreateWikiError = Class.new(StandardError)
@@ -355,13 +382,15 @@ class Wiki
end
def with_valid_format(format, &block)
- unless Wiki::MARKUPS.value?(format.to_sym)
+ default_extension = Wiki::VALID_USER_MARKUPS.dig(format.to_sym, :default_extension).to_s
+
+ if default_extension.blank?
@error_message = _('Invalid format selected')
return false
end
- yield Wiki::DEFAULT_MARKUP_EXTENSIONS[format.to_sym]
+ yield default_extension
end
def sluggified_full_path(title, extension)
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index c3ea0e14447..647b4e787c6 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -185,7 +185,7 @@ class WikiPage
# :content - The raw markup content.
# :format - Optional symbol representing the
# content format. Can be any type
- # listed in the Wiki::MARKUPS
+ # listed in the Wiki::VALID_USER_MARKUPS
# Hash.
# :message - Optional commit message to set on
# the new page.
@@ -205,7 +205,7 @@ class WikiPage
# attrs - Hash of attributes to be updated on the page.
# :content - The raw markup content to replace the existing.
# :format - Optional symbol representing the content format.
- # See Wiki::MARKUPS Hash for available formats.
+ # See Wiki::VALID_USER_MARKUPS Hash for available formats.
# :message - Optional commit message to set on the new version.
# :last_commit_sha - Optional last commit sha to validate the page unchanged.
# :title - The Title (optionally including dir) to replace existing title
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index 7fa21a58e44..417680e37cf 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -184,8 +184,9 @@ class EventCreateService
track_event(event_action: :pushed, event_target: Project, author_id: current_user.id)
- if Feature.enabled?(:route_hll_to_snowplow, project, default_enabled: :yaml)
- Gitlab::Tracking.event(self.class.to_s, 'action_active_users_project_repo', namespace: project, user: current_user)
+ namespace = project.namespace
+ if Feature.enabled?(:route_hll_to_snowplow, namespace, default_enabled: :yaml)
+ Gitlab::Tracking.event(self.class.to_s, 'action_active_users_project_repo', namespace: namespace, user: current_user, project: project)
end
Users::LastPushEventService.new(current_user)
diff --git a/app/uploaders/ci/secure_file_uploader.rb b/app/uploaders/ci/secure_file_uploader.rb
index 514d88dd177..8aa624d6b30 100644
--- a/app/uploaders/ci/secure_file_uploader.rb
+++ b/app/uploaders/ci/secure_file_uploader.rb
@@ -10,7 +10,7 @@ module Ci
encrypt(key: :key)
def key
- OpenSSL::HMAC.digest('SHA256', Gitlab::Application.secrets.db_key_base, model.project_id.to_s)
+ Digest::SHA256.digest model.key_data
end
def checksum
diff --git a/app/views/errors/_footer.html.haml b/app/views/errors/_footer.html.haml
index 62bac62c70c..3adde3ef544 100644
--- a/app/views/errors/_footer.html.haml
+++ b/app/views/errors/_footer.html.haml
@@ -4,8 +4,8 @@
= link_to s_('Nav|Home'), root_path
%li
- if current_user
- = link_to s_('Nav|Sign out and sign in with a different account'), '#', id: 'sign_out_link'
- %form{ action: destroy_user_session_path, method: :post, id: 'sign_out_form' }
+ = link_to s_('Nav|Sign out and sign in with a different account'), '#', class: 'js-sign-out-link'
+ %form.js-sign-out-form{ action: destroy_user_session_path, method: :post }
- else
= link_to s_('Nav|Sign In / Register'), new_session_path(:user, redirect_to_referer: 'yes')
%li
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index 57260ccedea..3ddd8c6780f 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -22,8 +22,8 @@
}
// We do not have rails_ujs here, so we're manually making a link trigger a form submit.
- document.getElementById('sign_out_link').addEventListener('click', function(e) {
+ document.querySelector('.js-sign-out-link')?.addEventListener('click', (e) => {
e.preventDefault();
- document.getElementById('sign_out_form').submit();
+ document.querySelector('.js-sign-out-form')?.submit();
});
}());
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index 5330c3aa6d6..905c5779c7d 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -1,5 +1,7 @@
- sort_value = @sort || sort_value_recently_created
-- sort_title = forks_sort_options_hash[sort_value]
+- excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id]
+- created_at = { value: sort_value_created_date, text: sort_title_created_date, href: page_filter_path(sort: sort_value_recently_created, without: excluded_filters) }
+- activity = { value: sort_value_latest_activity, text: sort_title_latest_activity, href: page_filter_path(sort: sort_value_latest_activity, without: excluded_filters) }
.top-area
.nav-text
@@ -14,14 +16,7 @@
.dropdown.gl-display-inline.gl-md-ml-3.issue-sort-dropdown.gl-mt-3.gl-md-mt-0
.btn-group{ role: 'group' }
.btn-group{ role: 'group' }
- %button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'gl-button btn btn-default' }
- = sort_title
- = sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
- %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
- %li
- - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id]
- = sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_recently_created, without: excluded_filters), sort_title)
- = sortable_item(sort_title_latest_activity, page_filter_path(sort: sort_value_latest_activity, without: excluded_filters), sort_title)
+ = gl_redirect_listbox_tag [created_at, activity], @sort
= forks_sort_direction_button(sort_value)
- if current_user && can?(current_user, :fork_project, @project)
diff --git a/app/views/shared/wikis/_form.html.haml b/app/views/shared/wikis/_form.html.haml
index e121725b9af..34bedbd928a 100644
--- a/app/views/shared/wikis/_form.html.haml
+++ b/app/views/shared/wikis/_form.html.haml
@@ -3,4 +3,4 @@
.gl-mt-3
= form_errors(@page, truncate: :title)
-#js-wiki-form{ data: { page_info: page_info.to_json, format_options: Wiki::MARKUPS.to_json } }
+#js-wiki-form{ data: { page_info: page_info.to_json, format_options: wiki_markup_hash_by_name_id.to_json } }
diff --git a/config/feature_flags/development/ci_owned_runners_unnest_index.yml b/config/feature_flags/development/ci_owned_runners_unnest_index.yml
new file mode 100644
index 00000000000..225ec3d5df4
--- /dev/null
+++ b/config/feature_flags/development/ci_owned_runners_unnest_index.yml
@@ -0,0 +1,8 @@
+---
+name: ci_owned_runners_unnest_index
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83843
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357869
+milestone: '14.10'
+type: development
+group: group::sharding
+default_enabled: false
diff --git a/db/migrate/20220324175325_add_key_data_to_secure_files.rb b/db/migrate/20220324175325_add_key_data_to_secure_files.rb
new file mode 100644
index 00000000000..70dfd64be27
--- /dev/null
+++ b/db/migrate/20220324175325_add_key_data_to_secure_files.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddKeyDataToSecureFiles < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ def up
+ unless column_exists? :ci_secure_files, :key_data
+ add_column :ci_secure_files, :key_data, :text
+ end
+
+ add_text_limit :ci_secure_files, :key_data, 128
+ end
+
+ def down
+ remove_column :ci_secure_files, :key_data
+ end
+end
diff --git a/db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb b/db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb
new file mode 100644
index 00000000000..6f5d7b4c71e
--- /dev/null
+++ b/db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AddCiNamespaceMirrorsUnnestIndexOnTraversalIds < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_ci_namespace_mirrors_on_traversal_ids_unnest'
+
+ def up
+ return if index_exists_by_name?(:ci_namespace_mirrors, INDEX_NAME)
+
+ # We add only 4-levels since on average it is not expected that namespaces
+ # will be so granular beyond this point
+ disable_statement_timeout do
+ execute <<-SQL
+ CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON ci_namespace_mirrors
+ USING btree ((traversal_ids[1]), (traversal_ids[2]), (traversal_ids[3]), (traversal_ids[4]))
+ INCLUDE (traversal_ids, namespace_id)
+ SQL
+ end
+ end
+
+ def down
+ remove_concurrent_index_by_name(:ci_namespace_mirrors, INDEX_NAME)
+ end
+end
diff --git a/db/schema_migrations/20220324175325 b/db/schema_migrations/20220324175325
new file mode 100644
index 00000000000..e68c820a8f8
--- /dev/null
+++ b/db/schema_migrations/20220324175325
@@ -0,0 +1 @@
+8f423af68f25fb58374321eb38ff830fc47237005a23a66f61d5b794d519ef58 \ No newline at end of file
diff --git a/db/schema_migrations/20220329110630 b/db/schema_migrations/20220329110630
new file mode 100644
index 00000000000..01087e9bfb2
--- /dev/null
+++ b/db/schema_migrations/20220329110630
@@ -0,0 +1 @@
+47664025bee8b3728411bde53aa597cb962d859402b0504a1962a3e4f117782f \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index fd17f1898e7..f0d55208c0f 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -13038,8 +13038,10 @@ CREATE TABLE ci_secure_files (
name text NOT NULL,
file text NOT NULL,
checksum bytea NOT NULL,
+ key_data text,
CONSTRAINT check_320790634d CHECK ((char_length(file) <= 255)),
- CONSTRAINT check_402c7b4a56 CHECK ((char_length(name) <= 255))
+ CONSTRAINT check_402c7b4a56 CHECK ((char_length(name) <= 255)),
+ CONSTRAINT check_7279b4e293 CHECK ((char_length(key_data) <= 128))
);
CREATE SEQUENCE ci_secure_files_id_seq
@@ -27033,6 +27035,8 @@ CREATE INDEX index_ci_minutes_additional_packs_on_namespace_id_purchase_xid ON c
CREATE UNIQUE INDEX index_ci_namespace_mirrors_on_namespace_id ON ci_namespace_mirrors USING btree (namespace_id);
+CREATE INDEX index_ci_namespace_mirrors_on_traversal_ids_unnest ON ci_namespace_mirrors USING btree ((traversal_ids[1]), (traversal_ids[2]), (traversal_ids[3]), (traversal_ids[4])) INCLUDE (traversal_ids, namespace_id);
+
CREATE UNIQUE INDEX index_ci_namespace_monthly_usages_on_namespace_id_and_date ON ci_namespace_monthly_usages USING btree (namespace_id, date);
CREATE INDEX index_ci_pending_builds_id_on_protected_partial ON ci_pending_builds USING btree (id) WHERE (protected = true);
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index bd503c63059..fbd7915b8ad 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -24,7 +24,7 @@ full list of reference architectures, see
| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| PostgreSQL<sup>1</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
-| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | `c5.large` | `F2s v2` |
+| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| Gitaly<sup>5</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` | `D32s v3` |
@@ -86,7 +86,7 @@ card "Database" as database {
card "redis" as redis {
collections "**Redis Persistent** x3" as redis_persistent #FF6347
collections "**Redis Cache** x3" as redis_cache #FF6347
-
+
redis_cache -[hidden]-> redis_persistent
}
@@ -2358,7 +2358,7 @@ card "Database" as database {
card "redis" as redis {
collections "**Redis Persistent** x3" as redis_persistent #FF6347
collections "**Redis Cache** x3" as redis_cache #FF6347
-
+
redis_cache -[hidden]-> redis_persistent
}
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 2548a6443bd..6db37ac1546 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -236,57 +236,57 @@ table.test-coverage th {
<th scope="row">1k</th>
<td><a href="https://cloud.google.com/products/calculator#id=a6d6a94a-c7dc-4c22-85c4-7c5747f272ed">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=b51f178f4403b69a63f6eb33ea425f82de3bf249">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/1adf30bef7e34ceba9efa97c4470417b">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">2k</th>
<td><a href="https://cloud.google.com/products/calculator#id=84d11491-d72a-493c-a16e-650931faa658">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=dce36b5cb6ab25211f74e47233d77f58fefb54e2">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/72764902f3854f798407fb03c3de4b6f">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">3k</th>
<td><a href="https://cloud.google.com/products/calculator/#id=ac4838e6-9c40-4a36-ac43-6d1bc1843e08">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=b1c5b4e32e990eaeb035a148255132bd28988760">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/0dbfc575051943b9970e5d8ace03680d">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">5k</th>
<td><a href="https://cloud.google.com/products/calculator/#id=8742e8ea-c08f-4e0a-b058-02f3a1c38a2f">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=2bf1af883096e6f4c6efddb4f3c35febead7fec2">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/8f618711ffec4b039f1581871ca6a7c9">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">10k</th>
<td><a href="https://cloud.google.com/products/calculator#id=e77713f6-dc0b-4bb3-bcef-cea904ac8efd">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=1d374df13c0f2088d332ab0134f5b1d0f717259e">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/de3da8286dda4d4db1362932bc75410b">Calculated cost</a></td>
</tr>
<tr>
<th scope="row">25k</th>
<td><a href="https://cloud.google.com/products/calculator#id=925386e1-c01c-4c0a-8d7d-ebde1824b7b0">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=46fe6a6e9256d9b7779fae59fbbfa7e836942b7d">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/69724ebd82914a60857da6a3ace05a64">Calculate cost</a></td>
</tr>
<tr>
<th scope="row">50k</th>
<td><a href="https://cloud.google.com/products/calculator/#id=8006396b-88ee-40cd-a1c8-77cdefa4d3c8">Calculated cost</a></td>
<td></td>
+ <td><a href="https://calculator.aws/#/estimate?id=e15926b1a3c7139e4faf390a3875ff807d2ab91c">Calculated cost</a></td>
<td></td>
- <td></td>
- <td></td>
+ <td><a href="https://azure.com/e/3f973040ebc14023933d35f576c89846">Calculated cost</a></td>
</tr>
</table>
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index 2a538fd037e..1981cd83f97 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -114,6 +114,7 @@ The following API resources are available in the group context:
| [Group labels](group_labels.md) | `/groups/:id/labels` |
| [Group-level variables](group_level_variables.md) | `/groups/:id/variables` |
| [Group milestones](group_milestones.md) | `/groups/:id/milestones` |
+| [Group releases](group_releases.md) | `/groups/:id/releases`|
| [Group wikis](group_wikis.md) **(PREMIUM)** | `/groups/:id/wikis` |
| [Invitations](invitations.md) | `/groups/:id/invitations` (also available for projects) |
| [Issues](issues.md) | `/groups/:id/issues` (also available for projects and standalone) |
diff --git a/doc/api/group_releases.md b/doc/api/group_releases.md
new file mode 100644
index 00000000000..06ce55b7d48
--- /dev/null
+++ b/doc/api/group_releases.md
@@ -0,0 +1,77 @@
+---
+stage: Release
+group: Release
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Group releases API **(FREE)**
+
+Review your groups' [releases](../user/project/releases/index.md) with the REST API.
+
+NOTE:
+For information about the project releases API, visit the [Releases API](releases/index.md) page.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `group_releases_finder_inoperator`.
+
+## List group releases
+
+Returns a list of group releases.
+
+```plaintext
+GET /groups/:id/releases
+GET /groups/:id/releases?simple=true
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+|---------------------|----------------|----------|---------------------------------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `sort` | string | no | The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order. |
+| `simple` | boolean | no | Return only limited fields for each release. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/releases"
+```
+
+Example response:
+
+```json
+[
+ {
+ "name": "standard release",
+ "tag_name": "releasetag",
+ "description": "",
+ "created_at": "2022-01-10T15:23:15.529Z",
+ "released_at": "2022-01-10T15:23:15.529Z",
+ "author": {
+ "id": 1,
+ "username": "root",
+ "name": "Administrator",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "https://gitlab.com/root"
+ },
+ "commit": {
+ "id": "e8cbb845ae5a53a2fef2938cf63cf82efc10d993",
+ "short_id": "e8cbb845",
+ "created_at": "2022-01-10T15:20:29.000+00:00",
+ "parent_ids": [],
+ "title": "Update test",
+ "message": "Update test",
+ "author_name": "Administrator",
+ "author_email": "admin@example.com",
+ "authored_date": "2022-01-10T15:20:29.000+00:00",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
+ "committed_date": "2022-01-10T15:20:29.000+00:00",
+ "trailers": {},
+ "web_url": "https://gitlab.com/groups/gitlab-org/-/commit/e8cbb845ae5a53a2fef2938cf63cf82efc10d993"
+ },
+ "upcoming_release": false,
+ "commit_path": "/testgroup/test/-/commit/e8cbb845ae5a53a2fef2938cf63cf82efc10d993",
+ "tag_path": "/testgroup/test/-/tags/testtag"
+ }
+]
+```
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index c603be9489c..c7b11c7959f 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -241,10 +241,10 @@ Get a Release for the given tag.
GET /projects/:id/releases/:tag_name
```
-| Attribute | Type | Required | Description |
-| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../index.md#namespaced-path-encoding). |
-| `tag_name` | string | yes | The Git tag the release is associated with. |
+| Attribute | Type | Required | Description |
+|----------------------------| -------------- | -------- | ----------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../index.md#namespaced-path-encoding). |
+| `tag_name` | string | yes | The Git tag the release is associated with. |
| `include_html_description` | boolean | no | If `true`, a response includes HTML rendered Markdown of the release description. |
Example request:
diff --git a/doc/architecture/blueprints/container_registry_metadata_database/index.md b/doc/architecture/blueprints/container_registry_metadata_database/index.md
index ba0bee04f35..963977be549 100644
--- a/doc/architecture/blueprints/container_registry_metadata_database/index.md
+++ b/doc/architecture/blueprints/container_registry_metadata_database/index.md
@@ -150,7 +150,7 @@ Following the GitLab [Go standards and style guidelines](../../../development/go
The design and development of the registry database adhere to the GitLab [database guidelines](../../../development/database/). Being a Go application, the required tooling to support the database will have to be developed, such as for running database migrations.
-Running *online* and [*post deployment*](../../../development/post_deployment_migrations.md) migrations is already supported by the registry CLI, as described in the [documentation](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/database-migrations.md).
+Running *online* and [*post deployment*](../../../development/database/post_deployment_migrations.md) migrations is already supported by the registry CLI, as described in the [documentation](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/database-migrations.md).
#### Partitioning
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 99c01039f76..8dfedc07077 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -615,9 +615,9 @@ Enterprise Edition instance. This has some implications:
migration on the staging environment if you aren't sure.
1. Categorized correctly:
- Regular migrations run before the new code is running on the instance.
- - [Post-deployment migrations](post_deployment_migrations.md) run _after_
+ - [Post-deployment migrations](database/post_deployment_migrations.md) run _after_
the new code is deployed, when the instance is configured to do that.
- - [Background migrations](background_migrations.md) run in Sidekiq, and
+ - [Background migrations](database/background_migrations.md) run in Sidekiq, and
should only be done for migrations that would take an extreme amount of
time at GitLab.com scale.
1. **Sidekiq workers** [cannot change in a backwards-incompatible way](sidekiq/compatibility_across_updates.md):
diff --git a/doc/development/database/add_foreign_key_to_existing_column.md b/doc/development/database/add_foreign_key_to_existing_column.md
index d74f826cc14..bfd455ef9da 100644
--- a/doc/development/database/add_foreign_key_to_existing_column.md
+++ b/doc/development/database/add_foreign_key_to_existing_column.md
@@ -123,7 +123,7 @@ end
Validating the foreign key scans the whole table and makes sure that each relation is correct.
NOTE:
-When using [background migrations](../background_migrations.md), foreign key validation should happen in the next GitLab release.
+When using [background migrations](background_migrations.md), foreign key validation should happen in the next GitLab release.
Migration file for validating the foreign key:
diff --git a/doc/development/avoiding_downtime_in_migrations.md b/doc/development/database/avoiding_downtime_in_migrations.md
index 1de96df327c..ad2768397e6 100644
--- a/doc/development/avoiding_downtime_in_migrations.md
+++ b/doc/development/database/avoiding_downtime_in_migrations.md
@@ -151,9 +151,9 @@ the whole column type.
You can check the following guides for each specific use case:
-- [Adding foreign-key constraints](migration_style_guide.md#adding-foreign-key-constraints)
-- [Adding `NOT NULL` constraints](database/not_null_constraints.md)
-- [Adding limits to text columns](database/strings_and_the_text_data_type.md)
+- [Adding foreign-key constraints](../migration_style_guide.md#adding-foreign-key-constraints)
+- [Adding `NOT NULL` constraints](not_null_constraints.md)
+- [Adding limits to text columns](strings_and_the_text_data_type.md)
## Changing Column Types
@@ -240,7 +240,7 @@ migrations](background_migrations.md#cleaning-up).
Adding indexes does not require downtime when `add_concurrent_index`
is used.
-See also [Migration Style Guide](migration_style_guide.md#adding-indexes)
+See also [Migration Style Guide](../migration_style_guide.md#adding-indexes)
for more information.
## Dropping Indexes
@@ -265,7 +265,7 @@ If the table and the ActiveRecord model is not in use yet, removing the old
table and creating a new one is the preferred way to "rename" the table.
Renaming a table is possible without downtime by following our multi-release
-[rename table process](database/rename_database_tables.md#rename-table-without-downtime).
+[rename table process](rename_database_tables.md#rename-table-without-downtime).
## Adding Foreign Keys
@@ -355,7 +355,7 @@ Check how the migration is performing while it's running. Multiple ways to do th
#### High-level status of batched background migrations
-See how to [check the status of batched background migrations](../update/index.md#checking-for-background-migrations-before-upgrading).
+See how to [check the status of batched background migrations](../../update/index.md#checking-for-background-migrations-before-upgrading).
#### Query the database
diff --git a/doc/development/background_migrations.md b/doc/development/database/background_migrations.md
index 95eeffd77e2..a982b76ccf7 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/database/background_migrations.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Background migrations
Background migrations should be used to perform data migrations whenever a
-migration exceeds [the time limits in our guidelines](migration_style_guide.md#how-long-a-migration-should-take). For example, you can use background
+migration exceeds [the time limits in our guidelines](../migration_style_guide.md#how-long-a-migration-should-take). For example, you can use background
migrations to migrate data that's stored in a single JSON column
to a separate table instead.
@@ -17,9 +17,9 @@ migrations automatically reschedule themselves for a later point in time.
## When To Use Background Migrations
You should use a background migration when you migrate _data_ in tables that have
-so many rows that the process would exceed [the time limits in our guidelines](migration_style_guide.md#how-long-a-migration-should-take) if performed using a regular Rails migration.
+so many rows that the process would exceed [the time limits in our guidelines](../migration_style_guide.md#how-long-a-migration-should-take) if performed using a regular Rails migration.
-- Background migrations should be used when migrating data in [high-traffic tables](migration_style_guide.md#high-traffic-tables).
+- Background migrations should be used when migrating data in [high-traffic tables](../migration_style_guide.md#high-traffic-tables).
- Background migrations may also be used when executing numerous single-row queries
for every item on a large dataset. Typically, for single-record patterns, runtime is
largely dependent on the size of the dataset, hence it should be split accordingly
@@ -63,7 +63,7 @@ integrity is guaranteed.
All the background migration classes for EE-only features should be present in GitLab CE.
For this purpose, an empty class can be created for GitLab CE, and it can be extended for GitLab EE
-as explained in the [guidelines for implementing Enterprise Edition features](ee_features.md#code-in-libgitlabbackground_migration).
+as explained in the [guidelines for implementing Enterprise Edition features](../ee_features.md#code-in-libgitlabbackground_migration).
## How It Works
@@ -168,7 +168,7 @@ roughly be as follows:
the `delete_tracking_jobs: false` parameter.
1. Remove the old column.
-This may also require a bump to the [import/export version](../user/project/settings/import_export.md), if
+This may also require a bump to the [import/export version](../../user/project/settings/import_export.md), if
importing a project from a prior version of GitLab requires the data to be in
the new format.
@@ -298,7 +298,7 @@ It is required to write tests for:
The `:migration` and `schema: :latest` RSpec tags are automatically set for
background migration specs.
See the
-[Testing Rails migrations](testing_guide/testing_migrations_guide.md#testing-a-non-activerecordmigration-class)
+[Testing Rails migrations](../testing_guide/testing_migrations_guide.md#testing-a-non-activerecordmigration-class)
style guide.
Keep in mind that `before` and `after` RSpec hooks are going
@@ -359,9 +359,9 @@ A strategy to make the migration run faster is to schedule larger batches, and t
within the background migration to perform multiple statements.
The background migration helpers that queue multiple jobs such as
-`queue_background_migration_jobs_by_range_at_intervals` use [`EachBatch`](iterating_tables_in_batches.md).
+`queue_background_migration_jobs_by_range_at_intervals` use [`EachBatch`](../iterating_tables_in_batches.md).
The example above has batches of 1000, where each queued job takes two seconds. If the query has been optimized
-to make the time for the delete statement within the [query performance guidelines](query_performance.md),
+to make the time for the delete statement within the [query performance guidelines](../query_performance.md),
1000 may be the largest number of records that can be deleted in a reasonable amount of time.
The minimum and most common interval for delaying jobs is two minutes. This results in two seconds
diff --git a/doc/development/database/database_reviewer_guidelines.md b/doc/development/database/database_reviewer_guidelines.md
index 9d5e4821c9f..ca9ca36b156 100644
--- a/doc/development/database/database_reviewer_guidelines.md
+++ b/doc/development/database/database_reviewer_guidelines.md
@@ -70,7 +70,7 @@ Finally, you can find various guides in the [Database guides](index.md) page tha
topics and use cases. The most frequently required during database reviewing are the following:
- [Migrations style guide](../migration_style_guide.md) for creating safe SQL migrations.
-- [Avoiding downtime in migrations](../avoiding_downtime_in_migrations.md).
+- [Avoiding downtime in migrations](avoiding_downtime_in_migrations.md).
- [SQL guidelines](../sql.md) for working with SQL queries.
- [Guidelines for JiHu contributions with database migrations](https://about.gitlab.com/handbook/ceo/chief-of-staff-team/jihu-support/jihu-database-change-process.html)
diff --git a/doc/development/deleting_migrations.md b/doc/development/database/deleting_migrations.md
index be9009f365d..be9009f365d 100644
--- a/doc/development/deleting_migrations.md
+++ b/doc/development/database/deleting_migrations.md
diff --git a/doc/development/database/index.md b/doc/development/database/index.md
index 830e97ec533..1dc40e62840 100644
--- a/doc/development/database/index.md
+++ b/doc/development/database/index.md
@@ -23,14 +23,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Migrations
-- [Avoiding downtime in migrations](../avoiding_downtime_in_migrations.md)
+- [Avoiding downtime in migrations](avoiding_downtime_in_migrations.md)
- [SQL guidelines](../sql.md) for working with SQL queries
- [Migrations style guide](../migration_style_guide.md) for creating safe SQL migrations
- [Testing Rails migrations](../testing_guide/testing_migrations_guide.md) guide
-- [Post deployment migrations](../post_deployment_migrations.md)
-- [Background migrations](../background_migrations.md)
+- [Post deployment migrations](post_deployment_migrations.md)
+- [Background migrations](background_migrations.md)
- [Swapping tables](../swapping_tables.md)
-- [Deleting migrations](../deleting_migrations.md)
+- [Deleting migrations](deleting_migrations.md)
- [Partitioning tables](table_partitioning.md)
## Debugging
diff --git a/doc/development/database/loose_foreign_keys.md b/doc/development/database/loose_foreign_keys.md
index 2d3812ec584..2bcdc91202a 100644
--- a/doc/development/database/loose_foreign_keys.md
+++ b/doc/development/database/loose_foreign_keys.md
@@ -191,7 +191,7 @@ ci_pipelines:
### Track record changes
To know about deletions in the `projects` table, configure a `DELETE` trigger
-using a [post-deployment migration](../post_deployment_migrations.md). The
+using a [post-deployment migration](post_deployment_migrations.md). The
trigger needs to be configured only once. If the model already has at least one
`loose_foreign_key` definition, then this step can be skipped:
@@ -226,7 +226,7 @@ ON DELETE CASCADE;
The migration must run after the `DELETE` trigger is installed and the loose
foreign key definition is deployed. As such, it must be a [post-deployment
-migration](../post_deployment_migrations.md) dated after the migration for the
+migration](post_deployment_migrations.md) dated after the migration for the
trigger. If the foreign key is deleted earlier, there is a good chance of
introducing data inconsistency which needs manual cleanup:
diff --git a/doc/development/database/not_null_constraints.md b/doc/development/database/not_null_constraints.md
index de070f7e434..af7d569e282 100644
--- a/doc/development/database/not_null_constraints.md
+++ b/doc/development/database/not_null_constraints.md
@@ -197,7 +197,7 @@ end
If you have to clean up a nullable column for a [high-traffic table](../migration_style_guide.md#high-traffic-tables)
(for example, the `artifacts` in `ci_builds`), your background migration will go on for a while and
-it will need an additional [background migration cleaning up](../background_migrations.md#cleaning-up)
+it will need an additional [background migration cleaning up](background_migrations.md#cleaning-up)
in the release after adding the data migration.
In that rare case you will need 3 releases end-to-end:
diff --git a/doc/development/post_deployment_migrations.md b/doc/development/database/post_deployment_migrations.md
index 799eefdb875..799eefdb875 100644
--- a/doc/development/post_deployment_migrations.md
+++ b/doc/development/database/post_deployment_migrations.md
diff --git a/doc/development/database/rename_database_tables.md b/doc/development/database/rename_database_tables.md
index 881adf00ad0..7a76c028042 100644
--- a/doc/development/database/rename_database_tables.md
+++ b/doc/development/database/rename_database_tables.md
@@ -82,7 +82,7 @@ when naming indexes, so there is a possibility that not all indexes are properly
the migration locally, check if there are inconsistently named indexes (`db/structure.sql`). Those can be
renamed manually in a separate migration, which can be also part of the release M.N+1.
- Foreign key columns might still contain the old table name. For smaller tables, follow our [standard column
-rename process](../avoiding_downtime_in_migrations.md#renaming-columns)
+rename process](avoiding_downtime_in_migrations.md#renaming-columns)
- Avoid renaming database tables which are using with triggers.
- Table modifications (add or remove columns) are not allowed during the rename process, please make sure that all changes to the table happen before the rename migration is started (or in the next release).
- As the index names might change, verify that the model does not use bulk insert
diff --git a/doc/development/database/strings_and_the_text_data_type.md b/doc/development/database/strings_and_the_text_data_type.md
index 9674deb4603..4ed7cf1b4de 100644
--- a/doc/development/database/strings_and_the_text_data_type.md
+++ b/doc/development/database/strings_and_the_text_data_type.md
@@ -229,7 +229,7 @@ end
To keep this guide short, we skipped the definition of the background migration and only
provided a high level example of the post-deployment migration that is used to schedule the batches.
-You can find more information on the guide about [background migrations](../background_migrations.md)
+You can find more information on the guide about [background migrations](background_migrations.md)
#### Validate the text limit (next release)
@@ -277,7 +277,7 @@ end
If you have to clean up a text column for a really [large table](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3)
(for example, the `artifacts` in `ci_builds`), your background migration will go on for a while and
-it will need an additional [background migration cleaning up](../background_migrations.md#cleaning-up)
+it will need an additional [background migration cleaning up](background_migrations.md#cleaning-up)
in the release after adding the data migration.
In that rare case you will need 3 releases end-to-end:
diff --git a/doc/development/database/table_partitioning.md b/doc/development/database/table_partitioning.md
index 5319c73aad0..ec768136404 100644
--- a/doc/development/database/table_partitioning.md
+++ b/doc/development/database/table_partitioning.md
@@ -214,7 +214,7 @@ end
```
This step uses the same mechanism as any background migration, so you
-may want to read the [Background Migration](../background_migrations.md)
+may want to read the [Background Migration](background_migrations.md)
guide for details on that process. Background jobs are scheduled every
2 minutes and copy `50_000` records at a time, which can be used to
estimate the timing of the background migration portion of the
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 069d8e477fe..fd0e2e17623 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -125,7 +125,7 @@ the following preparations into account.
test its execution using `CREATE INDEX CONCURRENTLY` in the `#database-lab` Slack channel and add the execution time to the MR description:
- Execution time largely varies between `#database-lab` and GitLab.com, but an elevated execution time from `#database-lab`
can give a hint that the execution on GitLab.com will also be considerably high.
- - If the execution from `#database-lab` is longer than `1h`, the index should be moved to a [post-migration](post_deployment_migrations.md).
+ - If the execution from `#database-lab` is longer than `1h`, the index should be moved to a [post-migration](database/post_deployment_migrations.md).
Keep in mind that in this case you may need to split the migration and the application changes in separate releases to ensure the index
will be in place when the code that needs it will be deployed.
- Manually trigger the [database testing](database/database_migration_pipeline.md) job (`db:gitlabcom-database-testing`) in the `test` stage.
@@ -212,7 +212,7 @@ Include in the MR description:
#### Preparation when removing columns, tables, indexes, or other structures
-- Follow the [guidelines on dropping columns](avoiding_downtime_in_migrations.md#dropping-columns).
+- Follow the [guidelines on dropping columns](database/avoiding_downtime_in_migrations.md#dropping-columns).
- Generally it's best practice (but not a hard rule) to remove indexes and foreign keys in a post-deployment migration.
- Exceptions include removing indexes and foreign keys for small tables.
- If you're adding a composite index, another index might become redundant, so remove that in the same migration.
@@ -236,8 +236,8 @@ Include in the MR description:
- Check that the relevant version files under `db/schema_migrations` were added or removed.
- Check queries timing (If any): In a single transaction, cumulative query time executed in a migration
needs to fit comfortably within `15s` - preferably much less than that - on GitLab.com.
- - For column removals, make sure the column has been [ignored in a previous release](avoiding_downtime_in_migrations.md#dropping-columns)
-- Check [background migrations](background_migrations.md):
+ - For column removals, make sure the column has been [ignored in a previous release](database/avoiding_downtime_in_migrations.md#dropping-columns)
+- Check [background migrations](database/background_migrations.md):
- Establish a time estimate for execution on GitLab.com. For historical purposes,
it's highly recommended to include this estimation on the merge request description.
- If a single `update` is below than `1s` the query can be placed
@@ -250,7 +250,7 @@ Include in the MR description:
it's suggested to treat background migrations as post migrations:
place them in `db/post_migrate` instead of `db/migrate`. Keep in mind
that post migrations are executed post-deployment in production.
- - If a migration [has tracking enabled](background_migrations.md#background-jobs-tracking),
+ - If a migration [has tracking enabled](database/background_migrations.md#background-jobs-tracking),
ensure `mark_all_as_succeeded` is called even if no work is done.
- Check [timing guidelines for migrations](migration_style_guide.md#how-long-a-migration-should-take)
- Check migrations are reversible and implement a `#down` method
diff --git a/doc/development/iterating_tables_in_batches.md b/doc/development/iterating_tables_in_batches.md
index 38cdbdf5b79..8813fe560db 100644
--- a/doc/development/iterating_tables_in_batches.md
+++ b/doc/development/iterating_tables_in_batches.md
@@ -93,7 +93,7 @@ falling into an endless loop as described in following
When dealing with data migrations the preferred way to iterate over a large volume of data is using
`EachBatch`.
-A special case of data migration is a [background migration](background_migrations.md#scheduling)
+A special case of data migration is a [background migration](database/background_migrations.md#scheduling)
where the actual data modification is executed in a background job. The migration code that
determines the data ranges (slices) and schedules the background jobs uses `each_batch`.
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index 40f02f4fb6f..fe8e730d64e 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -16,7 +16,7 @@ with and agreed upon by backend maintainers and performance specialists.
It's also highly recommended that you read the following guides:
- [Performance Guidelines](performance.md)
-- [Avoiding downtime in migrations](avoiding_downtime_in_migrations.md)
+- [Avoiding downtime in migrations](database/avoiding_downtime_in_migrations.md)
## Definition
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index d85b7372814..1d010fa6ee6 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -45,14 +45,14 @@ work it needs to perform and how long it takes to complete:
One exception is a migration that takes longer but is absolutely critical for the application to operate correctly.
For example, you might have indices that enforce unique tuples, or that are needed for query performance in critical parts of the application. In cases where the migration would be unacceptably slow, however, a better option might be to guard the feature with a [feature flag](feature_flags/index.md)
and perform a post-deployment migration instead. The feature can then be turned on after the migration finishes.
-1. [**Post-deployment migrations.**](post_deployment_migrations.md) These are Rails migrations in `db/post_migrate` and
+1. [**Post-deployment migrations.**](database/post_deployment_migrations.md) These are Rails migrations in `db/post_migrate` and
run _after_ new application code has been deployed (for GitLab.com after the production deployment has finished).
They can be used for schema changes that aren't critical for the application to operate, or data migrations that take at most a few minutes.
Common examples for schema changes that should run post-deploy include:
- Clean-ups, like removing unused columns.
- Adding non-critical indices on high-traffic tables.
- Adding non-critical indices that take a long time to create.
-1. [**Background migrations.**](background_migrations.md) These aren't regular Rails migrations, but application code that is
+1. [**Background migrations.**](database/background_migrations.md) These aren't regular Rails migrations, but application code that is
executed via Sidekiq jobs, although a post-deployment migration is used to schedule them. Use them only for data migrations that
exceed the timing guidelines for post-deploy migrations. Background migrations should _not_ change the schema.
@@ -129,13 +129,13 @@ TARGET=12-9-stable-ee scripts/regenerate-schema
## Avoiding downtime
-The document ["Avoiding downtime in migrations"](avoiding_downtime_in_migrations.md) specifies
+The document ["Avoiding downtime in migrations"](database/avoiding_downtime_in_migrations.md) specifies
various database operations, such as:
-- [dropping and renaming columns](avoiding_downtime_in_migrations.md#dropping-columns)
-- [changing column constraints and types](avoiding_downtime_in_migrations.md#changing-column-constraints)
-- [adding and dropping indexes, tables, and foreign keys](avoiding_downtime_in_migrations.md#adding-indexes)
-- [migrating `integer` primary keys to `bigint`](avoiding_downtime_in_migrations.md#migrating-integer-primary-keys-to-bigint)
+- [dropping and renaming columns](database/avoiding_downtime_in_migrations.md#dropping-columns)
+- [changing column constraints and types](database/avoiding_downtime_in_migrations.md#changing-column-constraints)
+- [adding and dropping indexes, tables, and foreign keys](database/avoiding_downtime_in_migrations.md#adding-indexes)
+- [migrating `integer` primary keys to `bigint`](database/avoiding_downtime_in_migrations.md#migrating-integer-primary-keys-to-bigint)
and explains how to perform them without requiring downtime.
@@ -219,7 +219,7 @@ in that limit. Singular query timings should fit within the [standard limit](que
In case you need to insert, update, or delete a significant amount of data, you:
- Must disable the single transaction with `disable_ddl_transaction!`.
-- Should consider doing it in a [Background Migration](background_migrations.md).
+- Should consider doing it in a [Background Migration](database/background_migrations.md).
## Migration helpers and versioning
@@ -1114,7 +1114,7 @@ by an integer. For example: `users` would turn into `users0`
## Using models in migrations (discouraged)
The use of models in migrations is generally discouraged. As such models are
-[contraindicated for background migrations](background_migrations.md#isolation),
+[contraindicated for background migrations](database/background_migrations.md#isolation),
the model needs to be declared in the migration.
If using a model in the migrations, you should first
diff --git a/doc/development/scalability.md b/doc/development/scalability.md
index fe7063be0e8..4450df0399d 100644
--- a/doc/development/scalability.md
+++ b/doc/development/scalability.md
@@ -36,7 +36,7 @@ application starts, Rails queries the database schema, caching the tables and
column types for the data requested. Because of this schema cache, dropping a
column or table while the application is running can produce 500 errors to the
user. This is why we have a [process for dropping columns and other
-no-downtime changes](avoiding_downtime_in_migrations.md).
+no-downtime changes](database/avoiding_downtime_in_migrations.md).
#### Multi-tenancy
diff --git a/doc/development/service_ping/metrics_dictionary.md b/doc/development/service_ping/metrics_dictionary.md
index fb777f37067..ab3d301908b 100644
--- a/doc/development/service_ping/metrics_dictionary.md
+++ b/doc/development/service_ping/metrics_dictionary.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Metrics Dictionary Guide
[Service Ping](index.md) metrics are defined in individual YAML files definitions from which the
-[Metrics Dictionary](https://metrics.gitlab.com/) is built.
+[Metrics Dictionary](https://metrics.gitlab.com/) is built. Currently, the metrics dictionary is built automatically once a day. When a change to a metric is made in a YAML file, you can see the change in the dictionary within 24 hours.
This guide describes the dictionary and how it's implemented.
## Metrics Definition and validation
diff --git a/doc/development/service_ping/metrics_lifecycle.md b/doc/development/service_ping/metrics_lifecycle.md
index 18613c11d0b..844c989c640 100644
--- a/doc/development/service_ping/metrics_lifecycle.md
+++ b/doc/development/service_ping/metrics_lifecycle.md
@@ -60,6 +60,8 @@ The correct approach is to add a new metric for GitLab 12.6 release with updated
and update existing business analysis artefacts to use `example_metric_without_archived` instead of `example_metric`
+Currently, the [Metrics Dictionary](https://metrics.gitlab.com/) is built automatically once a day. When a change to a metric is made in a YAML file, you can see the change in the dictionary within 24 hours.
+
## Remove a metric
WARNING:
diff --git a/doc/development/sidekiq/compatibility_across_updates.md b/doc/development/sidekiq/compatibility_across_updates.md
index 919f6935139..35f4b88351e 100644
--- a/doc/development/sidekiq/compatibility_across_updates.md
+++ b/doc/development/sidekiq/compatibility_across_updates.md
@@ -156,4 +156,4 @@ end
You must rename the queue in a post-deployment migration not in a normal
migration. Otherwise, it runs too early, before all the workers that
-schedule these jobs have stopped running. See also [other examples](../post_deployment_migrations.md#use-cases).
+schedule these jobs have stopped running. See also [other examples](../database/post_deployment_migrations.md#use-cases).
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 7c8b0b2478d..29215ec9206 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -1417,7 +1417,7 @@ To prepare the new server:
1. Flush the Redis database to disk, and stop GitLab other than the services needed for migration:
```shell
- sudo /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket save && sudo gitlab-ctl stop && sudo gitlab-ctl start postgresql
+ sudo /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket save && sudo gitlab-ctl stop && sudo gitlab-ctl start postgresql && sudo gitlab-ctl start gitaly
```
1. Create a GitLab backup:
diff --git a/doc/raketasks/migrate_snippets.md b/doc/raketasks/migrate_snippets.md
index 0d2c4edb01f..c36009e69d0 100644
--- a/doc/raketasks/migrate_snippets.md
+++ b/doc/raketasks/migrate_snippets.md
@@ -18,7 +18,7 @@ For each snippet:
- A file is created in the repository, using the snippet filename.
- The snippet is committed to the repository.
-GitLab performs this migration through a [Background Migration](../development/background_migrations.md)
+GitLab performs this migration through a [Background Migration](../development/database/background_migrations.md)
when the GitLab instance is upgraded to 13.0 or a higher version.
However, if the migration fails for any of the snippets, they must be migrated individually.
The following Rake tasks help with that process.
diff --git a/doc/update/zero_downtime.md b/doc/update/zero_downtime.md
index d69d60fe73d..2cfe062aca2 100644
--- a/doc/update/zero_downtime.md
+++ b/doc/update/zero_downtime.md
@@ -13,7 +13,7 @@ there are the following requirements:
- You can only upgrade one minor release at a time. So from 13.1 to 13.2, not to
13.3. If you skip releases, database modifications may be run in the wrong
sequence [and leave the database schema in a broken state](https://gitlab.com/gitlab-org/gitlab/-/issues/321542).
-- You have to use [post-deployment migrations](../development/post_deployment_migrations.md).
+- You have to use [post-deployment migrations](../development/database/post_deployment_migrations.md).
- You are using PostgreSQL. Starting from GitLab 12.1, MySQL is not supported.
- Multi-node GitLab instance. Single-node instances may experience brief interruptions
[as services restart (Puma in particular)](#single-node-deployment).
diff --git a/lib/api/entities/basic_release_details.rb b/lib/api/entities/basic_release_details.rb
new file mode 100644
index 00000000000..d13080f32f4
--- /dev/null
+++ b/lib/api/entities/basic_release_details.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class BasicReleaseDetails < Grape::Entity
+ include ::API::Helpers::Presentable
+
+ expose :name
+ expose :tag, as: :tag_name
+ expose :description
+ expose :created_at
+ expose :released_at
+ expose :upcoming_release?, as: :upcoming_release
+ end
+ end
+end
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index 056b54674f1..2403c907f7f 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -2,20 +2,14 @@
module API
module Entities
- class Release < Grape::Entity
+ class Release < BasicReleaseDetails
include ::API::Helpers::Presentable
- expose :name
- expose :tag, as: :tag_name, if: ->(_, _) { can_download_code? }
- expose :description
expose :description_html, if: -> (_, options) { options[:include_html_description] } do |entity|
MarkupHelper.markdown_field(entity, :description, current_user: options[:current_user])
end
- expose :created_at
- expose :released_at
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? }
- expose :upcoming_release?, as: :upcoming_release
expose :milestones,
using: Entities::MilestoneWithStats,
if: -> (release, _) { release.milestones.present? && can_read_milestone? } do |release, _|
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index 7b89a177fd9..9e085a91a7c 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -8,16 +8,48 @@ module API
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
RELEASE_CLI_USER_AGENT = 'GitLab-release-cli'
- before { authorize_read_releases! }
+ feature_category :release_orchestration
- after { track_release_event }
+ params do
+ requires :id, type: String, desc: 'The ID of a group'
+ end
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ before { authorize_read_group_releases! }
- feature_category :release_orchestration
+ desc 'Get a list of releases for projects in this group.' do
+ success Entities::Release
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the group to get releases for'
+ optional :sort, type: String, values: %w[asc desc], default: 'desc',
+ desc: 'Return projects sorted in ascending and descending order by released_at'
+ optional :simple, type: Boolean, default: false,
+ desc: 'Return only the ID, URL, name, and path of each project'
+
+ use :pagination
+ end
+ get ":id/releases" do
+ not_found! unless Feature.enabled?(:group_releases_finder_inoperator)
+
+ finder_options = {
+ sort: params[:sort]
+ }
+
+ strict_params = declared_params(include_missing: false)
+ releases = find_group_releases(finder_options)
+
+ present_group_releases(strict_params, releases)
+ end
+ end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ before { authorize_read_releases! }
+
+ after { track_release_event }
+
desc 'Get a project releases' do
detail 'This feature was introduced in GitLab 11.7.'
named 'get_releases'
@@ -162,6 +194,10 @@ module API
end
helpers do
+ def authorize_read_group_releases!
+ authorize! :read_release, user_group
+ end
+
def authorize_create_release!
authorize! :create_release, user_project
end
@@ -220,6 +256,22 @@ module API
Gitlab::Tracking.event(options[:for].name, options[:route_options][:named],
project: user_project, user: current_user, **event_context)
end
+
+ def find_group_releases(finder_options)
+ ::Releases::GroupReleasesFinder
+ .new(user_group, current_user, finder_options)
+ .execute(preload: true)
+ end
+
+ def present_group_releases(params, releases)
+ options = {
+ with: params[:simple] ? Entities::BasicReleaseDetails : Entities::Release,
+ current_user: current_user
+ }
+
+ # GroupReleasesFinder has already ordered the data for us
+ present paginate(releases, skip_default_order: true), options
+ end
end
end
end
diff --git a/lib/api/wikis.rb b/lib/api/wikis.rb
index aaeeed5e08e..12dbf4792d6 100644
--- a/lib/api/wikis.rb
+++ b/lib/api/wikis.rb
@@ -12,7 +12,7 @@ module API
params :common_wiki_page_params do
optional :format,
type: String,
- values: Wiki::MARKUPS.values.map(&:to_s),
+ values: Wiki::VALID_USER_MARKUPS.keys.map(&:to_s),
default: 'markdown',
desc: 'Format of a wiki page. Available formats are markdown, rdoc, asciidoc and org'
end
diff --git a/lib/gitlab/ci/pipeline/chain/template_usage.rb b/lib/gitlab/ci/pipeline/chain/template_usage.rb
index 2fcf1740b5f..f9b3b6cd644 100644
--- a/lib/gitlab/ci/pipeline/chain/template_usage.rb
+++ b/lib/gitlab/ci/pipeline/chain/template_usage.rb
@@ -19,7 +19,7 @@ module Gitlab
def track_event(template)
Gitlab::UsageDataCounters::CiTemplateUniqueCounter
- .track_unique_project_event(project_id: pipeline.project_id, template: template, config_source: pipeline.config_source)
+ .track_unique_project_event(project: pipeline.project, template: template, config_source: pipeline.config_source, user: current_user)
end
def included_templates
diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb
index 300db6802e6..00304f48dc5 100644
--- a/lib/gitlab/pagination/offset_pagination.rb
+++ b/lib/gitlab/pagination/offset_pagination.rb
@@ -11,8 +11,8 @@ module Gitlab
@request_context = request_context
end
- def paginate(relation, exclude_total_headers: false)
- paginate_with_limit_optimization(add_default_order(relation)).tap do |data|
+ def paginate(relation, exclude_total_headers: false, skip_default_order: false)
+ paginate_with_limit_optimization(add_default_order(relation, skip_default_order: skip_default_order)).tap do |data|
add_pagination_headers(data, exclude_total_headers)
end
end
@@ -46,7 +46,9 @@ module Gitlab
false
end
- def add_default_order(relation)
+ def add_default_order(relation, skip_default_order: false)
+ return relation if skip_default_order
+
if relation.is_a?(ActiveRecord::Relation) && relation.order_values.empty?
relation = relation.order(:id) # rubocop: disable CodeReuse/ActiveRecord
end
diff --git a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
index b8de7de848d..cf3caf3f0c7 100644
--- a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
@@ -6,13 +6,18 @@ module Gitlab::UsageDataCounters
KNOWN_EVENTS_FILE_PATH = File.expand_path('known_events/ci_templates.yml', __dir__)
class << self
- def track_unique_project_event(project_id:, template:, config_source:)
+ def track_unique_project_event(project:, template:, config_source:, user:)
expanded_template_name = expand_template_name(template)
return unless expanded_template_name
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
- ci_template_event_name(expanded_template_name, config_source), values: project_id
+ ci_template_event_name(expanded_template_name, config_source), values: project.id
)
+
+ namespace = project.namespace
+ if Feature.enabled?(:route_hll_to_snowplow, namespace, default_enabled: :yaml)
+ Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace, user: user, project: project)
+ end
end
def ci_templates(relative_base = 'lib/gitlab/ci/templates')
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
index 1095d78c7ad..9a72636e1dc 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
@@ -6,8 +6,9 @@ module QA
describe "Gitlab migration" do
let(:logger) { Runtime::Logger.logger }
let(:differ) { RSpec::Support::Differ.new(color: true) }
- let(:gitlab_group) { 'gitlab-migration' }
- let(:gitlab_source_address) { "https://staging.gitlab.com" }
+ let(:gitlab_group) { ENV['QA_LARGE_IMPORT_GROUP'] || 'gitlab-migration' }
+ let(:gitlab_project) { ENV['QA_LARGE_IMPORT_REPO'] || 'dri' }
+ let(:gitlab_source_address) { 'https://staging.gitlab.com' }
let(:import_wait_duration) do
{
@@ -65,7 +66,7 @@ module QA
end
end
- let(:source_project) { source_group.projects.find { |project| project.name.include?("dri") }.reload! }
+ let(:source_project) { source_group.projects.find { |project| project.name.include?(gitlab_project) }.reload! }
let(:source_branches) { source_project.repository_branches(auto_paginate: true).map { |b| b[:name] } }
let(:source_commits) { source_project.commits(auto_paginate: true).map { |c| c[:id] } }
let(:source_labels) { source_project.labels(auto_paginate: true).map { |l| l.except(:id) } }
@@ -86,7 +87,7 @@ module QA
end
end
- let(:imported_project) { imported_group.projects.find { |project| project.name.include?("dri") }.reload! }
+ let(:imported_project) { imported_group.projects.find { |project| project.name.include?(gitlab_project) }.reload! }
let(:branches) { imported_project.repository_branches(auto_paginate: true).map { |b| b[:name] } }
let(:commits) { imported_project.commits(auto_paginate: true).map { |c| c[:id] } }
let(:labels) { imported_project.labels(auto_paginate: true).map { |l| l.except(:id) } }
@@ -280,11 +281,16 @@ module QA
#
expected_body = expected_item[:body]
actual_body = actual_item[:body]
- body_msg = <<~MSG
- #{msg} same description. diff:\n#{differ.diff(expected_body, actual_body)}
- MSG
+ body_msg = "#{msg} same description. diff:\n#{differ.diff(expected_body, actual_body)}"
expect(actual_body).to eq(expected_body), body_msg
+ # Print difference in state
+ #
+ expected_state = expected_item[:state]
+ actual_state = actual_item[:state]
+ state_msg = "#{msg} same state. Source: #{expected_state}, Target: #{actual_state}"
+ expect(actual_state).to eq(expected_state), state_msg
+
# Print amount difference first
#
expected_comments = expected_item[:comments]
@@ -330,6 +336,7 @@ module QA
url: mr[:web_url],
title: mr[:title],
body: sanitize_description(mr[:description]) || '',
+ state: mr[:state],
comments: resource
.comments(auto_paginate: true, attempts: 2)
.map { |c| sanitize_comment(c[:body]) }
@@ -355,6 +362,7 @@ module QA
[issue[:iid], {
url: issue[:web_url],
title: issue[:title],
+ state: issue[:state],
body: sanitize_description(issue[:description]) || '',
comments: resource
.comments(auto_paginate: true, attempts: 2)
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 76f43a05186..19e27144e66 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -10,7 +10,7 @@ FactoryBot.define do
options do
{
- image: 'ruby:2.7',
+ image: 'image:1.0',
services: ['postgres'],
script: ['ls -a']
}
@@ -493,7 +493,7 @@ FactoryBot.define do
trait :extended_options do
options do
{
- image: { name: 'ruby:2.7', entrypoint: '/bin/sh' },
+ image: { name: 'image:1.0', entrypoint: '/bin/sh' },
services: ['postgres', { name: 'docker:stable-dind', entrypoint: '/bin/sh', command: 'sleep 30', alias: 'docker' }, { name: 'mysql:latest', variables: { MYSQL_ROOT_PASSWORD: 'root123.' } }],
script: %w(echo),
after_script: %w(ls date),
diff --git a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
index 465e1193a64..0f9a5ccfa7d 100644
--- a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
+++ b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
@@ -5,6 +5,7 @@
"name": { "type": "string" },
"description": { "type": "string" },
"description_html": { "type": "string" },
+ "tag_name": { "type": "string"},
"created_at": { "type": "string", "format": "date-time" },
"released_at": { "type": "string", "format": "date-time" },
"upcoming_release": { "type": "boolean" },
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index 71cd57d317c..630dfcd06bb 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Ci::Build::Image do
subject { described_class.from_image(job) }
context 'when image is defined in job' do
- let(:image_name) { 'ruby:2.7' }
+ let(:image_name) { 'image:1.0' }
let(:job) { create(:ci_build, options: { image: image_name } ) }
context 'when image is defined as string' do
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index e810d65d560..e16a9a7a74a 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -6,11 +6,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
let(:entry) { described_class.new(config) }
context 'when configuration is a string' do
- let(:config) { 'ruby:2.7' }
+ let(:config) { 'image:1.0' }
describe '#value' do
it 'returns image hash' do
- expect(entry.value).to eq({ name: 'ruby:2.7' })
+ expect(entry.value).to eq({ name: 'image:1.0' })
end
end
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
describe '#image' do
it "returns image's name" do
- expect(entry.name).to eq 'ruby:2.7'
+ expect(entry.name).to eq 'image:1.0'
end
end
@@ -46,7 +46,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
end
context 'when configuration is a hash' do
- let(:config) { { name: 'ruby:2.7', entrypoint: %w(/bin/sh run) } }
+ let(:config) { { name: 'image:1.0', entrypoint: %w(/bin/sh run) } }
describe '#value' do
it 'returns image hash' do
@@ -68,7 +68,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
describe '#image' do
it "returns image's name" do
- expect(entry.name).to eq 'ruby:2.7'
+ expect(entry.name).to eq 'image:1.0'
end
end
@@ -80,7 +80,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
context 'when configuration has ports' do
let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] }
- let(:config) { { name: 'ruby:2.7', entrypoint: %w(/bin/sh run), ports: ports } }
+ let(:config) { { name: 'image:1.0', entrypoint: %w(/bin/sh run), ports: ports } }
let(:entry) { described_class.new(config, with_image_ports: image_ports) }
let(:image_ports) { false }
@@ -112,7 +112,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
end
context 'when entry value is not correct' do
- let(:config) { ['ruby:2.7'] }
+ let(:config) { ['image:1.0'] }
describe '#errors' do
it 'saves errors' do
@@ -129,7 +129,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do
end
context 'when unexpected key is specified' do
- let(:config) { { name: 'ruby:2.7', non_existing: 'test' } }
+ let(:config) { { name: 'image:1.0', non_existing: 'test' } }
describe '#errors' do
it 'saves errors' do
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index daf58aff116..b9c32bc51be 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
let(:hash) do
{
before_script: %w(ls pwd),
- image: 'ruby:2.7',
+ image: 'image:1.0',
default: {},
services: ['postgres:9.1', 'mysql:5.5'],
variables: { VAR: 'root', VAR2: { value: 'val 2', description: 'this is var 2' } },
@@ -154,7 +154,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
{ name: :rspec,
script: %w[rspec ls],
before_script: %w(ls pwd),
- image: { name: 'ruby:2.7' },
+ image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
@@ -169,7 +169,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
{ name: :spinach,
before_script: [],
script: %w[spinach],
- image: { name: 'ruby:2.7' },
+ image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
@@ -186,7 +186,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
before_script: [],
script: ["make changelog | tee release_changelog.txt"],
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
- image: { name: "ruby:2.7" },
+ image: { name: "image:1.0" },
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }],
only: { refs: %w(branches tags) },
@@ -206,7 +206,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
{ before_script: %w(ls pwd),
after_script: ['make clean'],
default: {
- image: 'ruby:2.7',
+ image: 'image:1.0',
services: ['postgres:9.1', 'mysql:5.5']
},
variables: { VAR: 'root' },
@@ -233,7 +233,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
rspec: { name: :rspec,
script: %w[rspec ls],
before_script: %w(ls pwd),
- image: { name: 'ruby:2.7' },
+ image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
@@ -246,7 +246,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
spinach: { name: :spinach,
before_script: [],
script: %w[spinach],
- image: { name: 'ruby:2.7' },
+ image: { name: 'image:1.0' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index aa46fa61bf6..ca3d731b86f 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
let(:root_ref_sha) { project.repository.root_ref_sha }
before do
- stub_project_blob(root_ref_sha, '/file.yml') { 'image: ruby:2.7' }
+ stub_project_blob(root_ref_sha, '/file.yml') { 'image: image:1.0' }
end
it { is_expected.to be_truthy }
@@ -102,7 +102,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do
let(:ref_sha) { project.commit('master').sha }
before do
- stub_project_blob(ref_sha, '/file.yml') { 'image: ruby:2.7' }
+ stub_project_blob(ref_sha, '/file.yml') { 'image: image:1.0' }
end
it { is_expected.to be_truthy }
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index f69feba5e59..3da7181ba83 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
let(:file_content) do
<<~HEREDOC
- image: 'ruby:2.7'
+ image: 'image:1.0'
HEREDOC
end
@@ -36,7 +36,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when the string is a local file' do
let(:values) do
{ include: local_file,
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns File instances' do
@@ -48,7 +48,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when the key is a local file hash' do
let(:values) do
{ include: { 'local' => local_file },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns File instances' do
@@ -59,7 +59,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when the string is a remote file' do
let(:values) do
- { include: remote_url, image: 'ruby:2.7' }
+ { include: remote_url, image: 'image:1.0' }
end
it 'returns File instances' do
@@ -71,7 +71,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when the key is a remote file hash' do
let(:values) do
{ include: { 'remote' => remote_url },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns File instances' do
@@ -83,7 +83,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when the key is a template file hash' do
let(:values) do
{ include: { 'template' => template_file },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns File instances' do
@@ -98,7 +98,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
let(:remote_url) { 'https://gitlab.com/secret-file.yml' }
let(:values) do
{ include: { 'local' => local_file, 'remote' => remote_url },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns ambigious specification error' do
@@ -109,7 +109,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context "when the key is a project's file" do
let(:values) do
{ include: { project: project.full_path, file: local_file },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns File instances' do
@@ -121,7 +121,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context "when the key is project's files" do
let(:values) do
{ include: { project: project.full_path, file: [local_file, 'another_file_path.yml'] },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns two File instances' do
@@ -135,7 +135,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context "when 'include' is defined as an array" do
let(:values) do
{ include: [remote_url, local_file],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns Files instances' do
@@ -147,7 +147,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context "when 'include' is defined as an array of hashes" do
let(:values) do
{ include: [{ remote: remote_url }, { local: local_file }],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns Files instances' do
@@ -158,7 +158,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when it has ambigious match' do
let(:values) do
{ include: [{ remote: remote_url, local: local_file }],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'returns ambigious specification error' do
@@ -170,7 +170,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context "when 'include' is not defined" do
let(:values) do
{
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -185,7 +185,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
{ 'local' => local_file },
{ 'local' => local_file }
],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'does not raise an exception' do
@@ -199,7 +199,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
{ 'local' => local_file },
{ 'remote' => remote_url }
],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
before do
@@ -217,7 +217,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
{ 'local' => local_file },
{ 'remote' => remote_url }
],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
before do
@@ -269,7 +269,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'defined as an array' do
let(:values) do
{ include: [full_local_file_path, remote_url],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'expands the variable' do
@@ -281,7 +281,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'defined as an array of hashes' do
let(:values) do
{ include: [{ local: full_local_file_path }, { remote: remote_url }],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'expands the variable' do
@@ -303,7 +303,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'project name' do
let(:values) do
{ include: { project: '$CI_PROJECT_PATH', file: local_file },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'expands the variable', :aggregate_failures do
@@ -315,7 +315,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'with multiple files' do
let(:values) do
{ include: { project: project.full_path, file: [full_local_file_path, 'another_file_path.yml'] },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'expands the variable' do
@@ -327,7 +327,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
context 'when include variable has an unsupported type for variable expansion' do
let(:values) do
{ include: { project: project.id, file: local_file },
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
it 'does not invoke expansion for the variable', :aggregate_failures do
@@ -365,7 +365,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
let(:values) do
{ include: [{ remote: remote_url },
{ local: local_file, rules: [{ if: "$CI_PROJECT_ID == '#{project_id}'" }] }],
- image: 'ruby:2.7' }
+ image: 'image:1.0' }
end
context 'when the rules matches' do
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 97bd74721f2..68f5aaee95f 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
subject { processor.perform }
context 'when no external files defined' do
- let(:values) { { image: 'ruby:2.7' } }
+ let(:values) { { image: 'image:1.0' } }
it 'returns the same values' do
expect(processor.perform).to eq(values)
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
end
context 'when an invalid local file is defined' do
- let(:values) { { include: '/lib/gitlab/ci/templates/non-existent-file.yml', image: 'ruby:2.7' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/non-existent-file.yml', image: 'image:1.0' } }
it 'raises an error' do
expect { processor.perform }.to raise_error(
@@ -45,7 +45,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
context 'when an invalid remote file is defined' do
let(:remote_file) { 'http://doesntexist.com/.gitlab-ci-1.yml' }
- let(:values) { { include: remote_file, image: 'ruby:2.7' } }
+ let(:values) { { include: remote_file, image: 'image:1.0' } }
before do
stub_full_request(remote_file).and_raise(SocketError.new('Some HTTP error'))
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
context 'with a valid remote external file is defined' do
let(:remote_file) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' }
- let(:values) { { include: remote_file, image: 'ruby:2.7' } }
+ let(:values) { { include: remote_file, image: 'image:1.0' } }
let(:external_file_content) do
<<-HEREDOC
before_script:
@@ -95,7 +95,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
end
context 'with a valid local external file is defined' do
- let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'ruby:2.7' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'image:1.0' } }
let(:local_file_content) do
<<-HEREDOC
before_script:
@@ -133,7 +133,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
let(:values) do
{
include: external_files,
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -165,7 +165,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
end
context 'when external files are defined but not valid' do
- let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'ruby:2.7' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'image:1.0' } }
let(:local_file_content) { 'invalid content file ////' }
@@ -187,7 +187,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
let(:values) do
{
include: remote_file,
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -200,7 +200,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
it 'takes precedence' do
stub_full_request(remote_file).to_return(body: remote_file_content)
- expect(processor.perform[:image]).to eq('ruby:2.7')
+ expect(processor.perform[:image]).to eq('image:1.0')
end
end
@@ -210,7 +210,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
include: [
{ local: '/local/file.yml' }
],
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -294,7 +294,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
context 'when config includes an external configuration file via SSL web request' do
before do
stub_full_request('https://sha256.badssl.com/fake.yml', ip_address: '8.8.8.8')
- .to_return(body: 'image: ruby:2.6', status: 200)
+ .to_return(body: 'image: image:1.0', status: 200)
stub_full_request('https://self-signed.badssl.com/fake.yml', ip_address: '8.8.8.9')
.to_raise(OpenSSL::SSL::SSLError.new('SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate)'))
@@ -303,7 +303,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
context 'with an acceptable certificate' do
let(:values) { { include: 'https://sha256.badssl.com/fake.yml' } }
- it { is_expected.to include(image: 'ruby:2.6') }
+ it { is_expected.to include(image: 'image:1.0') }
end
context 'with a self-signed certificate' do
@@ -319,7 +319,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
let(:values) do
{
include: { project: another_project.full_path, file: '/templates/my-build.yml' },
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -349,7 +349,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
project: another_project.full_path,
file: ['/templates/my-build.yml', '/templates/my-test.yml']
},
- image: 'ruby:2.7'
+ image: 'image:1.0'
}
end
@@ -383,7 +383,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
let_it_be(:project) { create(:project, :repository) }
let(:values) do
- { include: 'myfolder/*.yml', image: 'ruby:2.7' }
+ { include: 'myfolder/*.yml', image: 'image:1.0' }
end
before do
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 05ff1f3618b..05558464a98 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Ci::Config do
context 'when config is valid' do
let(:yml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
rspec:
script:
@@ -32,7 +32,7 @@ RSpec.describe Gitlab::Ci::Config do
describe '#to_hash' do
it 'returns hash created from string' do
hash = {
- image: 'ruby:2.7',
+ image: 'image:1.0',
rspec: {
script: ['gem install rspec',
'rspec']
@@ -109,7 +109,7 @@ RSpec.describe Gitlab::Ci::Config do
context 'when using extendable hash' do
let(:yml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
rspec:
script: rspec
@@ -122,7 +122,7 @@ RSpec.describe Gitlab::Ci::Config do
it 'correctly extends the hash' do
hash = {
- image: 'ruby:2.7',
+ image: 'image:1.0',
rspec: { script: 'rspec' },
test: {
extends: 'rspec',
@@ -212,7 +212,7 @@ RSpec.describe Gitlab::Ci::Config do
let(:yml) do
<<-EOS
image:
- name: ruby:2.7
+ name: image:1.0
ports:
- 80
EOS
@@ -226,12 +226,12 @@ RSpec.describe Gitlab::Ci::Config do
context 'in the job image' do
let(:yml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
test:
script: rspec
image:
- name: ruby:2.7
+ name: image:1.0
ports:
- 80
EOS
@@ -245,11 +245,11 @@ RSpec.describe Gitlab::Ci::Config do
context 'in the services' do
let(:yml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
test:
script: rspec
- image: ruby:2.7
+ image: image:1.0
services:
- name: test
alias: test
@@ -325,7 +325,7 @@ RSpec.describe Gitlab::Ci::Config do
- project: '$MAIN_PROJECT'
ref: '$REF'
file: '$FILENAME'
- image: ruby:2.7
+ image: image:1.0
HEREDOC
end
@@ -364,7 +364,7 @@ RSpec.describe Gitlab::Ci::Config do
it 'returns a composed hash' do
composed_hash = {
before_script: local_location_hash[:before_script],
- image: "ruby:2.7",
+ image: "image:1.0",
rspec: { script: ["bundle exec rspec"] },
variables: remote_file_hash[:variables]
}
@@ -481,7 +481,7 @@ RSpec.describe Gitlab::Ci::Config do
include:
- #{remote_location}
- image: ruby:2.7
+ image: image:1.0
HEREDOC
end
@@ -492,7 +492,7 @@ RSpec.describe Gitlab::Ci::Config do
end
it 'takes precedence' do
- expect(config.to_hash).to eq({ image: 'ruby:2.7' })
+ expect(config.to_hash).to eq({ image: 'image:1.0' })
end
end
@@ -699,7 +699,7 @@ RSpec.describe Gitlab::Ci::Config do
- #{local_location}
- #{other_file_location}
- image: ruby:2.7
+ image: image:1.0
HEREDOC
end
@@ -718,7 +718,7 @@ RSpec.describe Gitlab::Ci::Config do
it 'returns a composed hash' do
composed_hash = {
before_script: local_location_hash[:before_script],
- image: "ruby:2.7",
+ image: "image:1.0",
build: { stage: "build", script: "echo hello" },
rspec: { stage: "test", script: "bundle exec rspec" }
}
@@ -735,7 +735,7 @@ RSpec.describe Gitlab::Ci::Config do
- local: #{local_location}
rules:
- if: $CI_PROJECT_ID == "#{project_id}"
- image: ruby:2.7
+ image: image:1.0
HEREDOC
end
@@ -763,7 +763,7 @@ RSpec.describe Gitlab::Ci::Config do
- local: #{local_location}
rules:
- exists: "#{filename}"
- image: ruby:2.7
+ image: image:1.0
HEREDOC
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
index 8e0b032e68c..ddd0de69d79 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/template_usage_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::TemplateUsage do
%w(Template-1 Template-2).each do |expected_template|
expect(Gitlab::UsageDataCounters::CiTemplateUniqueCounter).to(
receive(:track_unique_project_event)
- .with(project_id: project.id, template: expected_template, config_source: pipeline.config_source)
+ .with(project: project, template: expected_template, config_source: pipeline.config_source, user: user)
)
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index ebb5c91ebad..9b68ee2d6a2 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -842,7 +842,7 @@ module Gitlab
describe "Image and service handling" do
context "when extended docker configuration is used" do
it "returns image and service when defined" do
- config = YAML.dump({ image: { name: "ruby:2.7", entrypoint: ["/usr/local/bin/init", "run"] },
+ config = YAML.dump({ image: { name: "image:1.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: ["mysql", { name: "docker:dind", alias: "docker",
entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] }],
@@ -860,7 +860,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:2.7", entrypoint: ["/usr/local/bin/init", "run"] },
+ image: { name: "image:1.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: [{ name: "mysql" },
{ name: "docker:dind", alias: "docker", entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] }]
@@ -874,10 +874,10 @@ module Gitlab
end
it "returns image and service when overridden for job" do
- config = YAML.dump({ image: "ruby:2.7",
+ config = YAML.dump({ image: "image:1.0",
services: ["mysql"],
before_script: ["pwd"],
- rspec: { image: { name: "ruby:3.0", entrypoint: ["/usr/local/bin/init", "run"] },
+ rspec: { image: { name: "image:1.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: [{ name: "postgresql", alias: "db-pg",
entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] }, "docker:dind"],
@@ -894,7 +894,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:3.0", entrypoint: ["/usr/local/bin/init", "run"] },
+ image: { name: "image:1.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: [{ name: "postgresql", alias: "db-pg", entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] },
{ name: "docker:dind" }]
@@ -910,7 +910,7 @@ module Gitlab
context "when etended docker configuration is not used" do
it "returns image and service when defined" do
- config = YAML.dump({ image: "ruby:2.7",
+ config = YAML.dump({ image: "image:1.0",
services: ["mysql", "docker:dind"],
before_script: ["pwd"],
rspec: { script: "rspec" } })
@@ -926,7 +926,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:2.7" },
+ image: { name: "image:1.0" },
services: [{ name: "mysql" }, { name: "docker:dind" }]
},
allow_failure: false,
@@ -938,10 +938,10 @@ module Gitlab
end
it "returns image and service when overridden for job" do
- config = YAML.dump({ image: "ruby:2.7",
+ config = YAML.dump({ image: "image:1.0",
services: ["mysql"],
before_script: ["pwd"],
- rspec: { image: "ruby:3.0", services: ["postgresql", "docker:dind"], script: "rspec" } })
+ rspec: { image: "image:1.0", services: ["postgresql", "docker:dind"], script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
@@ -954,7 +954,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:3.0" },
+ image: { name: "image:1.0" },
services: [{ name: "postgresql" }, { name: "docker:dind" }]
},
allow_failure: false,
@@ -1557,7 +1557,7 @@ module Gitlab
describe "Artifacts" do
it "returns artifacts when defined" do
config = YAML.dump({
- image: "ruby:2.7",
+ image: "image:1.0",
services: ["mysql"],
before_script: ["pwd"],
rspec: {
@@ -1583,7 +1583,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:2.7" },
+ image: { name: "image:1.0" },
services: [{ name: "mysql" }],
artifacts: {
name: "custom_name",
@@ -2327,7 +2327,7 @@ module Gitlab
context 'when hidden job have a script definition' do
let(:config) do
YAML.dump({
- '.hidden_job' => { image: 'ruby:2.7', script: 'test' },
+ '.hidden_job' => { image: 'image:1.0', script: 'test' },
'normal_job' => { script: 'test' }
})
end
@@ -2338,7 +2338,7 @@ module Gitlab
context "when hidden job doesn't have a script definition" do
let(:config) do
YAML.dump({
- '.hidden_job' => { image: 'ruby:2.7' },
+ '.hidden_job' => { image: 'image:1.0' },
'normal_job' => { script: 'test' }
})
end
diff --git a/spec/lib/gitlab/config/loader/yaml_spec.rb b/spec/lib/gitlab/config/loader/yaml_spec.rb
index be568a8e5f9..66ea931a42c 100644
--- a/spec/lib/gitlab/config/loader/yaml_spec.rb
+++ b/spec/lib/gitlab/config/loader/yaml_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Gitlab::Config::Loader::Yaml do
let(:yml) do
<<~YAML
- image: 'ruby:2.7'
+ image: 'image:1.0'
texts:
nested_key: 'value1'
more_text:
@@ -34,7 +34,7 @@ RSpec.describe Gitlab::Config::Loader::Yaml do
end
context 'when yaml syntax is correct' do
- let(:yml) { 'image: ruby:2.7' }
+ let(:yml) { 'image: image:1.0' }
describe '#valid?' do
it 'returns true' do
@@ -44,7 +44,7 @@ RSpec.describe Gitlab::Config::Loader::Yaml do
describe '#load!' do
it 'returns a valid hash' do
- expect(loader.load!).to eq(image: 'ruby:2.7')
+ expect(loader.load!).to eq(image: 'image:1.0')
end
end
end
@@ -164,7 +164,7 @@ RSpec.describe Gitlab::Config::Loader::Yaml do
describe '#load_raw!' do
it 'loads keys as strings' do
expect(loader.load_raw!).to eq(
- 'image' => 'ruby:2.7',
+ 'image' => 'image:1.0',
'texts' => {
'nested_key' => 'value1',
'more_text' => {
@@ -178,7 +178,7 @@ RSpec.describe Gitlab::Config::Loader::Yaml do
describe '#load!' do
it 'symbolizes keys' do
expect(loader.load!).to eq(
- image: 'ruby:2.7',
+ image: 'image:1.0',
texts: {
nested_key: 'value1',
more_text: {
diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb
index 9876387512b..e5fa7538515 100644
--- a/spec/lib/gitlab/path_regex_spec.rb
+++ b/spec/lib/gitlab/path_regex_spec.rb
@@ -557,7 +557,7 @@ RSpec.describe Gitlab::PathRegex do
end
it 'does not match other non-word characters' do
- expect(subject.match('ruby:2.7.0')[0]).to eq('ruby')
+ expect(subject.match('image:1.0.0')[0]).to eq('image')
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
index 222198a58ac..6a37bfd106d 100644
--- a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
@@ -5,30 +5,52 @@ require 'spec_helper'
RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
describe '.track_unique_project_event' do
using RSpec::Parameterized::TableSyntax
+ include SnowplowHelpers
- let(:project_id) { 1 }
+ let(:project) { build(:project) }
+ let(:user) { build(:user) }
shared_examples 'tracks template' do
+ let(:subject) { described_class.track_unique_project_event(project: project, template: template_path, config_source: config_source, user: user) }
+
it "has an event defined for template" do
expect do
- described_class.track_unique_project_event(
- project_id: project_id,
- template: template_path,
- config_source: config_source
- )
+ subject
end.not_to raise_error
end
it "tracks template" do
expanded_template_name = described_class.expand_template_name(template_path)
expected_template_event_name = described_class.ci_template_event_name(expanded_template_name, config_source)
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(expected_template_event_name, values: project_id)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(expected_template_event_name, values: project.id)
+
+ subject
+ end
+
+ context 'Snowplow' do
+ it 'event is not tracked if FF is disabled' do
+ stub_feature_flags(route_hll_to_snowplow: false)
+
+ subject
- described_class.track_unique_project_event(project_id: project_id, template: template_path, config_source: config_source)
+ expect_no_snowplow_event
+ end
+
+ it 'tracks event' do
+ subject
+
+ expect_snowplow_event(
+ category: described_class.to_s,
+ action: 'ci_templates_unique',
+ namespace: project.namespace,
+ user: user,
+ project: project
+ )
+ end
end
end
- context 'with explicit includes' do
+ context 'with explicit includes', :snowplow do
let(:config_source) { :repository_source }
(described_class.ci_templates - ['Verify/Browser-Performance.latest.gitlab-ci.yml', 'Verify/Browser-Performance.gitlab-ci.yml']).each do |template|
@@ -40,7 +62,7 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
end
end
- context 'with implicit includes' do
+ context 'with implicit includes', :snowplow do
let(:config_source) { :auto_devops_source }
[
@@ -60,7 +82,7 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
it 'expands short template names' do
expect do
- described_class.track_unique_project_event(project_id: 1, template: 'Dependency-Scanning.gitlab-ci.yml', config_source: :repository_source)
+ described_class.track_unique_project_event(project: project, template: 'Dependency-Scanning.gitlab-ci.yml', config_source: :repository_source, user: user)
end.not_to raise_error
end
end
diff --git a/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb b/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb
index f8c4a28ed45..7d96adf95e8 100644
--- a/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb
+++ b/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb
@@ -132,7 +132,7 @@ RSpec.describe Gitlab::WebIde::Config::Entry::Terminal do
{ before_script: %w[ls pwd],
script: 'sleep 100',
tags: ['webide'],
- image: 'ruby:3.0',
+ image: 'image:1.0',
services: ['mysql'],
variables: { KEY: 'value' } }
end
@@ -143,7 +143,7 @@ RSpec.describe Gitlab::WebIde::Config::Entry::Terminal do
tag_list: ['webide'],
job_variables: [{ key: 'KEY', value: 'value', public: true }],
options: {
- image: { name: "ruby:3.0" },
+ image: { name: "image:1.0" },
services: [{ name: "mysql" }],
before_script: %w[ls pwd],
script: ['sleep 100']
diff --git a/spec/lib/gitlab/web_ide/config_spec.rb b/spec/lib/gitlab/web_ide/config_spec.rb
index 7ee9d40410c..11ea6150719 100644
--- a/spec/lib/gitlab/web_ide/config_spec.rb
+++ b/spec/lib/gitlab/web_ide/config_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::WebIde::Config do
let(:yml) do
<<-EOS
terminal:
- image: ruby:2.7
+ image: image:1.0
before_script:
- gem install rspec
EOS
@@ -21,7 +21,7 @@ RSpec.describe Gitlab::WebIde::Config do
it 'returns hash created from string' do
hash = {
terminal: {
- image: 'ruby:2.7',
+ image: 'image:1.0',
before_script: ['gem install rspec']
}
}
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 5723e45a83a..a60c6d4d5f3 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2224,7 +2224,7 @@ RSpec.describe Ci::Build do
describe '#options' do
let(:options) do
{
- image: "ruby:2.7",
+ image: "image:1.0",
services: ["postgres"],
script: ["ls -a"]
}
@@ -2235,7 +2235,7 @@ RSpec.describe Ci::Build do
end
it 'allows to access with symbolized keys' do
- expect(build.options[:image]).to eq('ruby:2.7')
+ expect(build.options[:image]).to eq('image:1.0')
end
it 'rejects access with string keys' do
diff --git a/spec/models/ci/namespace_mirror_spec.rb b/spec/models/ci/namespace_mirror_spec.rb
index 38471f15849..9b4e86916b8 100644
--- a/spec/models/ci/namespace_mirror_spec.rb
+++ b/spec/models/ci/namespace_mirror_spec.rb
@@ -44,6 +44,53 @@ RSpec.describe Ci::NamespaceMirror do
end
end
+ describe '.contains_traversal_ids' do
+ let!(:other_group1) { create(:group) }
+ let!(:other_group2) { create(:group, parent: other_group1) }
+ let!(:other_group3) { create(:group, parent: other_group2) }
+ let!(:other_group4) { create(:group) }
+
+ subject(:result) { described_class.contains_traversal_ids(all_traversal_ids) }
+
+ context 'when passing a top-level group' do
+ let(:all_traversal_ids) do
+ [
+ [other_group1.id]
+ ]
+ end
+
+ it 'returns only itself and children of that group' do
+ expect(result.map(&:namespace)).to contain_exactly(other_group1, other_group2, other_group3)
+ end
+ end
+
+ context 'when passing many levels of groups' do
+ let(:all_traversal_ids) do
+ [
+ [other_group2.parent_id, other_group2.id],
+ [other_group3.parent_id, other_group3.id],
+ [other_group4.id]
+ ]
+ end
+
+ it 'returns only the asked group' do
+ expect(result.map(&:namespace)).to contain_exactly(other_group2, other_group3, other_group4)
+ end
+ end
+
+ context 'when passing invalid data ' do
+ let(:all_traversal_ids) do
+ [
+ ["; UPDATE"]
+ ]
+ end
+
+ it 'data is properly sanitised' do
+ expect(result.to_sql).to include "((traversal_ids[1])) IN (('; UPDATE'))"
+ end
+ end
+ end
+
describe '.by_namespace_id' do
subject(:result) { described_class.by_namespace_id(group2.id) }
diff --git a/spec/models/preloaders/environments/deployment_preloader_spec.rb b/spec/models/preloaders/environments/deployment_preloader_spec.rb
index 3f2f28a069e..4c05d9632de 100644
--- a/spec/models/preloaders/environments/deployment_preloader_spec.rb
+++ b/spec/models/preloaders/environments/deployment_preloader_spec.rb
@@ -6,14 +6,14 @@ RSpec.describe Preloaders::Environments::DeploymentPreloader do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) }
- let_it_be(:pipeline) { create(:ci_pipeline, user: user, project: project, sha: project.commit.sha) }
- let_it_be(:ci_build_a) { create(:ci_build, user: user, project: project, pipeline: pipeline) }
- let_it_be(:ci_build_b) { create(:ci_build, user: user, project: project, pipeline: pipeline) }
- let_it_be(:ci_build_c) { create(:ci_build, user: user, project: project, pipeline: pipeline) }
-
let_it_be(:environment_a) { create(:environment, project: project, state: :available) }
let_it_be(:environment_b) { create(:environment, project: project, state: :available) }
+ let_it_be(:pipeline) { create(:ci_pipeline, user: user, project: project, sha: project.commit.sha) }
+ let_it_be(:ci_build_a) { create(:ci_build, user: user, project: project, pipeline: pipeline, environment: environment_a.name) }
+ let_it_be(:ci_build_b) { create(:ci_build, user: user, project: project, pipeline: pipeline, environment: environment_a.name) }
+ let_it_be(:ci_build_c) { create(:ci_build, user: user, project: project, pipeline: pipeline, environment: environment_b.name) }
+
before do
create(:deployment, :success, project: project, environment: environment_a, deployable: ci_build_a)
create(:deployment, :success, project: project, environment: environment_a, deployable: ci_build_b)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 6e0c53a8823..d8267c7db99 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -4271,6 +4271,14 @@ RSpec.describe User do
it_behaves_like '#ci_owned_runners'
end
+
+ context 'when FF ci_owned_runners_unnest_index is disabled uses GIN index' do
+ before do
+ stub_feature_flags(ci_owned_runners_unnest_index: false)
+ end
+
+ it_behaves_like '#ci_owned_runners'
+ end
end
describe '#projects_with_reporter_access_limited_to' do
diff --git a/spec/models/web_ide_terminal_spec.rb b/spec/models/web_ide_terminal_spec.rb
index 149fce33f43..fc30bc18f68 100644
--- a/spec/models/web_ide_terminal_spec.rb
+++ b/spec/models/web_ide_terminal_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe WebIdeTerminal do
context 'when image does not have an alias' do
let(:config) do
- { image: 'ruby:2.7' }.merge(services_with_aliases)
+ { image: 'image:1.0' }.merge(services_with_aliases)
end
it 'returns services aliases' do
@@ -51,7 +51,7 @@ RSpec.describe WebIdeTerminal do
context 'when both image and services have aliases' do
let(:config) do
- { image: { name: 'ruby:2.7', alias: 'ruby' } }.merge(services_with_aliases)
+ { image: { name: 'image:1.0', alias: 'ruby' } }.merge(services_with_aliases)
end
it 'returns all aliases' do
@@ -61,7 +61,7 @@ RSpec.describe WebIdeTerminal do
context 'when image and services does not have any alias' do
let(:config) do
- { image: 'ruby:2.7', services: ['postgres'] }
+ { image: 'image:1.0', services: ['postgres'] }
end
it 'returns an empty array' do
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index ffa46dbb9b0..9e6bac41d59 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -216,7 +216,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(json_response['token']).to eq(job.token)
expect(json_response['job_info']).to eq(expected_job_info)
expect(json_response['git_info']).to eq(expected_git_info)
- expect(json_response['image']).to eq({ 'name' => 'ruby:2.7', 'entrypoint' => '/bin/sh', 'ports' => [] })
+ expect(json_response['image']).to eq({ 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [] })
expect(json_response['services']).to eq([{ 'name' => 'postgres', 'entrypoint' => nil,
'alias' => nil, 'command' => nil, 'ports' => [], 'variables' => nil },
{ 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh',
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 73bc4a5d1f3..ef7f5ee87dc 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -195,7 +195,7 @@ RSpec.describe API::Lint do
end
context 'with invalid configuration' do
- let(:yaml_content) { '{ image: "ruby:2.7", services: ["postgres"] }' }
+ let(:yaml_content) { '{ image: "image:1.0", services: ["postgres"] }' }
it 'responds with errors about invalid configuration' do
post api('/ci/lint', api_user), params: { content: yaml_content }
@@ -465,7 +465,7 @@ RSpec.describe API::Lint do
context 'with invalid .gitlab-ci.yml content' do
let(:yaml_content) do
- { image: 'ruby:2.7', services: ['postgres'] }.deep_stringify_keys.to_yaml
+ { image: 'image:1.0', services: ['postgres'] }.deep_stringify_keys.to_yaml
end
before do
@@ -712,7 +712,7 @@ RSpec.describe API::Lint do
context 'with invalid .gitlab-ci.yml content' do
let(:yaml_content) do
- { image: 'ruby:2.7', services: ['postgres'] }.deep_stringify_keys.to_yaml
+ { image: 'image:1.0', services: ['postgres'] }.deep_stringify_keys.to_yaml
end
context 'when running as dry run' do
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 6038682de1e..df0b4a19f6e 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe API::Releases do
+ include UploadHelpers
+
let(:project) { create(:project, :repository, :private) }
let(:maintainer) { create(:user) }
let(:reporter) { create(:user) }
@@ -1358,4 +1360,80 @@ RSpec.describe API::Releases do
release_cli: release_cli
)
end
+
+ describe 'GET /groups/:id/releases' do
+ let_it_be(:user1) { create(:user, can_create_group: false) }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:group1) { create(:group, path: 'some_path', avatar: File.open(uploaded_image_temp_path)) }
+ let_it_be(:group2) { create(:group, :private) }
+ let_it_be(:project1) { create(:project, namespace: group1) }
+ let_it_be(:project2) { create(:project, namespace: group2) }
+ let_it_be(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
+ let_it_be(:release1) { create(:release, project: project1) }
+ let_it_be(:release2) { create(:release, project: project2) }
+ let_it_be(:release3) { create(:release, project: project3) }
+
+ context 'when authenticated as owner' do
+ it 'gets releases from all projects in the group' do
+ get api("/groups/#{group1.id}/releases", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.length).to eq(2)
+ expect(json_response.pluck('name')).to match_array([release1.name, release3.name])
+ end
+
+ it 'respects order by parameters' do
+ create(:release, project: project1, released_at: DateTime.now + 1.day)
+ get api("/groups/#{group1.id}/releases", admin), params: { sort: 'desc' }
+
+ expect(DateTime.parse(json_response[0]["released_at"]))
+ .to be > (DateTime.parse(json_response[1]["released_at"]))
+ end
+
+ it 'respects the simple parameter' do
+ get api("/groups/#{group1.id}/releases", admin), params: { simple: true }
+
+ expect(json_response[0].keys).not_to include("assets")
+ end
+
+ it 'denies access to private groups' do
+ get api("/groups/#{group2.id}/releases", user1), params: { simple: true }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns not found unless :group_releases_finder_inoperator feature flag enabled' do
+ stub_feature_flags(group_releases_finder_inoperator: false)
+
+ get api("/groups/#{group1.id}/releases", admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'performance testing' do
+ shared_examples 'avoids N+1 queries' do |query_params = {}|
+ context 'with subgroups' do
+ let(:group) { create(:group) }
+
+ it 'include_subgroups avoids N+1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ get api("/groups/#{group.id}/releases", admin), params: query_params.merge({ include_subgroups: true })
+ end.count
+
+ subgroups = create_list(:group, 10, parent: group1)
+ projects = create_list(:project, 10, namespace: subgroups[0])
+ create_list(:release, 10, project: projects[0], author: admin)
+
+ expect do
+ get api("/groups/#{group.id}/releases", admin), params: query_params.merge({ include_subgroups: true })
+ end.not_to exceed_all_query_limit(control_count)
+ end
+ end
+ end
+
+ it_behaves_like 'avoids N+1 queries'
+ it_behaves_like 'avoids N+1 queries', { simple: true }
+ end
+ end
end
diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb
index ec0dd735755..fe6278084f9 100644
--- a/spec/serializers/environment_serializer_spec.rb
+++ b/spec/serializers/environment_serializer_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe EnvironmentSerializer do
context 'when there is a single environment' do
before do
- create(:environment, name: 'staging')
+ create(:environment, project: project, name: 'staging')
end
it 'represents one standalone environment' do
@@ -63,8 +63,8 @@ RSpec.describe EnvironmentSerializer do
context 'when there are multiple environments in folder' do
before do
- create(:environment, name: 'staging/my-review-1')
- create(:environment, name: 'staging/my-review-2')
+ create(:environment, project: project, name: 'staging/my-review-1')
+ create(:environment, project: project, name: 'staging/my-review-2')
end
it 'represents one item that is a folder' do
@@ -78,10 +78,10 @@ RSpec.describe EnvironmentSerializer do
context 'when there are multiple folders and standalone environments' do
before do
- create(:environment, name: 'staging/my-review-1')
- create(:environment, name: 'staging/my-review-2')
- create(:environment, name: 'production/my-review-3')
- create(:environment, name: 'testing')
+ create(:environment, project: project, name: 'staging/my-review-1')
+ create(:environment, project: project, name: 'staging/my-review-2')
+ create(:environment, project: project, name: 'production/my-review-3')
+ create(:environment, project: project, name: 'testing')
end
it 'represents multiple items grouped within folders' do
@@ -124,7 +124,7 @@ RSpec.describe EnvironmentSerializer do
context 'when resource is paginatable relation' do
context 'when there is a single environment object in relation' do
before do
- create(:environment)
+ create(:environment, project: project)
end
it 'serializes environments' do
@@ -134,7 +134,7 @@ RSpec.describe EnvironmentSerializer do
context 'when multiple environment objects are serialized' do
before do
- create_list(:environment, 3)
+ create_list(:environment, 3, project: project)
end
it 'serializes appropriate number of objects' do
@@ -159,10 +159,10 @@ RSpec.describe EnvironmentSerializer do
end
before do
- create(:environment, name: 'staging/review-1')
- create(:environment, name: 'staging/review-2')
- create(:environment, name: 'production/deploy-3')
- create(:environment, name: 'testing')
+ create(:environment, project: project, name: 'staging/review-1')
+ create(:environment, project: project, name: 'staging/review-2')
+ create(:environment, project: project, name: 'production/deploy-3')
+ create(:environment, project: project, name: 'testing')
end
it 'paginates grouped items including ordering' do
@@ -189,7 +189,7 @@ RSpec.describe EnvironmentSerializer do
let(:resource) { Environment.all }
before do
- create(:environment, name: 'staging/review-1')
+ create(:environment, project: project, name: 'staging/review-1')
create_environment_with_associations(project)
end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index a7026f5062e..5a5b3b9d581 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -526,7 +526,7 @@ RSpec.describe Ci::CreatePipelineService do
let(:ci_yaml) do
<<-EOS
image:
- name: ruby:2.7
+ name: image:1.0
ports:
- 80
EOS
@@ -538,12 +538,12 @@ RSpec.describe Ci::CreatePipelineService do
context 'in the job image' do
let(:ci_yaml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
test:
script: rspec
image:
- name: ruby:2.7
+ name: image:1.0
ports:
- 80
EOS
@@ -555,11 +555,11 @@ RSpec.describe Ci::CreatePipelineService do
context 'in the service' do
let(:ci_yaml) do
<<-EOS
- image: ruby:2.7
+ image: image:1.0
test:
script: rspec
- image: ruby:2.7
+ image: image:1.0
services:
- name: test
ports:
diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb
index 0804773442d..3462b48cfe7 100644
--- a/spec/services/ci/create_web_ide_terminal_service_spec.rb
+++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Ci::CreateWebIdeTerminalService do
<<-EOS
terminal:
image:
- name: ruby:2.7
+ name: image:1.0
ports:
- 80
script: rspec
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index 1d3547e278c..c22099fe410 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -35,8 +35,9 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
expect_snowplow_event(
category: described_class.to_s,
action: 'action_active_users_project_repo',
- namespace: project,
- user: user
+ namespace: project.namespace,
+ user: user,
+ project: project
)
end
end
diff --git a/spec/support/gitlab_stubs/gitlab_ci.yml b/spec/support/gitlab_stubs/gitlab_ci.yml
index 52ae36229a6..b1533879e32 100644
--- a/spec/support/gitlab_stubs/gitlab_ci.yml
+++ b/spec/support/gitlab_stubs/gitlab_ci.yml
@@ -1,4 +1,4 @@
-image: ruby:2.6
+image: image:1.0
services:
- postgres
diff --git a/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
index f676b6aa60d..41b1964cff0 100644
--- a/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
@@ -20,6 +20,12 @@ RSpec.shared_examples 'User creates wiki page' do
click_link "Create your first page"
end
+ it 'shows all available formats in the dropdown' do
+ Wiki::VALID_USER_MARKUPS.each do |key, markup|
+ expect(page).to have_css("#wiki_format option[value=#{key}]", text: markup[:name])
+ end
+ end
+
it "disables the submit button", :js do
page.within(".wiki-form") do
fill_in(:wiki_content, with: "")
diff --git a/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb b/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
index 6b208c0024d..e625ba785d2 100644
--- a/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
@@ -20,6 +20,12 @@ RSpec.shared_examples 'from set operator' do |sql_klass|
expect(query.to_sql).to match(/FROM \(\(SELECT.+\)\n#{operator_keyword}\n\(SELECT.+\)\) users/m)
end
+ it "returns empty set when passing empty array" do
+ query = model.public_send(operator_method, [])
+
+ expect(query.to_sql).to match(/WHERE \(1=0\)/m)
+ end
+
it 'supports the use of a custom alias for the sub query' do
query = model.public_send(operator_method,
[model.where(id: 1), model.where(id: 2)],
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index 1b7da3b0ef1..03e9dd65e33 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -11,6 +11,10 @@ RSpec.shared_examples 'wiki model' do
subject { wiki }
+ it 'VALID_USER_MARKUPS contains all valid markups' do
+ expect(described_class::VALID_USER_MARKUPS.keys).to match_array(%i(markdown rdoc asciidoc org))
+ end
+
it 'container class includes HasWiki' do
# NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
expect(wiki_container).to be_kind_of(HasWiki)
@@ -520,6 +524,15 @@ RSpec.shared_examples 'wiki model' do
end
end
+ context 'when format is not allowed' do
+ let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
+
+ it 'returns false and sets error message' do
+ expect(subject.update_page(page.page, content: 'new content', format: :creole)).to eq false
+ expect(subject.error_message).to match(/Invalid format selected/)
+ end
+ end
+
context 'when page path does not have a default extension' do
let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
diff --git a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
index 87a33060435..8f63192e709 100644
--- a/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/environment_serializer_shared_examples.rb
@@ -1,8 +1,5 @@
# frozen_string_literal: true
RSpec.shared_examples 'avoid N+1 on environments serialization' do |ee: false|
- # Investigating in https://gitlab.com/gitlab-org/gitlab/-/issues/353209
- let(:query_threshold) { 1 + (ee ? 4 : 0) }
-
it 'avoids N+1 database queries with grouping', :request_store do
create_environment_with_associations(project)
@@ -11,9 +8,7 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do |ee: false|
create_environment_with_associations(project)
create_environment_with_associations(project)
- expect { serialize(grouping: true) }
- .not_to exceed_query_limit(control.count)
- .with_threshold(query_threshold)
+ expect { serialize(grouping: true) }.not_to exceed_query_limit(control.count)
end
it 'avoids N+1 database queries without grouping', :request_store do
@@ -24,9 +19,7 @@ RSpec.shared_examples 'avoid N+1 on environments serialization' do |ee: false|
create_environment_with_associations(project)
create_environment_with_associations(project)
- expect { serialize(grouping: false) }
- .not_to exceed_query_limit(control.count)
- .with_threshold(query_threshold)
+ expect { serialize(grouping: false) }.not_to exceed_query_limit(control.count)
end
it 'does not preload for environments that does not exist in the page', :request_store do
diff --git a/spec/uploaders/ci/secure_file_uploader_spec.rb b/spec/uploaders/ci/secure_file_uploader_spec.rb
index 3be4f742a24..4bac591704b 100644
--- a/spec/uploaders/ci/secure_file_uploader_spec.rb
+++ b/spec/uploaders/ci/secure_file_uploader_spec.rb
@@ -15,9 +15,9 @@ RSpec.describe Ci::SecureFileUploader do
describe '#key' do
it 'creates a digest with a secret key and the project id' do
- expect(OpenSSL::HMAC)
+ expect(Digest::SHA256)
.to receive(:digest)
- .with('SHA256', Gitlab::Application.secrets.db_key_base, ci_secure_file.project_id.to_s)
+ .with(ci_secure_file.key_data)
.and_return('digest')
expect(subject.key).to eq('digest')