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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/CODEOWNERS1323
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml28
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/keybindings.js68
-rw-r--r--app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue12
-rw-r--r--app/assets/javascripts/ci/runner/project_register_runner/index.js36
-rw-r--r--app/assets/javascripts/ci/runner/project_register_runner/project_register_runner_app.vue69
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_overview.vue6
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_tabs.vue158
-rw-r--r--app/assets/javascripts/environments/constants.js2
-rw-r--r--app/assets/javascripts/environments/graphql/client.js19
-rw-r--r--app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql2
-rw-r--r--app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql15
-rw-r--r--app/assets/javascripts/environments/graphql/resolvers.js24
-rw-r--r--app/assets/javascripts/environments/graphql/typedefs.graphql19
-rw-r--r--app/assets/javascripts/environments/helpers/k8s_integration_helper.js36
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_trigger.vue19
-rw-r--r--app/assets/javascripts/invite_members/constants.js1
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue6
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue6
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue72
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue57
-rw-r--r--app/assets/javascripts/monitoring/constants.js13
-rw-r--r--app/assets/javascripts/pages/projects/runners/register/index.js3
-rw-r--r--app/assets/javascripts/super_sidebar/components/create_menu.vue47
-rw-r--r--app/assets/javascripts/super_sidebar/components/help_center.vue10
-rw-r--r--app/assets/javascripts/super_sidebar/constants.js4
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/constants.js4
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue70
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue38
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue61
-rw-r--r--app/assets/stylesheets/framework/variables.scss5
-rw-r--r--app/assets/stylesheets/utilities.scss4
-rw-r--r--app/controllers/projects/blob_controller.rb1
-rw-r--r--app/controllers/projects/runners_controller.rb14
-rw-r--r--app/controllers/projects/tree_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/finders/deployments_finder.rb4
-rw-r--r--app/graphql/types/ci/runner_type.rb6
-rw-r--r--app/graphql/types/query_type.rb16
-rw-r--r--app/helpers/sidebars_helper.rb25
-rw-r--r--app/models/ci/build_need.rb2
-rw-r--r--app/models/ci/runner.rb4
-rw-r--r--app/services/ci/archive_trace_service.rb22
-rw-r--r--app/services/ci/ensure_stage_service.rb10
-rw-r--r--app/services/ci/list_config_variables_service.rb9
-rw-r--r--app/services/ci/parse_dotenv_artifact_service.rb9
-rw-r--r--app/services/ci/stuck_builds/drop_helpers.rb29
-rw-r--r--app/views/groups/runners/register.html.haml2
-rw-r--r--app/views/projects/runners/register.html.haml7
-rw-r--r--config/feature_flags/development/allow_dots_on_tf_state_names.yml8
-rw-r--r--config/feature_flags/development/explain_code_chat.yml8
-rw-r--r--config/feature_flags/development/synchronize_fork.yml2
-rw-r--r--config/routes/project.rb1
-rw-r--r--doc/api/graphql/reference/index.md18
-rw-r--r--doc/ci/resource_groups/index.md10
-rw-r--r--doc/ci/secrets/id_token_authentication.md6
-rw-r--r--doc/install/aws/eks_clusters_aws.md2
-rw-r--r--doc/integration/advanced_search/elasticsearch.md7
-rw-r--r--doc/operations/metrics/index.md1
-rw-r--r--doc/policy/alpha-beta-support.md8
-rw-r--r--doc/topics/autodevops/cicd_variables.md5
-rw-r--r--doc/topics/autodevops/upgrading_postgresql.md4
-rw-r--r--doc/user/clusters/agent/index.md4
-rw-r--r--doc/user/clusters/agent/troubleshooting.md2
-rw-r--r--doc/user/compliance/license_check_rules.md15
-rw-r--r--doc/user/infrastructure/iac/terraform_state.md6
-rw-r--r--doc/user/infrastructure/iac/troubleshooting.md9
-rw-r--r--doc/user/profile/preferences.md7
-rw-r--r--doc/user/project/clusters/add_eks_clusters.md2
-rw-r--r--doc/user/project/merge_requests/reviews/data_usage.md2
-rw-r--r--lib/api/terraform/state.rb19
-rw-r--r--lib/gitlab/ci/jwt_v2.rb10
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml1
-rw-r--r--locale/gitlab.pot63
-rw-r--r--package.json2
-rw-r--r--scripts/review_apps/base-config.yaml2
-rw-r--r--spec/controllers/projects/runners_controller_spec.rb79
-rw-r--r--spec/factories/customer_relations/contacts.rb4
-rw-r--r--spec/factories/customer_relations/organizations.rb2
-rw-r--r--spec/features/groups/crm/contacts/create_spec.rb2
-rw-r--r--spec/features/nav/new_nav_invite_members_spec.rb50
-rw-r--r--spec/features/runners_spec.rb10
-rw-r--r--spec/finders/crm/contacts_finder_spec.rb4
-rw-r--r--spec/finders/crm/organizations_finder_spec.rb22
-rw-r--r--spec/finders/deployments_finder_spec.rb6
-rw-r--r--spec/finders/issuables/crm_organization_filter_spec.rb22
-rw-r--r--spec/frontend/behaviors/shortcuts/keybindings_spec.js6
-rw-r--r--spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js32
-rw-r--r--spec/frontend/ci/runner/project_register_runner_app/project_register_runner_app_spec.js120
-rw-r--r--spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap2
-rw-r--r--spec/frontend/environments/graphql/mock_data.js53
-rw-r--r--spec/frontend/environments/graphql/resolvers_spec.js46
-rw-r--r--spec/frontend/environments/kubernetes_overview_spec.js8
-rw-r--r--spec/frontend/environments/kubernetes_tabs_spec.js158
-rw-r--r--spec/frontend/invite_members/components/invite_members_trigger_spec.js25
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js2
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js4
-rw-r--r--spec/frontend/ml/experiment_tracking/components/delete_button_spec.js6
-rw-r--r--spec/frontend/super_sidebar/components/create_menu_spec.js45
-rw-r--r--spec/frontend/super_sidebar/components/help_center_spec.js18
-rw-r--r--spec/frontend/super_sidebar/mock_data.js2
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_spec.js24
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_tree_spec.js13
-rw-r--r--spec/graphql/mutations/customer_relations/contacts/create_spec.rb12
-rw-r--r--spec/graphql/mutations/customer_relations/organizations/create_spec.rb2
-rw-r--r--spec/graphql/mutations/customer_relations/organizations/update_spec.rb12
-rw-r--r--spec/graphql/resolvers/crm/contacts_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb10
-rw-r--r--spec/graphql/resolvers/crm/organizations_resolver_spec.rb44
-rw-r--r--spec/graphql/resolvers/project_issues_resolver_spec.rb10
-rw-r--r--spec/helpers/sidebars_helper_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/jwt_v2_spec.rb42
-rw-r--r--spec/models/ci/build_spec.rb1
-rw-r--r--spec/models/ci/runner_spec.rb26
-rw-r--r--spec/models/customer_relations/contact_spec.rb8
-rw-r--r--spec/models/customer_relations/organization_spec.rb74
-rw-r--r--spec/models/group_spec.rb8
-rw-r--r--spec/requests/api/deployments_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb38
-rw-r--r--spec/requests/api/graphql/query_spec.rb34
-rw-r--r--spec/requests/api/terraform/state_spec.rb82
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb14
-rw-r--r--spec/services/ci/create_pipeline_service/include_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/logger_spec.rb4
-rw-r--r--spec/services/ci/create_pipeline_service/merge_requests_spec.rb14
-rw-r--r--spec/services/ci/create_pipeline_service/partitioning_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/rate_limit_spec.rb6
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb30
-rw-r--r--spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb60
-rw-r--r--spec/services/ci/list_config_variables_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb3
-rw-r--r--spec/services/ci/play_build_service_spec.rb3
-rw-r--r--spec/services/ci/play_manual_stage_service_spec.rb5
-rw-r--r--spec/services/ci/process_sync_events_service_spec.rb3
-rw-r--r--spec/services/ci/retry_job_service_spec.rb15
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb20
-rw-r--r--spec/services/ci/run_scheduled_build_service_spec.rb3
-rw-r--r--spec/services/customer_relations/contacts/create_service_spec.rb4
-rw-r--r--spec/services/customer_relations/organizations/create_service_spec.rb6
-rw-r--r--spec/services/customer_relations/organizations/update_service_spec.rb12
-rw-r--r--spec/services/groups/transfer_service_spec.rb2
-rw-r--r--spec/support/protected_branch_helpers.rb23
-rw-r--r--spec/support/shared_contexts/graphql/types/query_type_shared_context.rb1
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb103
-rw-r--r--spec/support/shared_examples/finders/issues_finder_shared_examples.rb12
-rw-r--r--yarn.lock8
148 files changed, 2634 insertions, 1533 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 2dfd9aa71ed..ab3b6348676 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -4,14 +4,15 @@
* @gitlab-org/maintainers/rails-backend @gitlab-org/maintainers/frontend @gitlab-org/maintainers/database @gl-quality/qe-maintainers @gl-quality/tooling-maintainers @gitlab-org/delivery @gitlab-org/maintainers/cicd-templates @nolith @jacobvosmaer-gitlab @gitlab-org/tw-leadership
-CODEOWNERS @gitlab-org/development-leaders @gitlab-org/tw-leadership
-docs/CODEOWNERS @gitlab-org/development-leaders @gitlab-org/tw-leadership
.gitlab/CODEOWNERS @gitlab-org/development-leaders @gitlab-org/tw-leadership
## Allows release tooling to update the Gitaly Version
GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend @gitlab-org/delivery
## Files that are excluded from required approval
+## These rules override the * rule above, so that changes to docs and templates
+## can be merged by any user who has maintainer rights, but is not included in
+## the * rule (usually technical writers).
/.gitlab/issue_templates/*.md
/.gitlab/merge_request_templates/*.md
/doc/*.md
@@ -21,9 +22,10 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
/data/deprecations/*.yml
/data/removals/**/*.yml
-## Technical writing files that do need approval
-/data/deprecations/templates/ @marcel.amirault @gitlab-org/tw-leadership @sarahgerman
-/data/removals/templates/ @marcel.amirault @gitlab-org/tw-leadership @sarahgerman
+## Technical writing files that do not need `*` rule approval,
+## but still require an approval from a TW team DRI for each file.
+/data/deprecations/templates/ @marcel.amirault @sarahgerman @gitlab-org/tw-leadership
+/data/removals/templates/ @marcel.amirault @sarahgerman @gitlab-org/tw-leadership
.markdownlint.yml @marcel.amirault @eread @aqualls @gitlab-org/tw-leadership
/doc/.markdownlint/ @marcel.amirault @eread @aqualls @gitlab-org/tw-leadership
/doc/.vale/ @marcel.amirault @eread @aqualls @gitlab-org/tw-leadership
@@ -32,238 +34,241 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
^[Source code editing]
.solargraph.yml.example @igor.drozdov
-^[Backend]
-*.rb @gitlab-org/maintainers/rails-backend
-*.rake @gitlab-org/maintainers/rails-backend
+^[Backend] @gitlab-org/maintainers/rails-backend
+*.rb
+*.rake
-^[Frontend]
-*.scss @gitlab-org/maintainers/frontend
-*.js @gitlab-org/maintainers/frontend
-/app/assets/ @gitlab-org/maintainers/frontend
-/ee/app/assets/ @gitlab-org/maintainers/frontend
-/spec/frontend/ @gitlab-org/maintainers/frontend
-/ee/spec/frontend/ @gitlab-org/maintainers/frontend
-/spec/frontend_integration/ @gitlab-org/maintainers/frontend
-/ee/spec/frontend_integration/ @gitlab-org/maintainers/frontend
+^[Frontend] @gitlab-org/maintainers/frontend
+*.scss
+*.js
+/app/assets/
+/ee/app/assets/
+/spec/frontend/
+/ee/spec/frontend/
+/spec/frontend_integration/
+/ee/spec/frontend_integration/
-^[Database]
-/db/ @gitlab-org/maintainers/database
-/ee/db/ @gitlab-org/maintainers/database
-/lib/gitlab/background_migration/ @gitlab-org/maintainers/database
-/ee/lib/ee/gitlab/background_migration/ @gitlab-org/maintainers/database
-/lib/gitlab/database/ @gitlab-org/maintainers/database
-/lib/gitlab/sql/ @gitlab-org/maintainers/database
-/app/finders/ @gitlab-org/maintainers/database
-/ee/app/finders/ @gitlab-org/maintainers/database
-/rubocop/rubocop-migrations.yml @gitlab-org/maintainers/database
+^[Database] @gitlab-org/maintainers/database
+/db/
+/ee/db/
+/lib/gitlab/background_migration/
+/ee/lib/ee/gitlab/background_migration/
+/lib/gitlab/database/
+/lib/gitlab/sql/
+/app/finders/
+/ee/app/finders/
+/rubocop/rubocop-migrations.yml
-[Engineering Productivity]
-/.gitlab-ci.yml @gl-quality/eng-prod
-/.gitlab/ci/ @gl-quality/eng-prod
-/.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam
-/.gitlab/ci/package-and-test/ @gl-quality/eng-prod @gl-quality/qe-maintainers
-/.gitlab/ci/qa.gitlab-ci.yml @gl-quality/eng-prod @gl-quality/qe-maintainers
-/.gitlab/ci/releases.gitlab-ci.yml @gl-quality/eng-prod @gitlab-org/delivery
-/.gitlab/ci/reports.gitlab-ci.yml @gitlab-com/gl-security/appsec @gl-quality/eng-prod
-/.gitlab/ci/review-apps/qa.gitlab-ci.yml @gl-quality/eng-prod @gl-quality/qe-maintainers
-/.gitlab/ci/test-on-gdk/ @gl-quality/eng-prod @gl-quality/qe-maintainers
-Dangerfile @gl-quality/eng-prod
-/danger/ @gl-quality/eng-prod
-/tooling/danger/ @gl-quality/eng-prod
-/scripts/ @gl-quality/eng-prod
-/scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend
-/scripts/review_apps/seed-dast-test-data.sh @dappelt @ngeorge1 @gl-quality/eng-prod
-.editorconfig @gl-quality/eng-prod
+[Engineering Productivity] @gl-quality/eng-prod
+/.gitlab-ci.yml
+/.gitlab/ci/
+/.gitlab/ci/docs.gitlab-ci.yml @gl-docsteam
+/.gitlab/ci/package-and-test/ @gl-quality/qe-maintainers
+/.gitlab/ci/qa.gitlab-ci.yml @gl-quality/qe-maintainers
+/.gitlab/ci/releases.gitlab-ci.yml @gitlab-org/delivery
+/.gitlab/ci/reports.gitlab-ci.yml @gitlab-com/gl-security/appsec
+/.gitlab/ci/review-apps/qa.gitlab-ci.yml @gl-quality/qe-maintainers
+/.gitlab/ci/test-on-gdk/ @gl-quality/qe-maintainers
+Dangerfile
+/danger/
+/tooling/danger/
+/scripts/
+/scripts/frontend/ @gitlab-org/maintainers/frontend
+/scripts/review_apps/seed-dast-test-data.sh @dappelt @ngeorge1
+.editorconfig
-^[Backend Static Code Analysis]
-.rubocop*.yml @dstull @splattael @gl-quality/eng-prod
-.rubocop_todo.yml @dstull @splattael @gl-quality/eng-prod
-.rubocop_todo/ @dstull @splattael @gl-quality/eng-prod
-/rubocop/ @dstull @splattael @gl-quality/eng-prod
-/spec/rubocop/ @dstull @splattael @gl-quality/eng-prod
+^[Backend Static Code Analysis] @gl-quality/eng-prod @dstull @splattael
+.rubocop*.yml
+.rubocop_todo/
+/rubocop/
+/spec/rubocop/
-^[End-to-end]
-/qa/ @gl-quality
+^[End-to-end] @gl-quality
+/qa/
-^[LDAP]
-/ee/lib/ee/gitlab/auth/ldap/ @dblessing @mkozono
-/lib/gitlab/auth/ldap/ @dblessing @mkozono
+^[LDAP] @dblessing @mkozono
+/ee/lib/ee/gitlab/auth/ldap/
+/lib/gitlab/auth/ldap/
-^[Project Alias]
-/ee/app/models/project_alias.rb @patrickbajao
-/ee/lib/api/project_aliases.rb @patrickbajao
+^[Project Alias] @patrickbajao
+/ee/app/models/project_alias.rb
+/ee/lib/api/project_aliases.rb
-^[Distribution]
-/lib/support/ @gitlab-org/distribution
+^[Distribution] @gitlab-org/distribution
+/lib/support/
# Secure & Threat Management ownership delineation
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
-^[Threat Insights]
-/app/finders/security/ @gitlab-org/govern/threat-insights-backend-team
-/app/models/vulnerability.rb @gitlab-org/govern/threat-insights-backend-team
-/app/presenters/projects/security/ @gitlab-org/govern/threat-insights-backend-team
-/spec/presenters/projects/security/ @gitlab-org/govern/threat-insights-backend-team
-/ee/app/finders/security/ @gitlab-org/govern/threat-insights-backend-team
-/ee/app/models/security/ @gitlab-org/govern/threat-insights-backend-team
-/ee/app/models/vulnerabilities/ @gitlab-org/govern/threat-insights-backend-team
-/ee/app/policies/vulnerabilities/ @gitlab-org/govern/threat-insights-backend-team
-/ee/app/policies/vulnerability*.rb @gitlab-org/govern/threat-insights-backend-team
-/ee/lib/api/vulnerabilit*.rb @gitlab-org/govern/threat-insights-backend-team
-/ee/spec/policies/vulnerabilities/ @gitlab-org/govern/threat-insights-backend-team
-/ee/spec/policies/vulnerability*.rb @gitlab-org/govern/threat-insights-backend-team
-/ee/app/assets/javascripts/license_compliance/components/detected_licenses_table.vue @gitlab-org/govern/threat-insights-frontend-team
-/ee/spec/frontend/license_compliance/components/detected_licenses_table_spec.js @gitlab-org/govern/threat-insights-frontend-team
+^[Threat Insights backend] @gitlab-org/govern/threat-insights-backend-team
+/app/finders/security/
+/app/models/vulnerability.rb
+/app/presenters/projects/security/
+/spec/presenters/projects/security/
+/ee/app/finders/security/
+/ee/app/models/security/
+/ee/app/models/vulnerabilities/
+/ee/app/policies/vulnerabilities/
+/ee/app/policies/vulnerability*.rb
+/ee/lib/api/vulnerabilit*.rb
+/ee/spec/policies/vulnerabilities/
+/ee/spec/policies/vulnerability*.rb
-^[Secure]
-/ee/app/services/app_sec/dast/ @gitlab-org/secure/dynamic-analysis-be
+^[Threat Insights frontend] @gitlab-org/govern/threat-insights-frontend-team
+/ee/app/assets/javascripts/license_compliance/components/detected_licenses_table.vue
+/ee/spec/frontend/license_compliance/components/detected_licenses_table_spec.js
-^[Security Policies]
-/ee/app/assets/javascripts/approvals/components/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/approvals/stores/modules/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/pages/projects/licenses/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/pages/projects/pipelines/licenses/** @gitlab-org/govern/security-policies-frontend
+^[Secure] @gitlab-org/secure/dynamic-analysis-be
+/ee/app/services/app_sec/dast/
+
+^[Security Policies frontend] @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/approvals/components/license_compliance/**
+/ee/app/assets/javascripts/approvals/stores/modules/license_compliance/**
+/ee/app/assets/javascripts/license_compliance/**
+/ee/app/assets/javascripts/pages/projects/licenses/**
+/ee/app/assets/javascripts/pages/projects/pipelines/licenses/**
/ee/app/assets/javascripts/pages/projects/pipelines/show/license_report.js
-/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/vue_shared/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/app/views/projects/licenses/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/approvals/components/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/approvals/stores/modules/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/vue_merge_request_widget/extensions/license_compliance/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/vue_shared/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/**
+/ee/app/assets/javascripts/vue_shared/license_compliance/**
+/ee/app/views/projects/licenses/**
+/ee/spec/frontend/approvals/components/license_compliance/**
+/ee/spec/frontend/approvals/stores/modules/license_compliance/**
+/ee/spec/frontend/license_compliance/**
+/ee/spec/frontend/vue_merge_request_widget/extensions/license_compliance/**
+/ee/spec/frontend/vue_shared/license_compliance/**
-/ee/app/assets/javascripts/approvals/components/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/approvals/stores/modules/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/pages/groups/security/policies/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/pages/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/app/views/groups/security/policies @gitlab-org/govern/security-policies-frontend
-/ee/app/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/approvals/components/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/approvals/stores/modules/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/security_orchestration/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/approvals/components/security_orchestration/**
+/ee/app/assets/javascripts/approvals/stores/modules/security_orchestration/**
+/ee/app/assets/javascripts/pages/groups/security/policies/**
+/ee/app/assets/javascripts/pages/projects/security/policies/**
+/ee/app/assets/javascripts/security_orchestration/**
+/ee/app/views/groups/security/policies
+/ee/app/views/projects/security/policies/**
+/ee/spec/frontend/approvals/components/security_orchestration/**
+/ee/spec/frontend/approvals/stores/modules/security_orchestration/**
+/ee/spec/frontend/security_orchestration/**
+/ee/spec/views/projects/security/policies/**
-/app/models/clusters/applications/cilium.rb @gitlab-org/govern/security-policies-backend
-/ee/app/controllers/groups/security/policies_controller.rb @gitlab-org/govern/security-policies-backend
-/ee/app/controllers/projects/security/policies_controller.rb @gitlab-org/govern/security-policies-backend
-/ee/app/graphql/mutations/concerns/mutations/finds_project_or_group_for_security_policies.rb @gitlab-org/govern/security-policies-backend
-/ee/app/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
-/ee/app/graphql/resolvers/concerns/resolves_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
-/ee/app/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/app/graphql/types/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/app/helpers/ee/security_orchestration_helper.rb @gitlab-org/govern/security-policies-backend
-/ee/app/models/security/orchestration_policy_configuration.rb @gitlab-org/govern/security-policies-backend
-/ee/app/models/security/orchestration_policy_rule_schedule.rb @gitlab-org/govern/security-policies-backend
-/ee/app/services/security/orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/app/services/security/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/app/validators/json_schemas/security_orchestration_policy.json @gitlab-org/govern/security-policies-backend
-/ee/app/workers/concerns/update_orchestration_policy_configuration.rb @gitlab-org/govern/security-policies-backend
-/ee/app/workers/security/create_orchestration_policy_worker.rb @gitlab-org/govern/security-policies-backend
-/ee/app/workers/security/orchestration_policy_rule_schedule_namespace_worker.rb @gitlab-org/govern/security-policies-backend
-/ee/app/workers/security/orchestration_policy_rule_schedule_worker.rb @gitlab-org/govern/security-policies-backend
-/ee/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
-/ee/lib/gitlab/ci/config/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/lib/gitlab/graphql/aggregations/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/spec/controllers/groups/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/security_orchestration_policy_configurations.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/security_orchestration_policy_rule_schedules.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/security/policies.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
-/ee/spec/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/spec/graphql/types/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/spec/helpers/ee/security_orchestration_helper_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/lib/gitlab/ci/config/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/spec/lib/gitlab/graphql/aggregations/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/spec/models/security/orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/models/security/orchestration_policy_rule_schedule_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/requests/api/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
-/ee/spec/requests/api/graphql/project/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/spec/requests/projects/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/services/security/orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/spec/services/security/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
-/ee/spec/support/shared_contexts/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
-/ee/spec/views/projects/security/policies/index.html.haml_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/workers/security/create_orchestration_policy_worker_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/workers/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb @gitlab-org/govern/security-policies-backend
-/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
-/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/govern/security-policies-backend
+^[Security Policies backend] @gitlab-org/govern/security-policies-backend
+/app/models/clusters/applications/cilium.rb
+/ee/app/controllers/groups/security/policies_controller.rb
+/ee/app/controllers/projects/security/policies_controller.rb
+/ee/app/graphql/mutations/concerns/mutations/finds_project_or_group_for_security_policies.rb
+/ee/app/graphql/mutations/security_policy/**
+/ee/app/graphql/resolvers/concerns/resolves_orchestration_policy.rb
+/ee/app/graphql/resolvers/security_orchestration/**
+/ee/app/graphql/types/security_orchestration/**
+/ee/app/helpers/ee/security_orchestration_helper.rb
+/ee/app/models/security/orchestration_policy_configuration.rb
+/ee/app/models/security/orchestration_policy_rule_schedule.rb
+/ee/app/services/security/orchestration/**
+/ee/app/services/security/security_orchestration_policies/**
+/ee/app/validators/json_schemas/security_orchestration_policy.json
+/ee/app/workers/concerns/update_orchestration_policy_configuration.rb
+/ee/app/workers/security/create_orchestration_policy_worker.rb
+/ee/app/workers/security/orchestration_policy_rule_schedule_namespace_worker.rb
+/ee/app/workers/security/orchestration_policy_rule_schedule_worker.rb
+/ee/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb
+/ee/lib/gitlab/ci/config/security_orchestration_policies/**
+/ee/lib/gitlab/graphql/aggregations/security_orchestration_policies/**
+/ee/spec/controllers/groups/security/policies_controller_spec.rb
+/ee/spec/factories/security_orchestration_policy_configurations.rb
+/ee/spec/factories/security_orchestration_policy_rule_schedules.rb
+/ee/spec/factories/security/policies.rb
+/ee/spec/graphql/mutations/security_policy/**
+/ee/spec/graphql/resolvers/security_orchestration/**
+/ee/spec/graphql/types/security_orchestration/**
+/ee/spec/helpers/ee/security_orchestration_helper_spec.rb
+/ee/spec/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy_spec.rb
+/ee/spec/lib/gitlab/ci/config/security_orchestration_policies/**
+/ee/spec/lib/gitlab/graphql/aggregations/security_orchestration_policies/**
+/ee/spec/models/security/orchestration_policy_configuration_spec.rb
+/ee/spec/models/security/orchestration_policy_rule_schedule_spec.rb
+/ee/spec/requests/api/graphql/mutations/security_policy/**
+/ee/spec/requests/api/graphql/project/security_orchestration/**
+/ee/spec/requests/projects/security/policies_controller_spec.rb
+/ee/spec/services/security/orchestration/**
+/ee/spec/services/security/security_orchestration_policies/**
+/ee/spec/support/shared_contexts/graphql/resolvers/security_orchestration/**
+/ee/spec/views/projects/security/policies/index.html.haml_spec.rb
+/ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb
+/ee/spec/workers/security/create_orchestration_policy_worker_spec.rb
+/ee/spec/workers/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb
+/ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb
+/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb
+/spec/models/clusters/applications/cilium_spec.rb
-/app/finders/security/license_compliance_jobs_finder.rb @gitlab-org/govern/security-policies-backend
-/ee/app/controllers/projects/licenses_controller.rb @gitlab-org/govern/security-policies-backend
-/ee/app/finders/software_license_policies_finder.rb @gitlab-org/govern/security-policies-backend
-/ee/app/models/sca/license_compliance.rb @gitlab-org/govern/security-policies-backend @gitlab-org/secure/composition-analysis-be
-/ee/app/models/sca/license_policy.rb @gitlab-org/govern/security-policies-backend
-/ee/app/models/software_license_policy.rb @gitlab-org/govern/security-policies-backend
-/ee/app/models/software_license.rb @gitlab-org/govern/security-policies-backend
-/ee/app/serializers/license_compliance/** @gitlab-org/govern/security-policies-backend
-/ee/app/serializers/license_entity.rb @gitlab-org/govern/security-policies-backend
-/ee/app/serializers/licenses_list_entity.rb @gitlab-org/govern/security-policies-backend
-/ee/app/serializers/licenses_list_serializer.rb @gitlab-org/govern/security-policies-backend
-/ee/app/serializers/security/license_policy_entity.rb @gitlab-org/govern/security-policies-backend
-/ee/app/services/ci/compare_license_scanning_reports_collapsed_service.rb @gitlab-org/govern/security-policies-backend
-/ee/app/services/ci/compare_license_scanning_reports_service.rb @gitlab-org/govern/security-policies-backend
-/ee/app/services/software_license_policies/** @gitlab-org/govern/security-policies-backend
-/ee/app/services/software_license_policies/update_service.rb @gitlab-org/govern/security-policies-backend
-/ee/app/workers/refresh_license_compliance_checks_worker.rb @gitlab-org/govern/security-policies-backend
-/ee/lib/api/managed_licenses.rb @gitlab-org/govern/security-policies-backend
-/ee/lib/ee/api/entities/managed_license.rb @gitlab-org/govern/security-policies-backend
-/ee/lib/gitlab/spdx/license.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/software_license_policy.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/software_license.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/factories/spdx_license.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/finders/software_license_policies_finder_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/lib/gitlab/ci/parsers/license_compliance/** @gitlab-org/govern/security-policies-backend
-/ee/spec/models/sca/license_compliance_spec.rb @gitlab-org/govern/security-policies-backend @gitlab-org/secure/composition-analysis-be
-/ee/spec/models/sca/license_policy_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/models/software_license_policy_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/models/software_license_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/requests/api/managed_licenses_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/serializers/license_compliance/** @gitlab-org/govern/security-policies-backend
-/ee/spec/services/ci/compare_license_scanning_reports_collapsed_service_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/services/ci/compare_license_scanning_reports_service_spec.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/services/software_license_policies/** @gitlab-org/govern/security-policies-backend
-/spec/finders/security/license_compliance_jobs_finder_spec.rb @gitlab-org/govern/security-policies-backend
+/app/finders/security/license_compliance_jobs_finder.rb
+/ee/app/controllers/projects/licenses_controller.rb
+/ee/app/finders/software_license_policies_finder.rb
+/ee/app/models/sca/license_compliance.rb @gitlab-org/secure/composition-analysis-be
+/ee/app/models/sca/license_policy.rb
+/ee/app/models/software_license_policy.rb
+/ee/app/models/software_license.rb
+/ee/app/serializers/license_compliance/**
+/ee/app/serializers/license_entity.rb
+/ee/app/serializers/licenses_list_entity.rb
+/ee/app/serializers/licenses_list_serializer.rb
+/ee/app/serializers/security/license_policy_entity.rb
+/ee/app/services/ci/compare_license_scanning_reports_collapsed_service.rb
+/ee/app/services/ci/compare_license_scanning_reports_service.rb
+/ee/app/services/software_license_policies/**
+/ee/app/services/software_license_policies/update_service.rb
+/ee/app/workers/refresh_license_compliance_checks_worker.rb
+/ee/lib/api/managed_licenses.rb
+/ee/lib/ee/api/entities/managed_license.rb
+/ee/lib/gitlab/spdx/license.rb
+/ee/spec/factories/software_license_policy.rb
+/ee/spec/factories/software_license.rb
+/ee/spec/factories/spdx_license.rb
+/ee/spec/finders/software_license_policies_finder_spec.rb
+/ee/spec/lib/gitlab/ci/parsers/license_compliance/**
+/ee/spec/models/sca/license_compliance_spec.rb @gitlab-org/secure/composition-analysis-be
+/ee/spec/models/sca/license_policy_spec.rb
+/ee/spec/models/software_license_policy_spec.rb
+/ee/spec/models/software_license_spec.rb
+/ee/spec/requests/api/managed_licenses_spec.rb
+/ee/spec/serializers/license_compliance/**
+/ee/spec/services/ci/compare_license_scanning_reports_collapsed_service_spec.rb
+/ee/spec/services/ci/compare_license_scanning_reports_service_spec.rb
+/ee/spec/services/software_license_policies/**
+/spec/finders/security/license_compliance_jobs_finder_spec.rb
-^[Code Owners]
-/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
-/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
-/ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
-/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
+^[Code Owners] @reprazent @kerrizor @garyh
+/ee/lib/gitlab/code_owners.rb
+/ee/lib/gitlab/code_owners/
+/ee/spec/lib/gitlab/code_owners/
+/doc/user/project/code_owners.md
-^[Merge Requests]
-/app/controllers/projects/merge_requests/ @garyh @patrickbajao @marc_shaw @kerrizor
-/app/models/merge_request.rb @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/app/services/merge_requests/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/app/workers/merge_requests/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/app/workers/merge_request_mergeability_check_worker.rb @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/lib/gitlab/diff/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/lib/gitlab/discussions_diff/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/lib/gitlab/quick_actions/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
+^[Merge Requests backend] @garyh @patrickbajao @marc_shaw @kerrizor
+/app/controllers/projects/merge_requests/
+/app/models/merge_request.rb @dskim_gitlab
+/app/services/merge_requests/ @dskim_gitlab
+/app/workers/merge_requests/ @dskim_gitlab
+/app/workers/merge_request_mergeability_check_worker.rb @dskim_gitlab
+/lib/gitlab/diff/ @dskim_gitlab
+/lib/gitlab/discussions_diff/ @dskim_gitlab
+/lib/gitlab/quick_actions/ @dskim_gitlab
-/ee/app/models/ee/merge_request.rb @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/ee/app/services/merge_requests/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/ee/app/workers/merge_requests/ @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
-/ee/app/workers/merge_request_reset_approvals_worker.rb @dskim_gitlab @garyh @patrickbajao @marc_shaw @kerrizor
+/ee/app/models/ee/merge_request.rb @dskim_gitlab
+/ee/app/services/merge_requests/ @dskim_gitlab
+/ee/app/workers/merge_requests/ @dskim_gitlab
+/ee/app/workers/merge_request_reset_approvals_worker.rb @dskim_gitlab
-/app/assets/javascripts/diffs @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/batch_comments/ @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/notes @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/merge_conflicts @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/mr_notes @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/issuable/popover @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/vue_merge_request_widget @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/merge_request.js @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/javascripts/merge_request_tabs.js @viktomas @jboyson @iamphill @thomasrandolph
-/app/assets/stylesheets/framework/diffs.scss @viktomas @jboyson @iamphill @thomasrandolph
-/ee/app/assets/javascripts/diffs/ @viktomas @jboyson @iamphill @thomasrandolph
-/ee/app/assets/javascripts/vue_merge_request_widget @viktomas @jboyson @iamphill @thomasrandolph
-/spec/frontend/diffs/ @viktomas @jboyson @iamphill @thomasrandolph
-/spec/frontend/batch_comments/ @viktomas @jboyson @iamphill @thomasrandolph
+^[Merge Requests frontend] @viktomas @jboyson @iamphill @thomasrandolph
+/app/assets/javascripts/diffs
+/app/assets/javascripts/batch_comments/
+/app/assets/javascripts/notes
+/app/assets/javascripts/merge_conflicts
+/app/assets/javascripts/mr_notes
+/app/assets/javascripts/issuable/popover
+/app/assets/javascripts/vue_merge_request_widget
+/app/assets/javascripts/merge_request.js
+/app/assets/javascripts/merge_request_tabs.js
+/app/assets/stylesheets/framework/diffs.scss
+/ee/app/assets/javascripts/diffs/
+/ee/app/assets/javascripts/vue_merge_request_widget
+/spec/frontend/diffs/
+/spec/frontend/batch_comments/
^[Product Analytics] @gitlab-org/analytics-section/product-analytics/engineers/frontend
/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard.vue
@@ -273,118 +278,118 @@ Dangerfile @gl-quality/eng-prod
/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/panels_base.vue
/ee/app/assets/javascripts/product_analytics/
-^[Product Intelligence]
-/ee/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/lib/gitlab/usage_data.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/lib/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/lib/ee/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/lib/ee/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
-/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
-/app/workers/gitlab_service_ping_worker.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/spec/workers/gitlab_service_ping_worker_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/spec/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/spec/lib/ee/gitlab/usage_data_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/spec/lib/gitlab/usage_data_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
-/spec/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/spec/lib/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/spec/lib/ee/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/spec/lib/ee/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
-/ee/spec/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
+^[Product Intelligence] @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/lib/gitlab/usage_data_counters/
+/ee/lib/ee/gitlab/usage_data.rb
+/lib/gitlab/usage_data.rb
+/lib/gitlab/usage_data_counters/
+/lib/gitlab/usage/
+/ee/lib/ee/gitlab/usage_data_counters/
+/ee/lib/ee/gitlab/usage/
+/config/metrics/
+/ee/config/metrics/
+/app/workers/gitlab_service_ping_worker.rb
+/spec/workers/gitlab_service_ping_worker_spec.rb
+/ee/spec/lib/gitlab/usage_data_counters/
+/ee/spec/lib/ee/gitlab/usage_data_spec.rb
+/spec/lib/gitlab/usage_data_spec.rb
+/spec/lib/gitlab/usage_data_counters/
+/spec/lib/gitlab/usage/
+/ee/spec/lib/ee/gitlab/usage_data_counters/
+/ee/spec/lib/ee/gitlab/usage/
+/ee/spec/config/metrics/
-^[Growth Experiments]
-/app/experiments/ @gitlab-org/growth/experiment-devs
-/spec/experiments/ @gitlab-org/growth/experiment-devs
-/config/initializers/gitlab_experiment.rb @gitlab-org/growth/experiment-devs
-/config/feature_flags/experiment/ @gitlab-org/growth/experiment-devs
-/ee/config/feature_flags/experiment/ @gitlab-org/growth/experiment-devs
-/ee/lib/api/experiments.rb @gitlab-org/growth/experiment-devs
-/ee/spec/requests/api/experiments_spec.rb @gitlab-org/growth/experiment-devs
-/ee/lib/ee/api/entities/experiment.rb @gitlab-org/growth/experiment-devs
-/ee/spec/lib/ee/api/entities/experiment_spec.rb @gitlab-org/growth/experiment-devs
+^[Growth Experiments] @gitlab-org/growth/experiment-devs
+/app/experiments/
+/spec/experiments/
+/config/initializers/gitlab_experiment.rb
+/config/feature_flags/experiment/
+/ee/config/feature_flags/experiment/
+/ee/lib/api/experiments.rb
+/ee/spec/requests/api/experiments_spec.rb
+/ee/lib/ee/api/entities/experiment.rb
+/ee/spec/lib/ee/api/entities/experiment_spec.rb
-^[Growth]
-/ee/app/workers/onboarding/ @gitlab-org/growth/engineers
-/ee/spec/workers/onboarding/ @gitlab-org/growth/engineers
-/app/models/onboarding/ @gitlab-org/growth/engineers
-/spec/models/onboarding/ @gitlab-org/growth/engineers
-/app/services/onboarding/ @gitlab-org/growth/engineers
-/spec/services/onboarding/ @gitlab-org/growth/engineers
-/ee/app/components/namespaces/free_user_cap/ @gitlab-org/growth/engineers
-/ee/spec/components/namespaces/free_user_cap/ @gitlab-org/growth/engineers
-/ee/app/models/namespaces/free_user_cap/ @gitlab-org/growth/engineers
-/ee/spec/models/namespaces/free_user_cap/ @gitlab-org/growth/engineers
-/app/controllers/registrations_controller.rb @gitlab-org/growth/engineers
-/spec/controllers/registrations_controller_spec.rb @gitlab-org/growth/engineers
-/app/controllers/registrations/ @gitlab-org/growth/engineers
-/spec/controllers/registrations/ @gitlab-org/growth/engineers
-/app/controllers/confirmations_controller.rb @gitlab-org/growth/engineers
-/spec/controllers/confirmations_controller_spec.rb @gitlab-org/growth/engineers
-/ee/app/controllers/trial_registrations_controller.rb @gitlab-org/growth/engineers
-/ee/spec/controllers/trial_registrations_controller_spec.rb @gitlab-org/growth/engineers
-/ee/spec/requests/trial_registrations_controller_spec.rb @gitlab-org/growth/engineers
-/ee/app/controllers/registrations/ @gitlab-org/growth/engineers
-/ee/spec/controllers/registrations/ @gitlab-org/growth/engineers
-/ee/spec/requests/registrations/ @gitlab-org/growth/engineers
-/ee/app/controllers/ee/registrations_controller.rb @gitlab-org/growth/engineers
-/ee/spec/controllers/ee/registrations_controller_spec.rb @gitlab-org/growth/engineers
-/ee/app/controllers/ee/registrations/ @gitlab-org/growth/engineers
-/ee/app/controllers/ee/confirmations_controller.rb @gitlab-org/growth/engineers
-/ee/app/controllers/subscriptions_controller.rb @gitlab-org/growth/engineers
-/ee/spec/controllers/subscriptions_controller_spec.rb @gitlab-org/growth/engineers
-/ee/app/controllers/subscriptions/ @gitlab-org/growth/engineers
-/ee/spec/controllers/subscriptions/ @gitlab-org/growth/engineers
-/app/services/users/in_product_marketing_email_records.rb @gitlab-org/growth/engineers
-/spec/services/users/in_product_marketing_email_records_spec.rb @gitlab-org/growth/engineers
-/app/workers/namespaces/in_product_marketing_emails_worker.rb @gitlab-org/growth/engineers
-/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb @gitlab-org/growth/engineers
-/ee/app/workers/ee/namespaces/in_product_marketing_emails_worker.rb @gitlab-org/growth/engineers
-/ee/spec/workers/ee/namespaces/in_product_marketing_emails_worker_spec.rb @gitlab-org/growth/engineers
-/app/models/users/in_product_marketing_email.rb @gitlab-org/growth/engineers
-/spec/models/users/in_product_marketing_email_spec.rb @gitlab-org/growth/engineers
-/app/services/namespaces/in_product_marketing_emails_service.rb @gitlab-org/growth/engineers
-/spec/services/namespaces/in_product_marketing_emails_service_spec.rb @gitlab-org/growth/engineers
-/ee/app/services/ee/namespaces/in_product_marketing_emails_service.rb @gitlab-org/growth/engineers
-/ee/spec/services/namespaces/in_product_marketing_emails_service_spec.rb @gitlab-org/growth/engineers
-/app/workers/projects/record_target_platforms_worker.rb @gitlab-org/growth/engineers
-/spec/workers/projects/record_target_platforms_worker_spec.rb @gitlab-org/growth/engineers
+^[Growth] @gitlab-org/growth/engineers
+/ee/app/workers/onboarding/
+/ee/spec/workers/onboarding/
+/app/models/onboarding/
+/spec/models/onboarding/
+/app/services/onboarding/
+/spec/services/onboarding/
+/ee/app/components/namespaces/free_user_cap/
+/ee/spec/components/namespaces/free_user_cap/
+/ee/app/models/namespaces/free_user_cap/
+/ee/spec/models/namespaces/free_user_cap/
+/app/controllers/registrations_controller.rb
+/spec/controllers/registrations_controller_spec.rb
+/app/controllers/registrations/
+/spec/controllers/registrations/
+/app/controllers/confirmations_controller.rb
+/spec/controllers/confirmations_controller_spec.rb
+/ee/app/controllers/trial_registrations_controller.rb
+/ee/spec/controllers/trial_registrations_controller_spec.rb
+/ee/spec/requests/trial_registrations_controller_spec.rb
+/ee/app/controllers/registrations/
+/ee/spec/controllers/registrations/
+/ee/spec/requests/registrations/
+/ee/app/controllers/ee/registrations_controller.rb
+/ee/spec/controllers/ee/registrations_controller_spec.rb
+/ee/app/controllers/ee/registrations/
+/ee/app/controllers/ee/confirmations_controller.rb
+/ee/app/controllers/subscriptions_controller.rb
+/ee/spec/controllers/subscriptions_controller_spec.rb
+/ee/app/controllers/subscriptions/
+/ee/spec/controllers/subscriptions/
+/app/services/users/in_product_marketing_email_records.rb
+/spec/services/users/in_product_marketing_email_records_spec.rb
+/app/workers/namespaces/in_product_marketing_emails_worker.rb
+/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
+/ee/app/workers/ee/namespaces/in_product_marketing_emails_worker.rb
+/ee/spec/workers/ee/namespaces/in_product_marketing_emails_worker_spec.rb
+/app/models/users/in_product_marketing_email.rb
+/spec/models/users/in_product_marketing_email_spec.rb
+/app/services/namespaces/in_product_marketing_emails_service.rb
+/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+/ee/app/services/ee/namespaces/in_product_marketing_emails_service.rb
+/ee/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+/app/workers/projects/record_target_platforms_worker.rb
+/spec/workers/projects/record_target_platforms_worker_spec.rb
-^[Legal]
-/config/dependency_decisions.yml @gitlab-org/legal-reviewers
+^[Legal] @gitlab-org/legal-reviewers
+/config/dependency_decisions.yml
-^[Workhorse]
-/workhorse/ @jacobvosmaer-gitlab @nolith @patrickbajao @igor.drozdov
+^[Workhorse] @jacobvosmaer-gitlab @nolith @patrickbajao @igor.drozdov
+/workhorse/
-[Application Security]
-/app/assets/javascripts/lib/dompurify.js @gitlab-com/gl-security/appsec
-/app/assets/javascripts/gfm_auto_complete.js @gitlab-com/gl-security/appsec
-/ee/app/assets/javascripts/gfm_auto_complete.js @gitlab-com/gl-security/appsec
-/app/validators/addressable_url_validator.rb @gitlab-com/gl-security/appsec
-/app/validators/public_url_validator.rb @gitlab-com/gl-security/appsec
-/config/initializers/content_security_policy.rb @gitlab-com/gl-security/appsec
-/lib/gitlab/content_security_policy/ @gitlab-com/gl-security/appsec
-/lib/gitlab/http.rb @gitlab-com/gl-security/appsec
-/lib/gitlab/http_connection_adapter.rb @gitlab-com/gl-security/appsec
-/lib/gitlab/sanitizers @gitlab-com/gl-security/appsec
-/lib/gitlab/untrusted_regexp.rb @gitlab-com/gl-security/appsec
-/lib/gitlab/url_blocker.rb @gitlab-com/gl-security/appsec
-/lib/gitlab/url_blockers/ @gitlab-com/gl-security/appsec
-/lib/gitlab/utils.rb @gitlab-com/gl-security/appsec
+[Application Security] @gitlab-com/gl-security/appsec
+/app/assets/javascripts/lib/dompurify.js
+/app/assets/javascripts/gfm_auto_complete.js
+/ee/app/assets/javascripts/gfm_auto_complete.js
+/app/validators/addressable_url_validator.rb
+/app/validators/public_url_validator.rb
+/config/initializers/content_security_policy.rb
+/lib/gitlab/content_security_policy/
+/lib/gitlab/http.rb
+/lib/gitlab/http_connection_adapter.rb
+/lib/gitlab/sanitizers
+/lib/gitlab/untrusted_regexp.rb
+/lib/gitlab/url_blocker.rb
+/lib/gitlab/url_blockers/
+/lib/gitlab/utils.rb
-^[Gitaly]
-lib/gitlab/git_access.rb @proglottis @toon
-lib/gitlab/git_access_*.rb @proglottis @toon
-ee/lib/ee/gitlab/git_access.rb @proglottis @toon
-ee/lib/ee/gitlab/git_access_*.rb @proglottis @toon
-ee/lib/ee/gitlab/checks/** @proglottis @toon
-lib/gitlab/checks/** @proglottis @toon
+^[Gitaly] @proglottis @toon
+lib/gitlab/git_access.rb
+lib/gitlab/git_access_*.rb
+ee/lib/ee/gitlab/git_access.rb
+ee/lib/ee/gitlab/git_access_*.rb
+ee/lib/ee/gitlab/checks/**
+lib/gitlab/checks/**
-^[Documentation Directories]
-/doc/ @gl-docsteam
-/data/deprecations/ @gl-docsteam
-/data/removals/ @gl-docsteam
+^[Documentation Directories] @gl-docsteam
+/doc/
+/data/deprecations/
+/data/removals/
^[Documentation Pages]
# This block is managed by the rake script at lib/tasks/gitlab/tw/codeowners.rake, manual updates will be overwritten!
@@ -978,253 +983,252 @@ lib/gitlab/checks/** @proglottis @toon
/doc/user/workspace/quick_start/ @ashrafkhamis
# End rake-managed-docs-block
-[Authentication and Authorization]
-/app/assets/javascripts/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/authentication/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/ide/components/shared/tokened_input.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/packages_and_registries/package_registry/components/list/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/admin/impersonation_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/groups/settings/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/ldap/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/omniauth_callbacks/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/profiles/password_prompt/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/profiles/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/profiles/two_factor_auths/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/projects/settings/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/projects/settings/topics/components/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/related_issues/components/issue_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/stylesheets/page_bundles/profile_two_factor_auth.scss @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/admin/impersonation_tokens_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/access_tokens_actions.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/authenticates_with_two_factor.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/enforces_admin_authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/enforces_two_factor_authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/oauth_applications.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/project_unauthorized.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/require_email_verification.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/sessionless_authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/snippet_authorizations.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/verifies_with_email.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/concerns/workhorse_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/groups/settings/access_tokens_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/ldap/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/omniauth_callbacks_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/passwords_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/profiles/passwords_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/profiles/personal_access_tokens_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/profiles/two_factor_auths_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/profiles/webauthn_registrations_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/projects/settings/access_tokens_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/controllers/sessions_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/finders/groups/projects_requiring_authorizations_refresh/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/finders/personal_access_tokens_finder.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/helpers/access_tokens_helper.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/helpers/auth_helper.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/authentication_event.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/admin_changed_password_notifier.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/mirror_authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/select_for_project_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/token_authenticatable.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/concerns/token_authenticatable_strategies/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/oauth_access_grant.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/oauth_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/personal_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/project_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/token_with_iv.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/models/webauthn_registration.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/policies/personal_access_token_policy.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/access_token_entity_base.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/group_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/group_access_token_serializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/impersonation_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/impersonation_access_token_serializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/personal_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/personal_access_token_serializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/project_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/serializers/project_access_token_serializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/access_token_validation_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/authorized_project_update/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/chat_names/authorize_user_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/projects/move_project_authorizations_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/resource_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/todos/destroy/unauthorized_features_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/users/authorized_build_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/users/authorized_create_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/users/email_verification/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/users/refresh_authorized_projects_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/services/webauthn/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/validators/json_schemas/cluster_agent_authorization_configuration.json @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/admin/application_settings/_external_authorization_service_form.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/admin/impersonation_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/authentication/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/dashboard/projects/_zero_authorized_projects.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/password_change.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/password_change.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/password_change_by_admin.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/password_change_by_admin.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/reset_password_instructions.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/mailer/reset_password_instructions.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/**/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/doorkeeper/authorizations/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/doorkeeper/authorized_applications/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/errors/omniauth_error.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/groups/settings/_resource_access_token_creation.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/groups/settings/_two_factor_auth.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/groups/settings/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/layouts/oauth_error.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_about_to_expire_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_about_to_expire_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_created_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_created_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_expired_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_expired_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_revoked_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/notify/access_token_revoked_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/profiles/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/profiles/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/profiles/two_factor_auths/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/projects/mirrors/_authentication_method.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/projects/settings/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/shared/_no_password.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/shared/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/shared/members/_two_factor_auth_badge.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/shared/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/workers/authorized_keys_worker.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/workers/authorized_project_update/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/workers/authorized_projects_worker.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/app/workers/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/01_secret_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/devise_dynamic_password_length_validation.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/devise_password_length.rb.example @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/gitlab_shell_secret_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/omniauth.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/rails_host_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/rails_host_authorization_gitpod.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers/webauthn.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers_before_autoloader/100_patch_omniauth_oauth2.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/initializers_before_autoloader/100_patch_omniauth_saml.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/config/weak_password_digests.yml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/audit_events/components/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/audit_events/token_utils.js @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/batch_comments/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/groups/settings/components/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/pages/admin/application_settings/general/components/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/pages/groups/omniauth_callbacks/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/pages/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/pages/profiles/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/password/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/requirements/components/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/saml_providers/scim_token_service.js @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/saml_sso/components/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_auth.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/concerns/ee/authenticates_with_two_factor.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/concerns/ee/enforces_two_factor_authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/concerns/saml_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/ee/ldap/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/ee/omniauth_callbacks_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/ee/passwords_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/ee/sessions_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/groups/omniauth_callbacks_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/groups/scim_oauth_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/omniauth_kerberos_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/controllers/users/identity_verification_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/finders/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/helpers/ee/access_tokens_helper.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/helpers/ee/auth_helper.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/helpers/ee/personal_access_tokens_helper.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/models/concerns/identity_verifiable.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/models/concerns/password_complexity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/models/ee/personal_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/models/ee/project_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/models/scim_oauth_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/serializers/scim_oauth_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/arkose/token_verification_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/ee/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/ee/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/ee/resource_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/ee/users/authorized_build_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/security/token_revocation_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/services/users/email_verification/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/validators/password/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/admin/application_settings/_personal_access_token_expiration_policy.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/credentials_inventory_mailer/personal_access_token_revoked_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/credentials_inventory_mailer/personal_access_token_revoked_email.text.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/devise/**/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/groups/_personal_access_token_expiration_policy.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/groups/sso/_authorize_pane.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/notify/policy_revoked_personal_access_tokens_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/notify/policy_revoked_personal_access_tokens_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/shared/_password_requirements_list.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/shared/credentials_inventory/_personal_access_tokens.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/views/shared/credentials_inventory/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/workers/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/workers/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/config/routes/oauth.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/ee/gitlab/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/ee/gitlab/omniauth_initializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/gitlab/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/gitlab/authority_analyzer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/gitlab/geo/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/gitlab/kerberos/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/omni_auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/system_check/geo/authorized_keys_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/system_check/geo/authorized_keys_flag_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/impersonation_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/impersonation_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/personal_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/personal_access_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/resource_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/resource_access_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/helpers/authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/helpers/packages/basic_auth_helpers.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/helpers/personal_access_tokens_helpers.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/personal_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/resource_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/support/token_with_expiration.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/api_authentication/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/auth.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/auth_logger.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/authorized_keys.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/background_migration/encrypt_static_object_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/background_migration/expire_o_auth_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/background_migration/migrate_u2f_webauthn.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/chat_name_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/cleanup/personal_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/external_authorization/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/external_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/grape_logging/loggers/token_logger.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/graphql/authorize/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/jwt_authenticatable.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/jwt_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/lfs_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/mail_room/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/omniauth_initializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/project_authorizations.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/json_web_token/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/omni_auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/security/weak_passwords.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/system_check/app/authorized_keys_permission_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/system_check/incoming_email/imap_authentication_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/tasks/gitlab/password.rake @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/tasks/tokens.rake @gitlab-org/manage/authentication-and-authorization/approvers
+[Authentication and Authorization] @gitlab-org/manage/authentication-and-authorization/approvers
+/app/assets/javascripts/access_tokens/
+/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql
+/app/assets/javascripts/authentication/
+/app/assets/javascripts/ide/components/shared/tokened_input.vue
+/app/assets/javascripts/packages_and_registries/package_registry/components/list/tokens/
+/app/assets/javascripts/pages/admin/impersonation_tokens/
+/app/assets/javascripts/pages/groups/settings/access_tokens/
+/app/assets/javascripts/pages/ldap/
+/app/assets/javascripts/pages/oauth/
+/app/assets/javascripts/pages/omniauth_callbacks/
+/app/assets/javascripts/pages/profiles/password_prompt/
+/app/assets/javascripts/pages/profiles/personal_access_tokens/
+/app/assets/javascripts/pages/profiles/two_factor_auths/
+/app/assets/javascripts/pages/projects/settings/access_tokens/
+/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
+/app/assets/javascripts/projects/settings/topics/components/
+/app/assets/javascripts/related_issues/components/issue_token.vue
+/app/assets/stylesheets/page_bundles/profile_two_factor_auth.scss
+/app/controllers/admin/impersonation_tokens_controller.rb
+/app/controllers/concerns/access_tokens_actions.rb
+/app/controllers/concerns/authenticates_with_two_factor.rb
+/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
+/app/controllers/concerns/enforces_admin_authentication.rb
+/app/controllers/concerns/enforces_two_factor_authentication.rb
+/app/controllers/concerns/oauth_applications.rb
+/app/controllers/concerns/project_unauthorized.rb
+/app/models/concerns/require_email_verification.rb
+/app/controllers/concerns/sessionless_authentication.rb
+/app/controllers/concerns/snippet_authorizations.rb
+/app/controllers/concerns/verifies_with_email.rb
+/app/controllers/concerns/workhorse_authorization.rb
+/app/controllers/groups/settings/access_tokens_controller.rb
+/app/controllers/ldap/
+/app/controllers/oauth/
+/app/controllers/omniauth_callbacks_controller.rb
+/app/controllers/passwords_controller.rb
+/app/controllers/profiles/passwords_controller.rb
+/app/controllers/profiles/personal_access_tokens_controller.rb
+/app/controllers/profiles/two_factor_auths_controller.rb
+/app/controllers/profiles/webauthn_registrations_controller.rb
+/app/controllers/projects/settings/access_tokens_controller.rb
+/app/controllers/sessions_controller.rb
+/app/finders/groups/projects_requiring_authorizations_refresh/
+/app/finders/personal_access_tokens_finder.rb
+/app/helpers/access_tokens_helper.rb
+/app/helpers/auth_helper.rb
+/app/models/authentication_event.rb
+/app/models/concerns/admin_changed_password_notifier.rb
+/app/models/concerns/mirror_authentication.rb
+/app/models/concerns/select_for_project_authorization.rb
+/app/models/concerns/token_authenticatable.rb
+/app/models/concerns/token_authenticatable_strategies/
+/app/models/oauth_access_grant.rb
+/app/models/oauth_access_token.rb
+/app/models/personal_access_token.rb
+/app/models/project_authorization.rb
+/app/models/token_with_iv.rb
+/app/models/webauthn_registration.rb
+/app/policies/personal_access_token_policy.rb
+/app/serializers/access_token_entity_base.rb
+/app/serializers/group_access_token_entity.rb
+/app/serializers/group_access_token_serializer.rb
+/app/serializers/impersonation_access_token_entity.rb
+/app/serializers/impersonation_access_token_serializer.rb
+/app/serializers/personal_access_token_entity.rb
+/app/serializers/personal_access_token_serializer.rb
+/app/serializers/project_access_token_entity.rb
+/app/serializers/project_access_token_serializer.rb
+/app/services/access_token_validation_service.rb
+/app/services/auth/
+/app/services/authorized_project_update/
+/app/services/chat_names/authorize_user_service.rb
+/app/services/personal_access_tokens/
+/app/services/projects/move_project_authorizations_service.rb
+/app/services/resource_access_tokens/
+/app/services/todos/destroy/unauthorized_features_service.rb
+/app/services/users/authorized_build_service.rb
+/app/services/users/authorized_create_service.rb
+/app/services/users/email_verification/
+/app/services/users/refresh_authorized_projects_service.rb
+/app/services/webauthn/
+/app/validators/json_schemas/cluster_agent_authorization_configuration.json
+/app/views/admin/application_settings/_external_authorization_service_form.html.haml
+/app/views/admin/impersonation_tokens/
+/app/views/authentication/
+/app/views/dashboard/projects/_zero_authorized_projects.html.haml
+/app/views/devise/mailer/password_change.html.haml
+/app/views/devise/mailer/password_change.text.erb
+/app/views/devise/mailer/password_change_by_admin.html.haml
+/app/views/devise/mailer/password_change_by_admin.text.erb
+/app/views/devise/mailer/reset_password_instructions.html.haml
+/app/views/devise/mailer/reset_password_instructions.text.erb
+/app/views/devise/**/
+/app/views/doorkeeper/authorizations/
+/app/views/doorkeeper/authorized_applications/
+/app/views/errors/omniauth_error.html.haml
+/app/views/groups/settings/_resource_access_token_creation.html.haml
+/app/views/groups/settings/_two_factor_auth.html.haml
+/app/views/groups/settings/access_tokens/
+/app/views/layouts/oauth_error.html.haml
+/app/views/notify/access_token_about_to_expire_email.html.haml
+/app/views/notify/access_token_about_to_expire_email.text.erb
+/app/views/notify/access_token_created_email.html.haml
+/app/views/notify/access_token_created_email.text.erb
+/app/views/notify/access_token_expired_email.html.haml
+/app/views/notify/access_token_expired_email.text.erb
+/app/views/notify/access_token_revoked_email.html.haml
+/app/views/notify/access_token_revoked_email.text.erb
+/app/views/profiles/passwords/
+/app/views/profiles/personal_access_tokens/
+/app/views/profiles/two_factor_auths/
+/app/views/projects/mirrors/_authentication_method.html.haml
+/app/views/projects/settings/access_tokens/
+/app/views/shared/_no_password.html.haml
+/app/views/shared/_two_factor_auth_recovery_settings_check.html.haml
+/app/views/shared/access_tokens/
+/app/views/shared/members/_two_factor_auth_badge.html.haml
+/app/views/shared/tokens/
+/app/workers/authorized_keys_worker.rb
+/app/workers/authorized_project_update/
+/app/workers/authorized_projects_worker.rb
+/app/workers/personal_access_tokens/
+/config/initializers/01_secret_token.rb
+/config/initializers/devise_dynamic_password_length_validation.rb
+/config/initializers/devise_password_length.rb.example
+/config/initializers/gitlab_shell_secret_token.rb
+/config/initializers/omniauth.rb
+/config/initializers/rails_host_authorization.rb
+/config/initializers/rails_host_authorization_gitpod.rb
+/config/initializers/webauthn.rb
+/config/initializers_before_autoloader/100_patch_omniauth_oauth2.rb
+/config/initializers_before_autoloader/100_patch_omniauth_saml.rb
+/config/weak_password_digests.yml
+/ee/app/assets/javascripts/access_tokens/
+/ee/app/assets/javascripts/audit_events/components/tokens/
+/ee/app/assets/javascripts/audit_events/token_utils.js
+/ee/app/assets/javascripts/batch_comments/
+/ee/app/assets/javascripts/groups/settings/components/
+/ee/app/assets/javascripts/pages/admin/application_settings/general/components/
+/ee/app/assets/javascripts/pages/groups/omniauth_callbacks/
+/ee/app/assets/javascripts/pages/passwords/
+/ee/app/assets/javascripts/pages/profiles/passwords/
+/ee/app/assets/javascripts/password/
+/ee/app/assets/javascripts/requirements/components/tokens/
+/ee/app/assets/javascripts/saml_providers/scim_token_service.js
+/ee/app/assets/javascripts/saml_sso/components/
+/ee/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_auth.vue
+/ee/app/controllers/concerns/ee/authenticates_with_two_factor.rb
+/ee/app/controllers/concerns/ee/enforces_two_factor_authentication.rb
+/ee/app/controllers/concerns/saml_authorization.rb
+/ee/app/controllers/ee/ldap/
+/ee/app/controllers/ee/omniauth_callbacks_controller.rb
+/ee/app/controllers/ee/passwords_controller.rb
+/ee/app/controllers/ee/sessions_controller.rb
+/ee/app/controllers/groups/omniauth_callbacks_controller.rb
+/ee/app/controllers/groups/scim_oauth_controller.rb
+/ee/app/controllers/oauth/
+/ee/app/controllers/omniauth_kerberos_controller.rb
+/ee/app/controllers/users/identity_verification_controller.rb
+/ee/app/finders/auth/
+/ee/app/helpers/ee/access_tokens_helper.rb
+/ee/app/helpers/ee/auth_helper.rb
+/ee/app/helpers/ee/personal_access_tokens_helper.rb
+/ee/app/models/concerns/identity_verifiable.rb
+/ee/app/models/concerns/password_complexity.rb
+/ee/app/models/ee/personal_access_token.rb
+/ee/app/models/ee/project_authorization.rb
+/ee/app/models/scim_oauth_access_token.rb
+/ee/app/serializers/scim_oauth_access_token_entity.rb
+/ee/app/services/arkose/token_verification_service.rb
+/ee/app/services/ee/auth/
+/ee/app/services/ee/personal_access_tokens/
+/ee/app/services/ee/resource_access_tokens/
+/ee/app/services/ee/users/authorized_build_service.rb
+/ee/app/services/personal_access_tokens/
+/ee/app/services/security/token_revocation_service.rb
+/ee/app/services/users/email_verification/
+/ee/app/validators/password/
+/ee/app/views/admin/application_settings/_personal_access_token_expiration_policy.html.haml
+/ee/app/views/credentials_inventory_mailer/personal_access_token_revoked_email.html.haml
+/ee/app/views/credentials_inventory_mailer/personal_access_token_revoked_email.text.haml
+/app/views/devise/**/
+/ee/app/views/groups/_personal_access_token_expiration_policy.html.haml
+/ee/app/views/groups/sso/_authorize_pane.html.haml
+/ee/app/views/notify/policy_revoked_personal_access_tokens_email.html.haml
+/ee/app/views/notify/policy_revoked_personal_access_tokens_email.text.erb
+/ee/app/views/oauth/
+/ee/app/views/shared/_password_requirements_list.html.haml
+/ee/app/views/shared/credentials_inventory/_personal_access_tokens.html.haml
+/ee/app/views/shared/credentials_inventory/personal_access_tokens/
+/ee/app/workers/auth/
+/ee/app/workers/personal_access_tokens/
+/ee/config/routes/oauth.rb
+/ee/lib/ee/gitlab/auth/
+/ee/lib/ee/gitlab/omniauth_initializer.rb
+/ee/lib/gitlab/auth/
+/ee/lib/gitlab/authority_analyzer.rb
+/ee/lib/gitlab/geo/oauth/
+/ee/lib/gitlab/kerberos/
+/ee/lib/omni_auth/
+/ee/lib/system_check/geo/authorized_keys_check.rb
+/ee/lib/system_check/geo/authorized_keys_flag_check.rb
+/lib/api/entities/impersonation_token.rb
+/lib/api/entities/impersonation_token_with_token.rb
+/lib/api/entities/personal_access_token.rb
+/lib/api/entities/personal_access_token_with_token.rb
+/lib/api/entities/resource_access_token.rb
+/lib/api/entities/resource_access_token_with_token.rb
+/lib/api/helpers/authentication.rb
+/lib/api/helpers/packages/basic_auth_helpers.rb
+/lib/api/helpers/personal_access_tokens_helpers.rb
+/lib/api/personal_access_tokens/
+/lib/api/personal_access_tokens.rb
+/lib/api/resource_access_tokens.rb
+/lib/api/support/token_with_expiration.rb
+/lib/gitlab/api_authentication/
+/lib/gitlab/auth/
+/lib/gitlab/auth.rb
+/lib/gitlab/auth_logger.rb
+/lib/gitlab/authorized_keys.rb
+/lib/gitlab/background_migration/encrypt_static_object_token.rb
+/lib/gitlab/background_migration/expire_o_auth_tokens.rb
+/lib/gitlab/background_migration/migrate_u2f_webauthn.rb
+/lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb
+/lib/gitlab/chat_name_token.rb
+/lib/gitlab/cleanup/personal_access_tokens.rb
+/lib/gitlab/external_authorization/
+/lib/gitlab/external_authorization.rb
+/lib/gitlab/grape_logging/loggers/token_logger.rb
+/lib/gitlab/graphql/authorize/
+/lib/gitlab/jwt_authenticatable.rb
+/lib/gitlab/jwt_token.rb
+/lib/gitlab/lfs_token.rb
+/lib/gitlab/mail_room/
+/lib/gitlab/omniauth_initializer.rb
+/lib/gitlab/project_authorizations.rb
+/lib/json_web_token/
+/lib/omni_auth/
+/lib/security/weak_passwords.rb
+/lib/system_check/app/authorized_keys_permission_check.rb
+/lib/system_check/incoming_email/imap_authentication_check.rb
+/lib/tasks/gitlab/password.rake
+/lib/tasks/tokens.rake
-[Verify] @gitlab-org/maintainers/cicd-verify @shinya.maeda @stanhu @ayufan
-# Verify Backend
+[Verify backend] @gitlab-org/maintainers/cicd-verify @shinya.maeda @stanhu @ayufan
/**/app/**/ci/
/**/lib/**/ci/
/**/spec/**/ci/
@@ -1336,17 +1340,26 @@ lib/gitlab/checks/** @proglottis @toon
/ee/spec/controllers/projects/subscriptions_controller_spec.rb
/ee/spec/helpers/ee/projects/pipeline_helper_spec.rb
/ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb
+# Overrides for Verify. These files below require approval from teams outside Verify.
+/**/ci/reports/**/ @gitlab-org/maintainers/rails-backend
+/**/ci/parsers/**/ @gitlab-org/maintainers/rails-backend
+/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
+/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/govern/threat-insights-backend-team
+/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be
+/ee/lib/gitlab/ci/reports/dependency_list/ @gitlab-org/secure/composition-analysis-be
+/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
+/ee/lib/gitlab/ci/reports/security/ @gitlab-org/govern/threat-insights-backend-team
-# Verify Frontend
-/**/spec/frontend/**/ci/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/pipelines/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/jobs/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/token_access/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/admin/application_settings/runner_token_expiration/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend @sheldonled @aalakkad @kpalchyk
+[Verify frontend] @gitlab-org/ci-cd/verify/frontend
+/**/spec/frontend/**/ci/
+/**/javascripts/ci/
+/**/javascripts/pipelines/
+/**/javascripts/jobs/
+/**/javascripts/token_access/
+/**/javascripts/admin/application_settings/runner_token_expiration/
+/**/javascripts/usage_quotas/pipelines/ @sheldonled @aalakkad @kpalchyk
-# CI/CD templates
+[CI/CD templates]
/lib/gitlab/ci/templates/ @gitlab-org/maintainers/cicd-templates
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @gonzoyumo @twoodham @sethgitlab @thiagocsf
@@ -1366,93 +1379,83 @@ lib/gitlab/checks/** @proglottis @toon
/lib/gitlab/ci/templates/Jobs/SAST.*.yml @gitlab-org/secure/static-analysis
/lib/gitlab/ci/templates/Jobs/Secret-Detection.*.yml @gitlab-org/secure/static-analysis
-# Overrides for Verify. These files below require approval from teams outside Verify.
-/**/ci/reports/**/ @gitlab-org/maintainers/rails-backend
-/**/ci/parsers/**/ @gitlab-org/maintainers/rails-backend
-/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
-/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/govern/threat-insights-backend-team
-/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be
-/ee/lib/gitlab/ci/reports/dependency_list/ @gitlab-org/secure/composition-analysis-be
-/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
-/ee/lib/gitlab/ci/reports/security/ @gitlab-org/govern/threat-insights-backend-team
-
-[Manage::Workspace]
-lib/api/entities/basic_project_details.rb @gitlab-org/manage/manage-workspace/backend-approvers
-lib/api/entities/project_with_access.rb @gitlab-org/manage/manage-workspace/backend-approvers
-lib/api/entities/project_identity.rb @gitlab-org/manage/manage-workspace/backend-approvers
-lib/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-approvers
-ee/lib/ee/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-approvers
+[Manage::Workspace] @gitlab-org/manage/manage-workspace/backend-approvers
+lib/api/entities/basic_project_details.rb
+lib/api/entities/project_with_access.rb
+lib/api/entities/project_identity.rb
+lib/api/entities/project.rb
+ee/lib/ee/api/entities/project.rb
-[Compliance]
-/app/services/audit_events/build_service.rb @gitlab-org/govern/compliance
-/ee/spec/services/audit_events/custom_audit_event_service_spec.rb @gitlab-org/govern/compliance
-/app/models/audit_event.rb @gitlab-org/govern/compliance
-/app/services/audit_event_service.rb @gitlab-org/govern/compliance
-/app/services/concerns/audit_event_save_type.rb @gitlab-org/govern/compliance
-/app/views/profiles/audit_log.html.haml @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_app.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_export_button.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_log.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_stream.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_table.vue @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/components/tokens/shared/ @gitlab-org/govern/compliance
-/ee/app/assets/javascripts/audit_events/init_audit_events.js @gitlab-org/govern/compliance
-/ee/app/controllers/admin/audit_log_reports_controller.rb @gitlab-org/govern/compliance
-/ee/app/controllers/admin/audit_logs_controller.rb @gitlab-org/govern/compliance
-/ee/app/controllers/concerns/audit_events/audit_events_params.rb @gitlab-org/govern/compliance
-/ee/app/controllers/groups/audit_events_controller.rb @gitlab-org/govern/compliance
-/ee/app/controllers/projects/audit_events_controller.rb @gitlab-org/govern/compliance
-/ee/app/finders/audit_event_finder.rb @gitlab-org/govern/compliance
-/ee/app/graphql/types/audit_events/external_audit_event_destination_type.rb @gitlab-org/govern/compliance
-/ee/app/helpers/audit_events_helper.rb @gitlab-org/govern/compliance
-/ee/app/helpers/auditor_user_helper.rb @gitlab-org/govern/compliance
-/ee/app/models/audit_events/external_audit_event_destination.rb @gitlab-org/govern/compliance
-/ee/app/models/concerns/auditable.rb @gitlab-org/govern/compliance
-/ee/app/models/ee/audit_event.rb @gitlab-org/govern/compliance
-/ee/app/policies/audit_events/external_audit_event_destination_policy.rb @gitlab-org/govern/compliance
-/ee/app/presenters/audit_event_presenter.rb @gitlab-org/govern/compliance
-/ee/app/serializers/audit_event_entity.rb @gitlab-org/govern/compliance
-/ee/app/serializers/audit_event_serializer.rb @gitlab-org/govern/compliance
-/ee/app/services/ci/audit_variable_change_service.rb @gitlab-org/govern/compliance
-/ee/app/services/ee/audit_event_service.rb @gitlab-org/govern/compliance
-/ee/app/views/admin/users/_auditor_access_level_radio.html.haml @gitlab-org/govern/compliance
-/ee/app/views/admin/users/_auditor_user_badge.html.haml @gitlab-org/govern/compliance
-/ee/app/views/shared/icons/_icon_audit_events_purple.svg @gitlab-org/govern/compliance
-/ee/app/views/shared/promotions/_promote_audit_events.html.haml @gitlab-org/govern/compliance
-/ee/app/workers/audit_events/audit_event_streaming_worker.rb @gitlab-org/govern/compliance
-/ee/config/events/1652263097_groups__audit_events__index_click_streams_tab.yml @gitlab-org/govern/compliance
-/ee/config/events/202108302307_admin_audit_logs_index_click_date_range_button.yml @gitlab-org/govern/compliance
-/ee/config/events/202108302307_groups__audit_events_controller_search_audit_event.yml @gitlab-org/govern/compliance
-/ee/config/events/202108302307_profiles_controller_search_audit_event.yml @gitlab-org/govern/compliance
-/ee/config/events/202108302307_projects__audit_events_controller_search_audit_event.yml @gitlab-org/govern/compliance
-/ee/config/events/202111041910_admin__audit_logs_controller_search_audit_event.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_28d/20210216183930_g_compliance_audit_events_monthly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_28d/20210216183934_i_compliance_audit_events_monthly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_28d/20210216183942_a_compliance_audit_events_api_monthly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_28d/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183906_g_compliance_audit_events.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183908_i_compliance_audit_events.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183912_a_compliance_audit_events_api.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183928_g_compliance_audit_events_weekly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183932_i_compliance_audit_events_weekly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_7d/20210216183940_a_compliance_audit_events_api_weekly.yml @gitlab-org/govern/compliance
-/ee/config/metrics/counts_all/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/govern/compliance
-/ee/lib/api/audit_events.rb @gitlab-org/govern/compliance
-/ee/lib/audit/ @gitlab-org/govern/compliance
-/ee/lib/ee/api/entities/audit_event.rb @gitlab-org/govern/compliance
-/ee/lib/ee/gitlab/audit/ @gitlab-org/govern/compliance
-/lib/gitlab/audit/auditor.rb @gitlab-org/govern/compliance
-/lib/gitlab/audit_json_logger.rb @gitlab-org/govern/compliance
+[Compliance] @gitlab-org/govern/compliance
+/app/services/audit_events/build_service.rb
+/ee/spec/services/audit_events/custom_audit_event_service_spec.rb
+/app/models/audit_event.rb
+/app/services/audit_event_service.rb
+/app/services/concerns/audit_event_save_type.rb
+/app/views/profiles/audit_log.html.haml
+/ee/app/assets/javascripts/audit_events/components/audit_events_app.vue
+/ee/app/assets/javascripts/audit_events/components/audit_events_export_button.vue
+/ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue
+/ee/app/assets/javascripts/audit_events/components/audit_events_log.vue
+/ee/app/assets/javascripts/audit_events/components/audit_events_stream.vue
+/ee/app/assets/javascripts/audit_events/components/audit_events_table.vue
+/ee/app/assets/javascripts/audit_events/components/tokens/shared/
+/ee/app/assets/javascripts/audit_events/init_audit_events.js
+/ee/app/controllers/admin/audit_log_reports_controller.rb
+/ee/app/controllers/admin/audit_logs_controller.rb
+/ee/app/controllers/concerns/audit_events/audit_events_params.rb
+/ee/app/controllers/groups/audit_events_controller.rb
+/ee/app/controllers/projects/audit_events_controller.rb
+/ee/app/finders/audit_event_finder.rb
+/ee/app/graphql/types/audit_events/external_audit_event_destination_type.rb
+/ee/app/helpers/audit_events_helper.rb
+/ee/app/helpers/auditor_user_helper.rb
+/ee/app/models/audit_events/external_audit_event_destination.rb
+/ee/app/models/concerns/auditable.rb
+/ee/app/models/ee/audit_event.rb
+/ee/app/policies/audit_events/external_audit_event_destination_policy.rb
+/ee/app/presenters/audit_event_presenter.rb
+/ee/app/serializers/audit_event_entity.rb
+/ee/app/serializers/audit_event_serializer.rb
+/ee/app/services/ci/audit_variable_change_service.rb
+/ee/app/services/ee/audit_event_service.rb
+/ee/app/views/admin/users/_auditor_access_level_radio.html.haml
+/ee/app/views/admin/users/_auditor_user_badge.html.haml
+/ee/app/views/shared/icons/_icon_audit_events_purple.svg
+/ee/app/views/shared/promotions/_promote_audit_events.html.haml
+/ee/app/workers/audit_events/audit_event_streaming_worker.rb
+/ee/config/events/1652263097_groups__audit_events__index_click_streams_tab.yml
+/ee/config/events/202108302307_admin_audit_logs_index_click_date_range_button.yml
+/ee/config/events/202108302307_groups__audit_events_controller_search_audit_event.yml
+/ee/config/events/202108302307_profiles_controller_search_audit_event.yml
+/ee/config/events/202108302307_projects__audit_events_controller_search_audit_event.yml
+/ee/config/events/202111041910_admin__audit_logs_controller_search_audit_event.yml
+/ee/config/metrics/counts_28d/20210216183930_g_compliance_audit_events_monthly.yml
+/ee/config/metrics/counts_28d/20210216183934_i_compliance_audit_events_monthly.yml
+/ee/config/metrics/counts_28d/20210216183942_a_compliance_audit_events_api_monthly.yml
+/ee/config/metrics/counts_28d/20211130085433_g_manage_compliance_audit_event_destinations.yml
+/ee/config/metrics/counts_7d/20210216183906_g_compliance_audit_events.yml
+/ee/config/metrics/counts_7d/20210216183908_i_compliance_audit_events.yml
+/ee/config/metrics/counts_7d/20210216183912_a_compliance_audit_events_api.yml
+/ee/config/metrics/counts_7d/20210216183928_g_compliance_audit_events_weekly.yml
+/ee/config/metrics/counts_7d/20210216183932_i_compliance_audit_events_weekly.yml
+/ee/config/metrics/counts_7d/20210216183940_a_compliance_audit_events_api_weekly.yml
+/ee/config/metrics/counts_all/20211130085433_g_manage_compliance_audit_event_destinations.yml
+/ee/lib/api/audit_events.rb
+/ee/lib/audit/
+/ee/lib/ee/api/entities/audit_event.rb
+/ee/lib/ee/gitlab/audit/
+/lib/gitlab/audit/auditor.rb
+/lib/gitlab/audit_json_logger.rb
-[Fulfillment::Utilization]
-/ee/app/assets/javascripts/usage_quotas/components/ @sheldonled @aalakkad @kpalchyk
-/ee/app/assets/javascripts/usage_quotas/seats/ @sheldonled @aalakkad @kpalchyk
-/ee/app/assets/javascripts/usage_quotas/storage/ @sheldonled @aalakkad @kpalchyk
+[Fulfillment::Utilization] @sheldonled @aalakkad @kpalchyk
+/ee/app/assets/javascripts/usage_quotas/components/
+/ee/app/assets/javascripts/usage_quotas/seats/
+/ee/app/assets/javascripts/usage_quotas/storage/
-[Manage::Foundations]
-/lib/sidebars/ @gitlab-org/manage/foundations/engineering
-/ee/lib/sidebars/ @gitlab-org/manage/foundations/engineering
+[Manage::Foundations] @gitlab-org/manage/foundations/engineering
+/lib/sidebars/
+/ee/lib/sidebars/
# JiHu GitLab rules. See https://gitlab.com/gitlab-jh/gitlab-jh-enablement/-/issues/213#note_1024367528
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index 15e8912cffb..bb17d0371dc 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -571,11 +571,6 @@ Layout/ArgumentAlignment:
- 'app/models/webauthn_registration.rb'
- 'app/models/wiki_page.rb'
- 'app/models/work_item.rb'
- - 'app/services/ci/archive_trace_service.rb'
- - 'app/services/ci/ensure_stage_service.rb'
- - 'app/services/ci/list_config_variables_service.rb'
- - 'app/services/ci/parse_dotenv_artifact_service.rb'
- - 'app/services/ci/stuck_builds/drop_helpers.rb'
- 'app/services/compare_service.rb'
- 'app/services/concerns/rate_limited_service.rb'
- 'app/services/design_management/copy_design_collection/copy_service.rb'
@@ -1465,11 +1460,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/services/audit_events/streaming/event_type_filters/destroy_service_spec.rb'
- 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
- 'ee/spec/services/boards/lists/update_service_spec.rb'
- - 'ee/spec/services/ci/process_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/retry_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/sync_reports_to_approval_rules_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/create_service_spec.rb'
- 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
- 'ee/spec/services/ee/boards/issues/move_service_spec.rb'
@@ -2458,24 +2448,6 @@ Layout/ArgumentAlignment:
- 'spec/services/award_emojis/destroy_service_spec.rb'
- 'spec/services/bulk_imports/create_service_spec.rb'
- 'spec/services/bulk_imports/get_importable_data_service_spec.rb'
- - 'spec/services/ci/archive_trace_service_spec.rb'
- - 'spec/services/ci/create_downstream_pipeline_service_spec.rb'
- - 'spec/services/ci/create_pipeline_service/include_spec.rb'
- - 'spec/services/ci/create_pipeline_service/logger_spec.rb'
- - 'spec/services/ci/create_pipeline_service/merge_requests_spec.rb'
- - 'spec/services/ci/create_pipeline_service/partitioning_spec.rb'
- - 'spec/services/ci/create_pipeline_service/rate_limit_spec.rb'
- - 'spec/services/ci/create_pipeline_service_spec.rb'
- - 'spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb'
- - 'spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb'
- - 'spec/services/ci/list_config_variables_service_spec.rb'
- - 'spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb'
- - 'spec/services/ci/play_build_service_spec.rb'
- - 'spec/services/ci/play_manual_stage_service_spec.rb'
- - 'spec/services/ci/process_sync_events_service_spec.rb'
- - 'spec/services/ci/retry_job_service_spec.rb'
- - 'spec/services/ci/retry_pipeline_service_spec.rb'
- - 'spec/services/ci/run_scheduled_build_service_spec.rb'
- 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
- 'spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb'
- 'spec/services/cohorts_service_spec.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 426ac482800..0f4b55a20b9 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-c751c4f269b472d5c35d59d869402a1efc227719
+3ce8f3a93ef7a00dfe5d65d92aa917a24e74e499
diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
index cc8a9baf69e..f4facc39f4a 100644
--- a/app/assets/javascripts/behaviors/shortcuts/keybindings.js
+++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
@@ -2,8 +2,11 @@ import { memoize } from 'lodash';
import AccessorUtilities from '~/lib/utils/accessor';
import { __ } from '~/locale';
-const isCustomizable = (command) =>
- 'customizable' in command ? Boolean(command.customizable) : true;
+/**
+ * @param {object} command
+ * @param {boolean} [command.customizable]
+ */
+const isCustomizable = ({ customizable }) => Boolean(customizable ?? true);
export const LOCAL_STORAGE_KEY = 'gl-keyboard-shortcuts-customizations';
@@ -183,7 +186,10 @@ export const TOGGLE_MARKDOWN_PREVIEW = {
defaultKeys: ['ctrl+shift+p', 'command+shift+p'],
};
-export const EDIT_RECENT_COMMENT = {
+/**
+ * @keydown.up event is handled here: https://gitlab.com/gitlab-org/gitlab/-/blob/f3e807cdff5cf25765894163b4e92f8b2bcf8a68/app/assets/javascripts/notes/components/comment_form.vue#L379
+ */
+const EDIT_RECENT_COMMENT = {
id: 'editing.editRecentComment',
description: __('Edit your most recent comment in a thread (from an empty textarea)'),
defaultKeys: ['up'],
@@ -472,13 +478,22 @@ export const ISSUE_CLOSE_DESIGN = {
defaultKeys: ['esc'],
};
-export const WEB_IDE_GO_TO_FILE = {
+/**
+ * Legacy Web IDE uses the same shortcuts as MR_GO_TO_FILE, from this shared component:
+ * https://gitlab.com/gitlab-org/gitlab/-/blob/f3e807cdff5cf25765894163b4e92f8b2bcf8a68/app/assets/javascripts/vue_shared/components/file_finder/index.vue#L6
+ */
+const WEB_IDE_GO_TO_FILE = {
id: 'webIDE.goToFile',
description: __('Go to file'),
- defaultKeys: ['mod+p'],
+ defaultKeys: ['mod+p', 't'],
+ customizable: false /* customize MR_GO_TO_FILE instead */,
};
-export const WEB_IDE_COMMIT = {
+/**
+ * Legacy Web IDE uses @keydown.ctrl.enter and @keydown.meta.enter events here:
+ * https://gitlab.com/gitlab-org/gitlab/-/blob/f3e807cdff5cf25765894163b4e92f8b2bcf8a68/app/assets/javascripts/ide/components/shared/commit_message_field.vue#L131-132
+ */
+const WEB_IDE_COMMIT = {
id: 'webIDE.commit',
description: __('Commit (when editing commit message)'),
defaultKeys: ['mod+enter'],
@@ -489,39 +504,28 @@ export const METRICS_EXPAND_PANEL = {
id: 'metrics.expandPanel',
description: __('Expand panel'),
defaultKeys: ['e'],
- customizable: false,
-};
-
-export const METRICS_VIEW_LOGS = {
- id: 'metrics.viewLogs',
- description: __('View logs'),
- defaultKeys: ['l'],
- customizable: false,
};
export const METRICS_DOWNLOAD_CSV = {
id: 'metrics.downloadCSV',
description: __('Download CSV'),
defaultKeys: ['d'],
- customizable: false,
};
export const METRICS_COPY_LINK_TO_CHART = {
id: 'metrics.copyLinkToChart',
description: __('Copy link to chart'),
defaultKeys: ['c'],
- customizable: false,
};
export const METRICS_SHOW_ALERTS = {
id: 'metrics.showAlerts',
description: __('Alerts'),
defaultKeys: ['a'],
- customizable: false,
};
// All keybinding groups
-export const GLOBAL_SHORTCUTS_GROUP = {
+const GLOBAL_SHORTCUTS_GROUP = {
id: 'globalShortcuts',
name: __('Global Shortcuts'),
keybindings: [
@@ -559,13 +563,13 @@ export const EDITING_SHORTCUTS_GROUP = {
],
};
-export const WIKI_SHORTCUTS_GROUP = {
+const WIKI_SHORTCUTS_GROUP = {
id: 'wiki',
name: __('Wiki'),
keybindings: [EDIT_WIKI_PAGE],
};
-export const REPOSITORY_GRAPH_SHORTCUTS_GROUP = {
+const REPOSITORY_GRAPH_SHORTCUTS_GROUP = {
id: 'repositoryGraph',
name: __('Repository Graph'),
keybindings: [
@@ -578,7 +582,7 @@ export const REPOSITORY_GRAPH_SHORTCUTS_GROUP = {
],
};
-export const PROJECT_SHORTCUTS_GROUP = {
+const PROJECT_SHORTCUTS_GROUP = {
id: 'project',
name: __('Project'),
keybindings: [
@@ -604,7 +608,7 @@ export const PROJECT_SHORTCUTS_GROUP = {
],
};
-export const PROJECT_FILES_SHORTCUTS_GROUP = {
+const PROJECT_FILES_SHORTCUTS_GROUP = {
id: 'projectFiles',
name: __('Project Files'),
keybindings: [
@@ -616,19 +620,19 @@ export const PROJECT_FILES_SHORTCUTS_GROUP = {
],
};
-export const ISSUABLE_SHORTCUTS_GROUP = {
+const ISSUABLE_SHORTCUTS_GROUP = {
id: 'issuables',
name: __('Epics, issues, and merge requests'),
keybindings: [ISSUABLE_COMMENT_OR_REPLY, ISSUABLE_EDIT_DESCRIPTION, ISSUABLE_CHANGE_LABEL],
};
-export const ISSUE_MR_SHORTCUTS_GROUP = {
+const ISSUE_MR_SHORTCUTS_GROUP = {
id: 'issuesMRs',
name: __('Issues and merge requests'),
keybindings: [ISSUE_MR_CHANGE_ASSIGNEE, ISSUE_MR_CHANGE_MILESTONE],
};
-export const MR_SHORTCUTS_GROUP = {
+const MR_SHORTCUTS_GROUP = {
id: 'mergeRequests',
name: __('Merge requests'),
keybindings: [
@@ -641,30 +645,29 @@ export const MR_SHORTCUTS_GROUP = {
],
};
-export const MR_COMMITS_SHORTCUTS_GROUP = {
+const MR_COMMITS_SHORTCUTS_GROUP = {
id: 'mergeRequestCommits',
name: __('Merge request commits'),
keybindings: [MR_COMMITS_NEXT_COMMIT, MR_COMMITS_PREVIOUS_COMMIT],
};
-export const ISSUES_SHORTCUTS_GROUP = {
+const ISSUES_SHORTCUTS_GROUP = {
id: 'issues',
name: __('Issues'),
keybindings: [ISSUE_NEXT_DESIGN, ISSUE_PREVIOUS_DESIGN, ISSUE_CLOSE_DESIGN],
};
-export const WEB_IDE_SHORTCUTS_GROUP = {
+const WEB_IDE_SHORTCUTS_GROUP = {
id: 'webIDE',
- name: __('Web IDE'),
+ name: __('Legacy Web IDE'),
keybindings: [WEB_IDE_GO_TO_FILE, WEB_IDE_COMMIT],
};
-export const METRICS_SHORTCUTS_GROUP = {
+const METRICS_SHORTCUTS_GROUP = {
id: 'metrics',
name: __('Metrics'),
keybindings: [
METRICS_EXPAND_PANEL,
- METRICS_VIEW_LOGS,
METRICS_DOWNLOAD_CSV,
METRICS_COPY_LINK_TO_CHART,
METRICS_SHOW_ALERTS,
@@ -700,6 +703,9 @@ export const keybindingGroups = [
*
* @param {Object} command The command object. All command objects are
* available as imports from this file.
+ * @param {string} command.id
+ * @param {string[]} command.defaultKeys
+ * @param {boolean} [command.customizable]
*
* @returns {string[]} An array of keyboard shortcut strings bound to the command
*
diff --git a/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue b/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
index abc2eca38f4..821e002581c 100644
--- a/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
@@ -1,9 +1,11 @@
<script>
import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { redirectTo, setUrlParams } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
import RunnerCreateForm from '~/ci/runner/components/runner_create_form.vue';
-import { DEFAULT_PLATFORM, PROJECT_TYPE } from '../constants';
+import { DEFAULT_PLATFORM, PARAM_KEY_PLATFORM, PROJECT_TYPE } from '../constants';
+import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
export default {
name: 'ProjectNewRunnerApp',
@@ -23,11 +25,15 @@ export default {
};
},
methods: {
- onSaved() {
- createAlert({
+ onSaved(runner) {
+ const params = { [PARAM_KEY_PLATFORM]: this.platform };
+ const ephemeralRegisterUrl = setUrlParams(params, runner.ephemeralRegisterUrl);
+
+ saveAlertToLocalStorage({
message: s__('Runners|Runner created.'),
variant: VARIANT_SUCCESS,
});
+ redirectTo(ephemeralRegisterUrl);
},
onError(error) {
createAlert({ message: error.message });
diff --git a/app/assets/javascripts/ci/runner/project_register_runner/index.js b/app/assets/javascripts/ci/runner/project_register_runner/index.js
new file mode 100644
index 00000000000..63e88359ee7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/project_register_runner/index.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
+import ProjectRegisterRunnerApp from './project_register_runner_app.vue';
+
+Vue.use(VueApollo);
+
+export const initProjectRegisterRunner = (selector = '#js-project-register-runner') => {
+ showAlertFromLocalStorage();
+
+ const el = document.querySelector(selector);
+
+ if (!el) {
+ return null;
+ }
+
+ const { runnerId, runnersPath } = el.dataset;
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ render(h) {
+ return h(ProjectRegisterRunnerApp, {
+ props: {
+ runnerId,
+ runnersPath,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci/runner/project_register_runner/project_register_runner_app.vue b/app/assets/javascripts/ci/runner/project_register_runner/project_register_runner_app.vue
new file mode 100644
index 00000000000..b3fad595c7e
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/project_register_runner/project_register_runner_app.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import { getParameterByName, updateHistory, mergeUrlParams } from '~/lib/utils/url_utility';
+import { PARAM_KEY_PLATFORM, DEFAULT_PLATFORM } from '../constants';
+import RegistrationInstructions from '../components/registration/registration_instructions.vue';
+import PlatformsDrawer from '../components/registration/platforms_drawer.vue';
+
+export default {
+ name: 'ProjectRegisterRunnerApp',
+ components: {
+ GlButton,
+ RegistrationInstructions,
+ PlatformsDrawer,
+ },
+ props: {
+ runnerId: {
+ type: String,
+ required: true,
+ },
+ runnersPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ platform: getParameterByName(PARAM_KEY_PLATFORM) || DEFAULT_PLATFORM,
+ isDrawerOpen: false,
+ };
+ },
+ watch: {
+ platform(platform) {
+ updateHistory({
+ url: mergeUrlParams({ [PARAM_KEY_PLATFORM]: platform }, window.location.href),
+ });
+ },
+ },
+ methods: {
+ onSelectPlatform(platform) {
+ this.platform = platform;
+ },
+ onToggleDrawer(val = !this.isDrawerOpen) {
+ this.isDrawerOpen = val;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <registration-instructions
+ :runner-id="runnerId"
+ :platform="platform"
+ @toggleDrawer="onToggleDrawer"
+ >
+ <template #runner-list-name>{{ s__('Runners|Project › CI/CD Settings › Runners') }}</template>
+ </registration-instructions>
+
+ <platforms-drawer
+ :platform="platform"
+ :open="isDrawerOpen"
+ @selectPlatform="onSelectPlatform"
+ @close="onToggleDrawer(false)"
+ />
+
+ <gl-button :href="runnersPath" variant="confirm">{{
+ s__('Runners|Go to runners page')
+ }}</gl-button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/environments/components/kubernetes_overview.vue b/app/assets/javascripts/environments/components/kubernetes_overview.vue
index 736eaa7062d..41abfcf6dc8 100644
--- a/app/assets/javascripts/environments/components/kubernetes_overview.vue
+++ b/app/assets/javascripts/environments/components/kubernetes_overview.vue
@@ -5,6 +5,7 @@ import csrf from '~/lib/utils/csrf';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import KubernetesAgentInfo from './kubernetes_agent_info.vue';
import KubernetesPods from './kubernetes_pods.vue';
+import KubernetesTabs from './kubernetes_tabs.vue';
export default {
components: {
@@ -13,6 +14,7 @@ export default {
GlAlert,
KubernetesAgentInfo,
KubernetesPods,
+ KubernetesTabs,
},
inject: ['kasTunnelUrl'],
props: {
@@ -103,6 +105,10 @@ export default {
:configuration="k8sAccessConfiguration"
:namespace="namespace"
class="gl-mb-5"
+ @cluster-error="onClusterError" />
+ <kubernetes-tabs
+ :configuration="k8sAccessConfiguration"
+ class="gl-mb-5"
@cluster-error="onClusterError"
/></template>
</gl-collapse>
diff --git a/app/assets/javascripts/environments/components/kubernetes_tabs.vue b/app/assets/javascripts/environments/components/kubernetes_tabs.vue
new file mode 100644
index 00000000000..b1eb92a4049
--- /dev/null
+++ b/app/assets/javascripts/environments/components/kubernetes_tabs.vue
@@ -0,0 +1,158 @@
+<script>
+import { GlTabs, GlTab, GlLoadingIcon, GlBadge, GlTable, GlPagination } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import k8sServicesQuery from '../graphql/queries/k8s_services.query.graphql';
+import { generateServicePortsString, getServiceAge } from '../helpers/k8s_integration_helper';
+import { SERVICES_LIMIT_PER_PAGE } from '../constants';
+
+const tableHeadingClasses = 'gl-bg-gray-50! gl-font-weight-bold gl-white-space-nowrap';
+
+export default {
+ components: {
+ GlTabs,
+ GlTab,
+ GlBadge,
+ GlTable,
+ GlPagination,
+ GlLoadingIcon,
+ },
+ apollo: {
+ k8sServices: {
+ query: k8sServicesQuery,
+ variables() {
+ return {
+ configuration: this.configuration,
+ };
+ },
+ update(data) {
+ return data?.k8sServices || [];
+ },
+ error(error) {
+ this.$emit('cluster-error', error);
+ },
+ },
+ },
+ props: {
+ configuration: {
+ required: true,
+ type: Object,
+ },
+ },
+ data() {
+ return {
+ currentPage: 1,
+ };
+ },
+ computed: {
+ servicesItems() {
+ if (!this.k8sServices?.length) return [];
+
+ return this.k8sServices.map((service) => {
+ return {
+ name: service?.metadata?.name,
+ namespace: service?.metadata?.namespace,
+ type: service?.spec?.type,
+ clusterIP: service?.spec?.clusterIP,
+ externalIP: service?.spec?.externalIP,
+ ports: generateServicePortsString(service?.spec?.ports),
+ age: getServiceAge(service?.metadata?.creationTimestamp),
+ };
+ });
+ },
+ servicesLoading() {
+ return this.$apollo.queries.k8sServices.loading;
+ },
+ showPagination() {
+ return this.servicesItems.length > SERVICES_LIMIT_PER_PAGE;
+ },
+ prevPage() {
+ return Math.max(this.currentPage - 1, 0);
+ },
+ nextPage() {
+ const nextPage = this.currentPage + 1;
+ return nextPage > Math.ceil(this.servicesItems.length / SERVICES_LIMIT_PER_PAGE)
+ ? null
+ : nextPage;
+ },
+ },
+ i18n: {
+ servicesTitle: s__('Environment|Services'),
+ name: __('Name'),
+ namespace: __('Namespace'),
+ status: __('Status'),
+ type: __('Type'),
+ clusterIP: s__('Environment|Cluster IP'),
+ externalIP: s__('Environment|External IP'),
+ ports: s__('Environment|Ports'),
+ age: s__('Environment|Age'),
+ },
+ servicesFields: [
+ {
+ key: 'name',
+ label: __('Name'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'namespace',
+ label: __('Namespace'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'type',
+ label: __('Type'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'clusterIP',
+ label: s__('Environment|Cluster IP'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'externalIP',
+ label: s__('Environment|External IP'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'ports',
+ label: s__('Environment|Ports'),
+ thClass: tableHeadingClasses,
+ },
+ {
+ key: 'age',
+ label: s__('Environment|Age'),
+ thClass: tableHeadingClasses,
+ },
+ ],
+ SERVICES_LIMIT_PER_PAGE,
+};
+</script>
+<template>
+ <gl-tabs>
+ <gl-tab>
+ <template #title>
+ {{ $options.i18n.servicesTitle }}
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ servicesItems.length }}</gl-badge>
+ </template>
+
+ <gl-loading-icon v-if="servicesLoading" />
+
+ <gl-table
+ v-else
+ :fields="$options.servicesFields"
+ :items="servicesItems"
+ :per-page="$options.SERVICES_LIMIT_PER_PAGE"
+ :current-page="currentPage"
+ stacked="lg"
+ class="gl-bg-white! gl-mt-3"
+ />
+ <gl-pagination
+ v-if="showPagination"
+ v-model="currentPage"
+ :prev-page="prevPage"
+ :next-page="nextPage"
+ align="center"
+ class="gl-mt-6"
+ />
+ </gl-tab>
+ </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/environments/constants.js b/app/assets/javascripts/environments/constants.js
index 28424322dd2..e675a73ba7d 100644
--- a/app/assets/javascripts/environments/constants.js
+++ b/app/assets/javascripts/environments/constants.js
@@ -87,3 +87,5 @@ export const ENVIRONMENT_NEW_HELP_TEXT = __(
);
export const ENVIRONMENT_EDIT_HELP_TEXT = ENVIRONMENT_NEW_HELP_TEXT;
+
+export const SERVICES_LIMIT_PER_PAGE = 10;
diff --git a/app/assets/javascripts/environments/graphql/client.js b/app/assets/javascripts/environments/graphql/client.js
index 0482741979b..bb6f57e7e80 100644
--- a/app/assets/javascripts/environments/graphql/client.js
+++ b/app/assets/javascripts/environments/graphql/client.js
@@ -6,6 +6,7 @@ import environmentToDeleteQuery from './queries/environment_to_delete.query.grap
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
import environmentToStopQuery from './queries/environment_to_stop.query.graphql';
import k8sPodsQuery from './queries/k8s_pods.query.graphql';
+import k8sServicesQuery from './queries/k8s_services.query.graphql';
import { resolvers } from './resolvers';
import typeDefs from './typedefs.graphql';
@@ -87,7 +88,23 @@ export const apolloProvider = (endpoint) => {
query: k8sPodsQuery,
data: {
status: {
- phase: '',
+ phase: null,
+ },
+ },
+ });
+ cache.writeQuery({
+ query: k8sServicesQuery,
+ data: {
+ metadata: {
+ name: null,
+ namespace: null,
+ creationTimestamp: null,
+ },
+ spec: {
+ type: null,
+ clusterIP: null,
+ externalIP: null,
+ ports: [],
},
},
});
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
index 818bca24d51..2d57ede8c15 100644
--- a/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/k8s_pods.query.graphql
@@ -1,4 +1,4 @@
-query getK8sPods($configuration: Object, $namespace: String) {
+query getK8sPods($configuration: LocalConfiguration, $namespace: String) {
k8sPods(configuration: $configuration, namespace: $namespace) @client {
status {
phase
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql
new file mode 100644
index 00000000000..d97849eecc1
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/queries/k8s_services.query.graphql
@@ -0,0 +1,15 @@
+query getK8sServices($configuration: LocalConfiguration) {
+ k8sServices(configuration: $configuration) @client {
+ metadata {
+ name
+ namespace
+ creationTimestamp
+ }
+ spec {
+ type
+ clusterIP
+ externalIP
+ ports
+ }
+ }
+}
diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js
index 013467e34be..8ebeeb92a53 100644
--- a/app/assets/javascripts/environments/graphql/resolvers.js
+++ b/app/assets/javascripts/environments/graphql/resolvers.js
@@ -85,6 +85,30 @@ export const resolvers = (endpoint) => ({
throw error;
});
},
+ k8sServices(_, { configuration }) {
+ const coreV1Api = new CoreV1Api(new Configuration(configuration));
+ return coreV1Api
+ .listCoreV1ServiceForAllNamespaces()
+ .then((res) => {
+ const items = res?.data?.items || [];
+ return items.map((item) => {
+ const { type, clusterIP, externalIP, ports } = item.spec;
+ return {
+ metadata: item.metadata,
+ spec: {
+ type,
+ clusterIP: clusterIP || '-',
+ externalIP: externalIP || '-',
+ ports,
+ },
+ };
+ });
+ })
+ .catch((err) => {
+ const error = err?.response?.data?.message ? new Error(err.response.data.message) : err;
+ throw error;
+ });
+ },
},
Mutation: {
stopEnvironmentREST(_, { environment }, { client }) {
diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql
index 4de271935d6..b85bf1e10d3 100644
--- a/app/assets/javascripts/environments/graphql/typedefs.graphql
+++ b/app/assets/javascripts/environments/graphql/typedefs.graphql
@@ -75,6 +75,24 @@ input LocalConfiguration {
baseOptions: JSON
}
+type k8sServiceMetadata {
+ name: String
+ namespace: String
+ creationTimestamp: String
+}
+
+type k8sServiceSpec {
+ type: String
+ clusterIP: String
+ externalIP: String
+ ports: JSON
+}
+
+type LocalK8sServices {
+ metadata: k8sServiceMetadata
+ spec: k8sServiceSpec
+}
+
extend type Query {
environmentApp(page: Int, scope: String): LocalEnvironmentApp
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
@@ -85,6 +103,7 @@ extend type Query {
isEnvironmentStopping(environment: LocalEnvironmentInput): Boolean
isLastDeployment(environment: LocalEnvironmentInput): Boolean
k8sPods(configuration: LocalConfiguration, namespace: String): [LocalK8sPods]
+ k8sServices(configuration: LocalConfiguration): [LocalK8sServices]
}
extend type Mutation {
diff --git a/app/assets/javascripts/environments/helpers/k8s_integration_helper.js b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js
new file mode 100644
index 00000000000..6a94ac31fa1
--- /dev/null
+++ b/app/assets/javascripts/environments/helpers/k8s_integration_helper.js
@@ -0,0 +1,36 @@
+import { differenceInSeconds } from '~/lib/utils/datetime_utility';
+
+export function generateServicePortsString(ports) {
+ if (!ports?.length) return '';
+
+ return ports
+ .map((port) => {
+ const nodePort = port.nodePort ? `:${port.nodePort}` : '';
+ return `${port.port}${nodePort}/${port.protocol}`;
+ })
+ .join(', ');
+}
+
+export function getServiceAge(creationTimestamp) {
+ if (!creationTimestamp) return '';
+
+ const timeDifference = differenceInSeconds(new Date(creationTimestamp), new Date());
+
+ const seconds = Math.floor(timeDifference);
+ const minutes = Math.floor(seconds / 60) % 60;
+ const hours = Math.floor(seconds / 60 / 60) % 24;
+ const days = Math.floor(seconds / 60 / 60 / 24);
+
+ let ageString;
+ if (days > 0) {
+ ageString = `${days}d`;
+ } else if (hours > 0) {
+ ageString = `${hours}h`;
+ } else if (minutes > 0) {
+ ageString = `${minutes}m`;
+ } else {
+ ageString = `${seconds}s`;
+ }
+
+ return ageString;
+}
diff --git a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
index 6d1a3ceba16..fadce6457bc 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlLink, GlDropdownItem } from '@gitlab/ui';
+import { GlButton, GlLink, GlDropdownItem, GlDisclosureDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
import {
@@ -7,10 +7,11 @@ import {
TRIGGER_DEFAULT_QA_SELECTOR,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
+ TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
} from '../constants';
export default {
- components: { GlButton, GlLink, GlDropdownItem },
+ components: { GlButton, GlLink, GlDropdownItem, GlDisclosureDropdownItem },
props: {
displayText: {
type: String,
@@ -55,6 +56,9 @@ export default {
'data-test-id': 'invite-members-button',
};
},
+ item() {
+ return { text: this.displayText };
+ },
},
methods: {
checkTrigger(targetTriggerElement) {
@@ -63,10 +67,15 @@ export default {
openModal() {
eventHub.$emit('openModal', { source: this.triggerSource });
},
+ handleDisclosureDropdownAction() {
+ this.openModal();
+ this.$emit('modal-opened');
+ },
},
TRIGGER_ELEMENT_BUTTON,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
+ TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
};
</script>
@@ -97,6 +106,12 @@ export default {
{{ displayText }}
<gl-emoji class="gl-vertical-align-baseline gl-reset-font-size gl-mr-1" :data-name="icon" />
</gl-dropdown-item>
+ <gl-disclosure-dropdown-item
+ v-else-if="checkTrigger($options.TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN)"
+ v-bind="componentAttributes"
+ :item="item"
+ @action="handleDisclosureDropdownAction"
+ />
<gl-link v-else v-bind="componentAttributes" data-is-link="true" @click="openModal">
{{ displayText }}
</gl-link>
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index d5e9e498c6b..58457c80524 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -21,6 +21,7 @@ export const TRIGGER_ELEMENT_BUTTON = 'button';
export const TOP_NAV_INVITE_MEMBERS_COMPONENT = 'invite_members';
export const TRIGGER_ELEMENT_WITH_EMOJI = 'text-emoji';
export const TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI = 'dropdown-text-emoji';
+export const TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN = 'dropdown-text';
export const INVITE_MEMBER_MODAL_TRACKING_CATEGORY = 'invite_members_modal';
export const TRIGGER_DEFAULT_QA_SELECTOR = 'invite_members_button';
export const MEMBERS_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite members');
diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
index 970ab12cc85..b4a9b37d487 100644
--- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -53,7 +53,7 @@ import {
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants';
+import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
import getIssuesCountsQuery from '../queries/get_issues_counts.query.graphql';
import { AutocompleteCache } from '../utils';
@@ -67,7 +67,7 @@ const MilestoneToken = () =>
export default {
i18n,
- IssuableListTabs,
+ issuableListTabs,
components: {
GlDisclosureDropdown,
GlEmptyState,
@@ -457,7 +457,7 @@ export default {
show-work-item-type-icon
:sort-options="sortOptions"
:tab-counts="tabCounts"
- :tabs="$options.IssuableListTabs"
+ :tabs="$options.issuableListTabs"
truncate-counts
:url-params="urlParams"
use-keyset-pagination
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index 5c4bf8f19e4..525daab41d5 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -52,7 +52,7 @@ import {
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { DEFAULT_PAGE_SIZE, IssuableListTabs } from '~/vue_shared/issuable/list/constants';
+import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue';
import {
@@ -108,7 +108,7 @@ const CrmOrganizationToken = () =>
export default {
i18n,
- IssuableListTabs,
+ issuableListTabs,
components: {
CsvImportExportButtons,
EmptyStateWithAnyIssues,
@@ -774,7 +774,7 @@ export default {
:issuables="issues"
:error="issuesError"
label-filter-param="label_name"
- :tabs="$options.IssuableListTabs"
+ :tabs="$options.issuableListTabs"
:current-tab="state"
:tab-counts="tabCounts"
:truncate-counts="!isProject"
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue b/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue
index 4c0f99cf62c..c10b0cb52b9 100644
--- a/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue
@@ -1,9 +1,9 @@
<script>
import {
GlModal,
- GlDropdown,
+ GlDisclosureDropdown,
GlTooltipDirective,
- GlDropdownItem,
+ GlDisclosureDropdownItem,
GlModalDirective,
} from '@gitlab/ui';
import { __ } from '~/locale';
@@ -12,8 +12,8 @@ import csrf from '~/lib/utils/csrf';
export default {
components: {
GlModal,
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -63,36 +63,42 @@ export default {
</script>
<template>
- <gl-dropdown
- right
- category="tertiary"
- :aria-label="__('More actions')"
- icon="ellipsis_v"
- no-caret
- >
- <gl-dropdown-item
- v-gl-modal-directive="modal.id"
- :aria-label="actionPrimaryText"
- variant="danger"
+ <div>
+ <gl-disclosure-dropdown
+ placement="right"
+ category="tertiary"
+ :aria-label="__('More actions')"
+ icon="ellipsis_v"
+ no-caret
>
- {{ actionPrimaryText }}
+ <gl-disclosure-dropdown-item
+ v-gl-modal-directive="modal.id"
+ :aria-label="actionPrimaryText"
+ variant="danger"
+ >
+ <template #list-item>
+ <span class="gl-text-red-500">
+ {{ actionPrimaryText }}
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
- <form ref="deleteForm" method="post" :action="deletePath">
- <input type="hidden" name="_method" value="delete" />
- <input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
- </form>
+ <form ref="deleteForm" method="post" :action="deletePath">
+ <input type="hidden" name="_method" value="delete" />
+ <input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
+ </form>
- <gl-modal
- :modal-id="modal.id"
- :title="modalTitle"
- :action-primary="modal.actionPrimary"
- :action-cancel="modal.actionCancel"
- @primary="confirmDelete"
- >
- <p>
- {{ deleteConfirmationText }}
- </p>
- </gl-modal>
- </gl-dropdown-item>
- </gl-dropdown>
+ <gl-modal
+ :modal-id="modal.id"
+ :title="modalTitle"
+ :action-primary="modal.actionPrimary"
+ :action-cancel="modal.actionCancel"
+ @primary="confirmDelete"
+ >
+ <p>
+ {{ deleteConfirmationText }}
+ </p>
+ </gl-modal>
+ </div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 100ef11409f..752ba4241d8 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -11,6 +11,13 @@ import {
import VueDraggable from 'vuedraggable';
import { mapActions, mapState, mapGetters } from 'vuex';
import { createAlert } from '~/alert';
+import {
+ keysFor,
+ METRICS_COPY_LINK_TO_CHART,
+ METRICS_DOWNLOAD_CSV,
+ METRICS_EXPAND_PANEL,
+ METRICS_SHOW_ALERTS,
+} from '~/behaviors/shortcuts/keybindings';
import invalidUrl from '~/lib/utils/invalid_url';
import { ESC_KEY } from '~/lib/utils/keys';
import { Mousetrap } from '~/lib/mousetrap';
@@ -18,7 +25,7 @@ import { mergeUrlParams, updateHistory } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import { defaultTimeRange } from '~/vue_shared/constants';
import TrackEventDirective from '~/vue_shared/directives/track_event';
-import { metricStates, keyboardShortcutKeys } from '../constants';
+import { metricStates } from '../constants';
import {
timeRangeFromUrl,
panelToUrl,
@@ -214,12 +221,28 @@ export default {
created() {
window.addEventListener('keyup', this.onKeyup);
- Mousetrap.bind(Object.values(keyboardShortcutKeys), this.runShortcut);
+ Mousetrap.bind(keysFor(METRICS_EXPAND_PANEL), () =>
+ this.runShortcut('onExpandFromKeyboardShortcut'),
+ );
+ Mousetrap.bind(keysFor(METRICS_SHOW_ALERTS), () =>
+ this.runShortcut('showAlertModalFromKeyboardShortcut'),
+ );
+ Mousetrap.bind(keysFor(METRICS_DOWNLOAD_CSV), () =>
+ this.runShortcut('downloadCsvFromKeyboardShortcut'),
+ );
+ Mousetrap.bind(keysFor(METRICS_COPY_LINK_TO_CHART), () =>
+ this.runShortcut('copyChartLinkFromKeyboardShotcut'),
+ );
},
destroyed() {
window.removeEventListener('keyup', this.onKeyup);
- Mousetrap.unbind(Object.values(keyboardShortcutKeys));
+ [
+ METRICS_COPY_LINK_TO_CHART,
+ METRICS_DOWNLOAD_CSV,
+ METRICS_EXPAND_PANEL,
+ METRICS_SHOW_ALERTS,
+ ].forEach((command) => Mousetrap.unbind(keysFor(command)));
},
mounted() {
if (!this.hasMetrics) {
@@ -339,42 +362,18 @@ export default {
},
/**
* TODO: Investigate this to utilize the eventBus from Vue
- * The intentation behind this cleanup is to allow for better tests
+ * The intention behind this cleanup is to allow for better tests
* as well as use the correct eventBus facilities that are compatible
* with Vue 3
* https://gitlab.com/gitlab-org/gitlab/-/issues/225583
*/
//
- runShortcut(e) {
+ runShortcut(actionToRun) {
const panel = this.$refs[this.hoveredPanel];
if (!panel) return;
const [panelInstance] = panel;
- let actionToRun = '';
-
- switch (e.key) {
- case keyboardShortcutKeys.EXPAND:
- actionToRun = 'onExpandFromKeyboardShortcut';
- break;
-
- case keyboardShortcutKeys.SHOW_ALERT:
- actionToRun = 'showAlertModalFromKeyboardShortcut';
- break;
-
- case keyboardShortcutKeys.DOWNLOAD_CSV:
- actionToRun = 'downloadCsvFromKeyboardShortcut';
- break;
-
- case keyboardShortcutKeys.CHART_COPY:
- actionToRun = 'copyChartLinkFromKeyboardShotcut';
- break;
-
- default:
- actionToRun = 'onExpandFromKeyboardShortcut';
- break;
- }
-
panelInstance[actionToRun]();
},
setHoveredPanel(groupKey, graphIndex) {
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index faef4b01c27..e35dcc350f2 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -256,19 +256,6 @@ export const VARIABLE_TYPES = {
*/
export const VARIABLE_PREFIX = 'var-';
-/**
- * All of the actions inside each panel dropdown can be accessed
- * via keyboard shortcuts than can be activated via mouse hovers
- * and or focus via tabs.
- */
-
-export const keyboardShortcutKeys = {
- EXPAND: 'e',
- SHOW_ALERT: 'a',
- DOWNLOAD_CSV: 'd',
- CHART_COPY: 'c',
-};
-
export const thresholdModeTypes = {
ABSOLUTE: 'absolute',
PERCENTAGE: 'percentage',
diff --git a/app/assets/javascripts/pages/projects/runners/register/index.js b/app/assets/javascripts/pages/projects/runners/register/index.js
new file mode 100644
index 00000000000..a55ff95f84d
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/runners/register/index.js
@@ -0,0 +1,3 @@
+import { initProjectRegisterRunner } from '~/ci/runner/project_register_runner';
+
+initProjectRegisterRunner();
diff --git a/app/assets/javascripts/super_sidebar/components/create_menu.vue b/app/assets/javascripts/super_sidebar/components/create_menu.vue
index 4cff4642cf7..fa6056aff5e 100644
--- a/app/assets/javascripts/super_sidebar/components/create_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/create_menu.vue
@@ -1,6 +1,16 @@
<script>
-import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
+import {
+ GlDisclosureDropdown,
+ GlTooltip,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+} from '@gitlab/ui';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import { __ } from '~/locale';
+import {
+ TOP_NAV_INVITE_MEMBERS_COMPONENT,
+ TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
+} from '~/invite_members/constants';
import { DROPDOWN_Y_OFFSET } from '../constants';
// Left offset required for the dropdown to be aligned with the super sidebar
@@ -9,7 +19,10 @@ const DROPDOWN_X_OFFSET = -147;
export default {
components: {
GlDisclosureDropdown,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
GlTooltip,
+ InviteMembersTrigger,
},
i18n: {
createNew: __('Create new...'),
@@ -25,6 +38,14 @@ export default {
dropdownOpen: false,
};
},
+ methods: {
+ isInvitedMembers(groupItem) {
+ return groupItem.component === TOP_NAV_INVITE_MEMBERS_COMPONENT;
+ },
+ closeAndFocus() {
+ this.$refs.dropdown.closeAndFocus();
+ },
+ },
toggleId: 'create-menu-toggle',
popperOptions: {
modifiers: [
@@ -36,24 +57,44 @@ export default {
},
],
},
+ TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
};
</script>
<template>
<div>
<gl-disclosure-dropdown
+ ref="dropdown"
category="tertiary"
icon="plus"
- :items="groups"
no-caret
text-sr-only
:toggle-text="$options.i18n.createNew"
:toggle-id="$options.toggleId"
:popper-options="$options.popperOptions"
data-qa-selector="new_menu_toggle"
+ data-testid="new-menu-toggle"
@shown="dropdownOpen = true"
@hidden="dropdownOpen = false"
- />
+ >
+ <gl-disclosure-dropdown-group
+ v-for="(group, index) in groups"
+ :key="group.name"
+ :bordered="index !== 0"
+ :group="group"
+ >
+ <template v-for="groupItem in group.items">
+ <invite-members-trigger
+ v-if="isInvitedMembers(groupItem)"
+ :key="`${groupItem.text}-trigger`"
+ trigger-source="top-nav"
+ :trigger-element="$options.TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN"
+ @modal-opened="closeAndFocus"
+ />
+ <gl-disclosure-dropdown-item v-else :key="groupItem.text" :item="groupItem" />
+ </template>
+ </gl-disclosure-dropdown-group>
+ </gl-disclosure-dropdown>
<gl-tooltip
v-if="!dropdownOpen"
:target="`#${$options.toggleId}`"
diff --git a/app/assets/javascripts/super_sidebar/components/help_center.vue b/app/assets/javascripts/super_sidebar/components/help_center.vue
index a75d1fd6bff..70e1780aae1 100644
--- a/app/assets/javascripts/super_sidebar/components/help_center.vue
+++ b/app/assets/javascripts/super_sidebar/components/help_center.vue
@@ -12,7 +12,7 @@ import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { __ } from '~/locale';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import Tracking from '~/tracking';
-import { DROPDOWN_Y_OFFSET, HELP_MENU_TRACKING_DEFAULTS } from '../constants';
+import { DROPDOWN_Y_OFFSET, HELP_MENU_TRACKING_DEFAULTS, helpCenterState } from '../constants';
// Left offset required for the dropdown to be aligned with the super sidebar
const DROPDOWN_X_OFFSET = -4;
@@ -49,6 +49,7 @@ export default {
data() {
return {
showWhatsNewNotification: this.shouldShowWhatsNewNotification(),
+ helpCenterState,
};
},
computed: {
@@ -175,9 +176,10 @@ export default {
this.$refs.dropdown.close();
},
- async showTanukiBotChat() {
- // This will be implemented in the following MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117930
- return true;
+ showTanukiBotChat() {
+ this.$refs.dropdown.close();
+
+ this.helpCenterState.showTanukiBotChatDrawer = true;
},
async showWhatsNew() {
diff --git a/app/assets/javascripts/super_sidebar/constants.js b/app/assets/javascripts/super_sidebar/constants.js
index 4f5b027c138..f3f71feaa8a 100644
--- a/app/assets/javascripts/super_sidebar/constants.js
+++ b/app/assets/javascripts/super_sidebar/constants.js
@@ -20,6 +20,10 @@ export const sidebarState = Vue.observable({
closePeekTimer: null,
});
+export const helpCenterState = Vue.observable({
+ showTanukiBotChatDrawer: false,
+});
+
export const MAX_FREQUENT_PROJECTS_COUNT = 5;
export const MAX_FREQUENT_GROUPS_COUNT = 3;
diff --git a/app/assets/javascripts/vue_shared/issuable/list/constants.js b/app/assets/javascripts/vue_shared/issuable/list/constants.js
index 1b71819bdc2..7ece3b60bd5 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/constants.js
+++ b/app/assets/javascripts/vue_shared/issuable/list/constants.js
@@ -1,7 +1,7 @@
import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import { __ } from '~/locale';
-export const IssuableListTabs = [
+export const issuableListTabs = [
{
id: 'state-opened',
name: STATUS_OPEN,
@@ -22,7 +22,7 @@ export const IssuableListTabs = [
},
];
-export const AvailableSortOptions = [
+export const availableSortOptions = [
{
id: 1,
title: __('Created date'),
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
index 3c999d166dc..c7ac0b71510 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
@@ -5,7 +5,6 @@ import { s__ } from '~/locale';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { TYPENAME_ISSUE, TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
import { isMetaKey } from '~/lib/utils/common_utils';
import { getParameterByName, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
@@ -21,7 +20,6 @@ import getWorkItemLinksQuery from '../../graphql/work_item_links.query.graphql';
import addHierarchyChildMutation from '../../graphql/add_hierarchy_child.mutation.graphql';
import removeHierarchyChildMutation from '../../graphql/remove_hierarchy_child.mutation.graphql';
import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql';
-import workItemQuery from '../../graphql/work_item.query.graphql';
import workItemByIidQuery from '../../graphql/work_item_by_iid.query.graphql';
import WidgetWrapper from '../widget_wrapper.vue';
import WorkItemDetailModal from '../work_item_detail_modal.vue';
@@ -43,14 +41,8 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagMixin()],
inject: ['projectPath', 'reportAbusePath'],
props: {
- workItemId: {
- type: String,
- required: false,
- default: null,
- },
issuableId: {
type: Number,
required: false,
@@ -75,10 +67,8 @@ export default {
this.error = e.message || this.$options.i18n.fetchError;
},
async result() {
- const { id, iid } = this.childUrlParams();
- this.activeChild = this.fetchByIid
- ? this.children.find((child) => child.iid === iid) ?? {}
- : this.children.find((child) => child.id === id) ?? {};
+ const iid = getParameterByName('work_item_iid');
+ this.activeChild = this.children.find((child) => child.iid === iid) ?? {};
await this.$nextTick();
if (!isEmpty(this.activeChild)) {
this.$refs.modal.show();
@@ -147,31 +137,11 @@ export default {
childrenCountLabel() {
return this.isLoading && this.children.length === 0 ? '...' : this.children.length;
},
- fetchByIid() {
- return true;
- },
},
mounted() {
- if (!isEmpty(this.childUrlParams())) {
- this.addWorkItemQuery(this.childUrlParams());
- }
+ this.addWorkItemQuery(getParameterByName('work_item_iid'));
},
methods: {
- childUrlParams() {
- const params = {};
- if (this.fetchByIid) {
- const iid = getParameterByName('work_item_iid');
- if (iid) {
- params.iid = iid;
- }
- } else {
- const workItemId = getParameterByName('work_item_id');
- if (workItemId) {
- params.id = convertToGraphQLId(TYPENAME_WORK_ITEM, workItemId);
- }
- }
- return params;
- },
showAddForm(formType) {
this.$refs.wrapper.show();
this.isShownAddForm = true;
@@ -200,11 +170,8 @@ export default {
this.removeHierarchyChild(child);
this.activeToast = this.$toast.show(s__('WorkItem|Task deleted'));
},
- updateWorkItemIdUrlQuery({ id, iid } = {}) {
- const params = this.fetchByIid
- ? { work_item_iid: iid }
- : { work_item_id: getIdFromGraphQLId(id) };
- updateHistory({ url: setUrlParams(params), replace: true });
+ updateWorkItemIdUrlQuery({ iid } = {}) {
+ updateHistory({ url: setUrlParams({ work_item_iid: iid }), replace: true });
},
async addHierarchyChild(workItem) {
return this.$apollo.mutate({
@@ -251,31 +218,28 @@ export default {
});
}
},
- addWorkItemQuery({ id, iid }) {
- const variables = this.fetchByIid
- ? {
- fullPath: this.projectPath,
- iid,
- }
- : {
- id,
- };
+ addWorkItemQuery(iid) {
+ if (!iid) {
+ return;
+ }
+
this.$apollo.addSmartQuery('prefetchedWorkItem', {
- query() {
- return this.fetchByIid ? workItemByIidQuery : workItemQuery;
+ query: workItemByIidQuery,
+ variables: {
+ fullPath: this.projectPath,
+ iid,
},
- variables,
update(data) {
- return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return data.workspace.workItems.nodes[0];
},
context: {
isSingleRequest: true,
},
});
},
- prefetchWorkItem({ id, iid }) {
+ prefetchWorkItem({ iid }) {
this.prefetch = setTimeout(
- () => this.addWorkItemQuery({ id, iid }),
+ () => this.addWorkItemQuery(iid),
DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
);
},
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
index dd0d50861e4..06d6d62e603 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
@@ -1,7 +1,6 @@
<script>
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-
+import { getParameterByName } from '~/lib/utils/url_utility';
import {
FORM_TYPES,
WIDGET_TYPE_HIERARCHY,
@@ -10,7 +9,6 @@ import {
WORK_ITEM_TYPE_ENUM_KEY_RESULT,
WORK_ITEM_TYPE_VALUE_OBJECTIVE,
} from '../../constants';
-import workItemQuery from '../../graphql/work_item.query.graphql';
import workItemByIidQuery from '../../graphql/work_item_by_iid.query.graphql';
import WidgetWrapper from '../widget_wrapper.vue';
import OkrActionsSplitButton from './okr_actions_split_button.vue';
@@ -28,7 +26,6 @@ export default {
WorkItemLinksForm,
WorkItemLinkChild,
},
- mixins: [glFeatureFlagMixin()],
props: {
workItemType: {
type: String,
@@ -72,9 +69,6 @@ export default {
};
},
computed: {
- fetchByIid() {
- return true;
- },
childrenIds() {
return this.children.map((c) => c.id);
},
@@ -86,6 +80,9 @@ export default {
.some((hierarchy) => hierarchy.hasChildren);
},
},
+ mounted() {
+ this.addWorkItemQuery(getParameterByName('work_item_iid'));
+ },
methods: {
showAddForm(formType, childType) {
this.$refs.wrapper.show();
@@ -99,10 +96,10 @@ export default {
hideAddForm() {
this.isShownAddForm = false;
},
- prefetchWorkItem({ id, iid }) {
+ prefetchWorkItem({ iid }) {
if (this.workItemType !== WORK_ITEM_TYPE_VALUE_OBJECTIVE) {
this.prefetch = setTimeout(
- () => this.addWorkItemQuery({ id, iid }),
+ () => this.addWorkItemQuery(iid),
DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
);
}
@@ -112,22 +109,19 @@ export default {
clearTimeout(this.prefetch);
}
},
- addWorkItemQuery({ id, iid }) {
- const variables = this.fetchByIid
- ? {
- fullPath: this.projectPath,
- iid,
- }
- : {
- id,
- };
+ addWorkItemQuery(iid) {
+ if (!iid) {
+ return;
+ }
+
this.$apollo.addSmartQuery('prefetchedWorkItem', {
- query() {
- return this.fetchByIid ? workItemByIidQuery : workItemQuery;
+ query: workItemByIidQuery,
+ variables: {
+ fullPath: this.projectPath,
+ iid,
},
- variables,
update(data) {
- return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return data.workspace.workItems.nodes[0];
},
context: {
isSingleRequest: true,
diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue
index 9f653fc8f71..49ec12db4e1 100644
--- a/app/assets/javascripts/work_items/pages/create_work_item.vue
+++ b/app/assets/javascripts/work_items/pages/create_work_item.vue
@@ -1,13 +1,12 @@
<script>
import { GlButton, GlAlert, GlLoadingIcon, GlFormSelect } from '@gitlab/ui';
+import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
import { getPreferredLocales, s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { sprintfWorkItem, I18N_WORK_ITEM_ERROR_CREATING } from '../constants';
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
-import { getWorkItemQuery } from '../utils';
+import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
import ItemTitle from '../components/item_title.vue';
@@ -22,7 +21,6 @@ export default {
ItemTitle,
GlFormSelect,
},
- mixins: [glFeatureFlagMixin()],
inject: ['fullPath'],
props: {
initialTitle: {
@@ -73,9 +71,6 @@ export default {
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, workItemType);
},
- fetchByIid() {
- return true;
- },
},
methods: {
async createWorkItem() {
@@ -96,45 +91,31 @@ export default {
},
update: (store, { data: { workItemCreate } }) => {
const { workItem } = workItemCreate;
- const data = this.fetchByIid
- ? {
- workspace: {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- __typename: 'Project',
- id: workItem.project.id,
- workItems: {
- __typename: 'WorkItemConnection',
- nodes: [workItem],
- },
- },
- }
- : { workItem };
store.writeQuery({
- query: getWorkItemQuery(this.fetchByIid),
- variables: this.fetchByIid
- ? {
- fullPath: this.fullPath,
- iid: workItem.iid,
- }
- : {
- id: workItem.id,
+ query: workItemByIidQuery,
+ variables: {
+ fullPath: this.fullPath,
+ iid: workItem.iid,
+ },
+ data: {
+ workspace: {
+ __typename: TYPENAME_PROJECT,
+ id: workItem.project.id,
+ workItems: {
+ __typename: 'WorkItemConnection',
+ nodes: [workItem],
},
- data,
+ },
+ },
});
},
});
- const {
- data: {
- workItemCreate: {
- workItem: { id, iid },
- },
- },
- } = response;
- const routerParams = this.fetchByIid
- ? { name: 'workItem', params: { id: iid } }
- : { name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } };
- this.$router.push(routerParams);
+
+ this.$router.push({
+ name: 'workItem',
+ params: { id: response.data.workItemCreate.workItem.iid },
+ });
} catch {
this.error = this.createErrorText;
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index dba9cafbd71..82da6e959d0 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -886,6 +886,11 @@ Multi file editor
$border-color-settings: #e1e1e1;
/*
+Drawers
+*/
+$wide-drawer: 500px;
+
+/*
Modals
*/
$modal-body-height: 80px;
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index e3c901d787c..267bd3f9506 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -145,3 +145,7 @@
width: $gl-spacing-scale-30;
}
}
+
+.gl-fill-orange-500 {
+ fill: $orange-500;
+}
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 53c6676b62b..727a4e0251d 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -50,6 +50,7 @@ class Projects::BlobController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:highlight_js, @project)
push_frontend_feature_flag(:synchronize_fork, @project&.fork_source)
+ push_frontend_feature_flag(:explain_code_chat, current_user)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 6e9a1b575ce..2b2c2cef8e2 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -2,8 +2,8 @@
class Projects::RunnersController < Projects::ApplicationController
before_action :authorize_admin_build!
- before_action :authorize_create_runner!, only: [:new]
- before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
+ before_action :authorize_create_runner!, only: [:new, :register]
+ before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show, :register]
feature_category :runner
urgency :low
@@ -24,7 +24,11 @@ class Projects::RunnersController < Projects::ApplicationController
end
def new
- render_404 unless Feature.enabled?(:create_runner_workflow_for_namespace, project.namespace)
+ render_404 unless create_runner_workflow_for_namespace_enabled?
+ end
+
+ def register
+ render_404 unless create_runner_workflow_for_namespace_enabled? && runner.registration_available?
end
def destroy
@@ -80,4 +84,8 @@ class Projects::RunnersController < Projects::ApplicationController
def runner_params
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
+
+ def create_runner_workflow_for_namespace_enabled?
+ Feature.enabled?(:create_runner_workflow_for_namespace, project.namespace)
+ end
end
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 0631c02355e..495241df912 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -19,6 +19,7 @@ class Projects::TreeController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:highlight_js, @project)
push_frontend_feature_flag(:synchronize_fork, @project.fork_source)
+ push_frontend_feature_flag(:explain_code_chat, current_user)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 0a6ac2a25a4..d1a86083ac0 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -40,6 +40,7 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:highlight_js, @project)
push_frontend_feature_flag(:synchronize_fork, @project&.fork_source)
push_frontend_feature_flag(:remove_monitor_metrics, @project)
+ push_frontend_feature_flag(:explain_code_chat, current_user)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
push_licensed_feature(:security_orchestration_policies) if @project.present? && @project.licensed_feature_available?(:security_orchestration_policies)
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb
index 3d40da78dbc..2a9eb3b9b22 100644
--- a/app/finders/deployments_finder.rb
+++ b/app/finders/deployments_finder.rb
@@ -59,8 +59,8 @@ class DeploymentsFinder
# Currently, the inefficient parameters are allowed in order to avoid breaking changes in Deployment API.
# We'll switch to a hard error in https://gitlab.com/gitlab-org/gitlab/-/issues/328500.
- if (filter_by_updated_at? && !order_by_updated_at?) || (!filter_by_updated_at? && order_by_updated_at?)
- error = InefficientQueryError.new('`updated_at` filter and `updated_at` sorting must be paired')
+ if filter_by_updated_at? && !order_by_updated_at?
+ error = InefficientQueryError.new('`updated_at` filter requires `updated_at` sort')
Gitlab::ErrorTracking.log_exception(error)
diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb
index 20e8b506a3f..6367847a5a5 100644
--- a/app/graphql/types/ci/runner_type.rb
+++ b/app/graphql/types/ci/runner_type.rb
@@ -158,6 +158,8 @@ module Types
Gitlab::Routing.url_helpers.register_admin_runner_url(runner)
when 'group_type'
Gitlab::Routing.url_helpers.register_group_runner_url(runner.groups[0], runner)
+ when 'project_type'
+ Gitlab::Routing.url_helpers.register_project_runner_url(runner.projects[0], runner)
end
end
@@ -212,6 +214,10 @@ module Types
group = runner.groups[0]
group && context[:current_user]&.can?(:register_group_runners, group)
+ when 'project_type'
+ project = runner.projects[0]
+
+ project && context[:current_user]&.can?(:register_project_runners, project)
end
end
end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index fb906759ba4..20dce54d740 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -14,6 +14,13 @@ module Types
null: true,
description: 'CI related settings that apply to the entire instance.'
field :ci_config, resolver: Resolvers::Ci::ConfigResolver, complexity: 126 # AUTHENTICATED_MAX_COMPLEXITY / 2 + 1
+
+ field :ci_pipeline_stage, ::Types::Ci::StageType,
+ null: true, description: 'Stage belonging to a CI pipeline.' do
+ argument :id, type: ::Types::GlobalIDType[::Ci::Stage],
+ required: true, description: 'Global ID of the CI stage.'
+ end
+
field :ci_variables,
Types::Ci::InstanceVariableType.connection_type,
null: true,
@@ -202,6 +209,15 @@ module Types
def query_complexity
context.query
end
+
+ def ci_pipeline_stage(id:)
+ stage = ::Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(id))
+ authorized = Ability.allowed?(current_user, :read_build, stage.project)
+
+ return unless authorized
+
+ stage
+ end
end
end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 4dfc65dd849..d249364a4de 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -155,18 +155,19 @@ module SidebarsHelper
{
name: show_headers ? section[:title] : '',
items: section[:menu_items].map do |item|
- {
- text: item[:title],
- href: item[:href],
- extraAttrs: {
- 'data-track-label': item[:id],
- 'data-track-action': 'click_link',
- 'data-track-property': 'nav_create_menu',
- 'data-qa-selector': 'create_menu_item',
- 'data-qa-create-menu-item': item[:id]
- }
- }
- end
+ {
+ text: item[:title],
+ href: item[:href].presence,
+ component: item[:component].presence,
+ extraAttrs: {
+ 'data-track-label': item[:id],
+ 'data-track-action': 'click_link',
+ 'data-track-property': 'nav_create_menu',
+ 'data-qa-selector': 'create_menu_item',
+ 'data-qa-create-menu-item': item[:id]
+ }
+ }
+ end
}
end
end
diff --git a/app/models/ci/build_need.rb b/app/models/ci/build_need.rb
index 03d1bd14bfb..940221619b3 100644
--- a/app/models/ci/build_need.rb
+++ b/app/models/ci/build_need.rb
@@ -6,8 +6,6 @@ module Ci
include BulkInsertSafe
include IgnorableColumns
- ignore_column :id_convert_to_bigint, remove_with: '16.0', remove_after: '2023-04-22'
-
belongs_to :build, class_name: "Ci::Processable", foreign_key: :build_id, inverse_of: :needs
partitionable scope: :build
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 80a3d8df632..dc285a4268a 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -506,6 +506,10 @@ module Ci
!runner_managers.any?
end
+ def gitlab_hosted?
+ Gitlab.com? && instance_type?
+ end
+
private
scope :with_upgrade_status, ->(upgrade_status) do
diff --git a/app/services/ci/archive_trace_service.rb b/app/services/ci/archive_trace_service.rb
index f2ace1f1590..e370f85fa96 100644
--- a/app/services/ci/archive_trace_service.rb
+++ b/app/services/ci/archive_trace_service.rb
@@ -67,21 +67,23 @@ module Ci
def failed_archive_counter
@failed_archive_counter ||=
- Gitlab::Metrics.counter(:job_trace_archive_failed_total,
- "Counter of failed attempts of trace archiving")
+ Gitlab::Metrics.counter(:job_trace_archive_failed_total, "Counter of failed attempts of trace archiving")
end
def archive_error(error, job, worker_name)
failed_archive_counter.increment
- Sidekiq.logger.warn(class: worker_name,
- message: "Failed to archive trace. message: #{error.message}.",
- job_id: job.id)
-
- Gitlab::ErrorTracking
- .track_and_raise_for_dev_exception(error,
- issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/51502',
- job_id: job.id)
+ Sidekiq.logger.warn(
+ class: worker_name,
+ message: "Failed to archive trace. message: #{error.message}.",
+ job_id: job.id
+ )
+
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ error,
+ issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/51502',
+ job_id: job.id
+ )
end
end
end
diff --git a/app/services/ci/ensure_stage_service.rb b/app/services/ci/ensure_stage_service.rb
index cbb3a2e4709..9d5ccecbe33 100644
--- a/app/services/ci/ensure_stage_service.rb
+++ b/app/services/ci/ensure_stage_service.rb
@@ -45,10 +45,12 @@ module Ci
# rubocop: enable CodeReuse/ActiveRecord
def create_stage
- Ci::Stage.create!(name: @build.stage,
- position: @build.stage_idx,
- pipeline: @build.pipeline,
- project: @build.project)
+ Ci::Stage.create!(
+ name: @build.stage,
+ position: @build.stage_idx,
+ pipeline: @build.pipeline,
+ project: @build.project
+ )
end
end
end
diff --git a/app/services/ci/list_config_variables_service.rb b/app/services/ci/list_config_variables_service.rb
index dbea270b7c6..1020e98f463 100644
--- a/app/services/ci/list_config_variables_service.rb
+++ b/app/services/ci/list_config_variables_service.rb
@@ -28,9 +28,12 @@ module Ci
return {} unless config.exists?
- result = Gitlab::Ci::YamlProcessor.new(config.content, project: project,
- user: current_user,
- sha: sha).execute
+ result = Gitlab::Ci::YamlProcessor.new(
+ config.content,
+ project: project,
+ user: current_user,
+ sha: sha
+ ).execute
result.valid? ? result.root_variables_with_prefill_data : {}
end
diff --git a/app/services/ci/parse_dotenv_artifact_service.rb b/app/services/ci/parse_dotenv_artifact_service.rb
index d4d5acef44e..89a3c7d9e03 100644
--- a/app/services/ci/parse_dotenv_artifact_service.rb
+++ b/app/services/ci/parse_dotenv_artifact_service.rb
@@ -44,8 +44,13 @@ module Ci
blob.each_line do |line|
key, value = scan_line!(line)
- variables[key] = Ci::JobVariable.new(job_id: artifact.job_id,
- source: :dotenv, key: key, value: value, raw: false)
+ variables[key] = Ci::JobVariable.new(
+ job_id: artifact.job_id,
+ source: :dotenv,
+ key: key,
+ value: value,
+ raw: false
+ )
end
end
diff --git a/app/services/ci/stuck_builds/drop_helpers.rb b/app/services/ci/stuck_builds/drop_helpers.rb
index f56c9aaeb55..4ce30a6068c 100644
--- a/app/services/ci/stuck_builds/drop_helpers.rb
+++ b/app/services/ci/stuck_builds/drop_helpers.rb
@@ -45,23 +45,26 @@ module Ci
end
def track_exception_for_build(ex, build)
- Gitlab::ErrorTracking.track_exception(ex,
- build_id: build.id,
- build_name: build.name,
- build_stage: build.stage_name,
- pipeline_id: build.pipeline_id,
- project_id: build.project_id
+ Gitlab::ErrorTracking.track_exception(
+ ex,
+ build_id: build.id,
+ build_name: build.name,
+ build_stage: build.stage_name,
+ pipeline_id: build.pipeline_id,
+ project_id: build.project_id
)
end
def log_dropping_message(type, build, reason)
- Gitlab::AppLogger.info(class: self.class.name,
- message: "Dropping #{type} build",
- build_stuck_type: type,
- build_id: build.id,
- runner_id: build.runner_id,
- build_status: build.status,
- build_failure_reason: reason)
+ Gitlab::AppLogger.info(
+ class: self.class.name,
+ message: "Dropping #{type} build",
+ build_stuck_type: type,
+ build_id: build.id,
+ runner_id: build.runner_id,
+ build_status: build.status,
+ build_failure_reason: reason
+ )
end
end
end
diff --git a/app/views/groups/runners/register.html.haml b/app/views/groups/runners/register.html.haml
index fdee1675475..7e12aa3ab3f 100644
--- a/app/views/groups/runners/register.html.haml
+++ b/app/views/groups/runners/register.html.haml
@@ -1,6 +1,6 @@
- runner_name = "##{@runner.id} (#{@runner.short_sha})"
- breadcrumb_title s_('Runners|Register')
-- page_title s_('Runners|Register'), "##{@runner.id} (#{@runner.short_sha})"
+- page_title s_('Runners|Register'), runner_name
- add_to_breadcrumbs _('Runners'), group_runners_path(@group)
- add_to_breadcrumbs runner_name, register_group_runner_path(@runner)
diff --git a/app/views/projects/runners/register.html.haml b/app/views/projects/runners/register.html.haml
new file mode 100644
index 00000000000..561a919323d
--- /dev/null
+++ b/app/views/projects/runners/register.html.haml
@@ -0,0 +1,7 @@
+- runner_name = "##{@runner.id} (#{@runner.short_sha})"
+
+- add_to_breadcrumbs _('CI/CD Settings'), project_settings_ci_cd_path(@project)
+- breadcrumb_title s_('Runners|Register runner')
+- page_title s_('Runners|Register'), runner_name
+
+#js-project-register-runner{ data: { runner_id: @runner.id, runners_path: project_runners_path(@project) } }
diff --git a/config/feature_flags/development/allow_dots_on_tf_state_names.yml b/config/feature_flags/development/allow_dots_on_tf_state_names.yml
deleted file mode 100644
index f7a981d11db..00000000000
--- a/config/feature_flags/development/allow_dots_on_tf_state_names.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: allow_dots_on_tf_state_names
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106861
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/385597
-milestone: '15.7'
-type: development
-group: group::configure
-default_enabled: true
diff --git a/config/feature_flags/development/explain_code_chat.yml b/config/feature_flags/development/explain_code_chat.yml
new file mode 100644
index 00000000000..6599c3015b4
--- /dev/null
+++ b/config/feature_flags/development/explain_code_chat.yml
@@ -0,0 +1,8 @@
+---
+name: explain_code_chat
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117674
+rollout_issue_url:
+milestone: '16.0'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/synchronize_fork.yml b/config/feature_flags/development/synchronize_fork.yml
index 46307136c33..207739cf34e 100644
--- a/config/feature_flags/development/synchronize_fork.yml
+++ b/config/feature_flags/development/synchronize_fork.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/395793
milestone: '15.10'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/routes/project.rb b/config/routes/project.rb
index bb79b4ee89d..ef5f95eee75 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -106,6 +106,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :runners, only: [:index, :new, :edit, :update, :destroy, :show] do
member do
+ get :register
post :resume
post :pause
end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 57868455803..78a9a8a9e67 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -108,6 +108,18 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="queryciminutesusagedate"></a>`date` | [`Date`](#date) | Date for which to retrieve the usage data, should be the first day of a month. |
| <a id="queryciminutesusagenamespaceid"></a>`namespaceId` | [`NamespaceID`](#namespaceid) | Global ID of the Namespace for the monthly CI/CD minutes usage. |
+### `Query.ciPipelineStage`
+
+Stage belonging to a CI pipeline.
+
+Returns [`CiStage`](#cistage).
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="querycipipelinestageid"></a>`id` | [`CiStageID!`](#cistageid) | Global ID of the CI stage. |
+
### `Query.ciVariables`
List of the instance's CI/CD variables.
@@ -25349,6 +25361,12 @@ A `CiRunnerManagerID` is a global ID. It is encoded as a string.
An example `CiRunnerManagerID` is: `"gid://gitlab/Ci::RunnerManager/1"`.
+### `CiStageID`
+
+A `CiStageID` is a global ID. It is encoded as a string.
+
+An example `CiStageID` is: `"gid://gitlab/Ci::Stage/1"`.
+
### `ClustersAgentID`
A `ClustersAgentID` is a global ID. It is encoded as a string.
diff --git a/doc/ci/resource_groups/index.md b/doc/ci/resource_groups/index.md
index d00a92169f1..ee7256dad3f 100644
--- a/doc/ci/resource_groups/index.md
+++ b/doc/ci/resource_groups/index.md
@@ -194,13 +194,11 @@ You must define [`strategy: depend`](../yaml/index.md#triggerstrategy)
with the `trigger` keyword. This ensures that the lock isn't released until the downstream pipeline
finishes.
-## API
+## Related topics
-See the [API documentation](../../api/resource_groups.md).
-
-## Related features
-
-Read more how you can use GitLab for [safe deployments](../environments/deployment_safety.md).
+- [API documentation](../../api/resource_groups.md)
+- [Log documentation](../../administration/logs/index.md#ci_resource_groups_jsonlog)
+- [GitLab for safe deployments](../environments/deployment_safety.md)
## Troubleshooting
diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md
index d6d1f62e47d..177398a6acc 100644
--- a/doc/ci/secrets/id_token_authentication.md
+++ b/doc/ci/secrets/id_token_authentication.md
@@ -67,6 +67,9 @@ The token also includes custom claims provided by GitLab:
| `environment` | Job specifies an environment | Environment this job deploys to ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9). |
| `environment_protected` | Job specifies an environment | `true` if deployed environment is protected, `false` otherwise ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9). |
| `deployment_tier` | Job specifies an environment | [Deployment tier](../environments/index.md#deployment-tier-of-environments) of the environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363590) in GitLab 15.2. |
+| `runner_id` | Always | ID of the runner executing the job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. |
+| `runner_environment` | Always | The type of runner used by the job. Can be either `gitlab-hosted` or `self-hosted`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. |
+| `sha` | Always | The commit SHA for the job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. |
```json
{
@@ -86,6 +89,9 @@ The token also includes custom claims provided by GitLab:
"environment": "test-environment2",
"environment_protected": "false",
"deployment_tier": "testing",
+ "runner_id": 1,
+ "runner_environment": "self-hosted",
+ "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
"jti": "235b3a54-b797-45c7-ae9a-f72d7bc6ef5b",
"iss": "https://gitlab.example.com",
"iat": 1681395193,
diff --git a/doc/install/aws/eks_clusters_aws.md b/doc/install/aws/eks_clusters_aws.md
index 191d0f93382..ccbc0752975 100644
--- a/doc/install/aws/eks_clusters_aws.md
+++ b/doc/install/aws/eks_clusters_aws.md
@@ -23,7 +23,7 @@ Using `eksctl` enables the following when building an EKS Cluster:
- You have various cluster configuration options:
- Selection of operating system: Amazon Linux 2, Windows, Bottlerocket
- Selection of Hardware Architecture: x86, ARM, GPU
- - Selection of Kubernetes version (the GitLab-managed clusters for your project's applications have [specific Kubernetes version requirements](../../user/clusters/agent/index.md#supported-cluster-versions))
+ - Selection of Kubernetes version (the GitLab-managed clusters for your project's applications have [specific Kubernetes version requirements](../../user/clusters/agent/index.md#gitlab-agent-for-kubernetes-supported-cluster-versions))
- It can deploy high value-add items to the cluster, including:
- A bastion host to keep the cluster endpoint private and possible perform performance testing.
- Prometheus and Grafana for monitoring.
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index 2cffad0b0e0..dfef58ad830 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -31,9 +31,10 @@ before we remove them.
### OpenSearch version requirements
-| GitLab version | OpenSearch version |
-|-----------------------|--------------------------|
-| GitLab 15.0 or later | OpenSearch 1.x or later |
+| GitLab version | OpenSearch version |
+|-------------------------|---------------------------|
+| GitLab 15.0 to 15.5.2 | OpenSearch 1.x |
+| GitLab 15.5.3 and later | OpenSearch 1.x and later |
If your version of Elasticsearch or OpenSearch is incompatible, to prevent data loss, indexing pauses and
a message is logged in the
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index e67e7b0f97e..d6a9190be1e 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.md
@@ -162,7 +162,6 @@ chart panel. To activate keyboard shortcuts, use keyboard tabs to highlight the
with your mouse, then press the key corresponding to your desired action:
- **Expand panel** - <kbd>e</kbd>
-- **View logs** - <kbd>l</kbd> (lowercase 'L')
- **Download CSV** - <kbd>d</kbd>
- **Copy link to chart** - <kbd>c</kbd>
- **Alerts** - <kbd>a</kbd>
diff --git a/doc/policy/alpha-beta-support.md b/doc/policy/alpha-beta-support.md
index 8976e0ed503..252b6a6fd1b 100644
--- a/doc/policy/alpha-beta-support.md
+++ b/doc/policy/alpha-beta-support.md
@@ -49,3 +49,11 @@ Generally Available features means that they passed the [Production Readiness Re
- Ready for production use at any scale.
- Fully documented and supported.
- UX complete and in line with GitLab design standards.
+
+## Never internal
+
+Features are never internal (GitLab team-members) only.
+Our [mission is "everyone can contribute"](https://about.gitlab.com/company/mission/), and that is only possible if people outside the company can try a feature.
+We will get higher quality (more diverse) feedback if people from different organizations try something.
+We've also learned that internal only as a state slows us down more than it speeds us up.
+The experimental features are only shown when people/organizations opt-in to experiments, we are allowed to make mistakes here and literally experiment.
diff --git a/doc/topics/autodevops/cicd_variables.md b/doc/topics/autodevops/cicd_variables.md
index 4242958d962..f4c74fe3245 100644
--- a/doc/topics/autodevops/cicd_variables.md
+++ b/doc/topics/autodevops/cicd_variables.md
@@ -62,8 +62,7 @@ Use these variables to customize and deploy your build.
## Database variables
WARNING:
-The default value of `true` for `POSTGRES_ENABLED` was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387766)
-in GitLab 15.8. In [GitLab 16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/343988), the default value will change to `false`.
+From [GitLab 16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/343988), `POSTGRES_ENABLED` is no longer set by default.
Use these variables to integrate CI/CD with PostgreSQL databases.
@@ -71,7 +70,7 @@ Use these variables to integrate CI/CD with PostgreSQL databases.
|-----------------------------------------|------------------------------------|
| `DB_INITIALIZE` | Used to specify the command to run to initialize the application's PostgreSQL database. Runs inside the application pod. |
| `DB_MIGRATE` | Used to specify the command to run to migrate the application's PostgreSQL database. Runs inside the application pod. |
-| `POSTGRES_ENABLED` | Whether PostgreSQL is enabled. Defaults to `true` until GitLab 16.0, when the default will change to `false`. Set to `false` to disable the automatic deployment of PostgreSQL. |
+| `POSTGRES_ENABLED` | Whether PostgreSQL is enabled. Set to `true` to enable the automatic deployment of PostgreSQL. |
| `POSTGRES_USER` | The PostgreSQL user. Defaults to `user`. Set it to use a custom username. |
| `POSTGRES_PASSWORD` | The PostgreSQL password. Defaults to `testing-password`. Set it to use a custom password. |
| `POSTGRES_DB` | The PostgreSQL database name. Defaults to the value of [`$CI_ENVIRONMENT_SLUG`](../../ci/variables/index.md#predefined-cicd-variables). Set it to use a custom database name. |
diff --git a/doc/topics/autodevops/upgrading_postgresql.md b/doc/topics/autodevops/upgrading_postgresql.md
index 2cf85dc07d7..77e98d7bcaa 100644
--- a/doc/topics/autodevops/upgrading_postgresql.md
+++ b/doc/topics/autodevops/upgrading_postgresql.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Upgrading PostgreSQL for Auto DevOps **(FREE)**
-Auto DevOps provides an [in-cluster PostgreSQL database](customize.md#postgresql-database-support)
-for your application.
+When `POSTGRES_ENABLED` is `true`, Auto DevOps provides an
+[in-cluster PostgreSQL database](customize.md#postgresql-database-support) for your application.
The version of the chart used to provision PostgreSQL:
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index 07149ccd8fc..ccb3a346903 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -52,9 +52,9 @@ Use this workflow:
This workflow has a weaker security model and is not recommended for production deployments.
-## Supported cluster versions
+## GitLab agent for Kubernetes supported cluster versions
-GitLab supports the following Kubernetes versions. You can upgrade your
+The agent for Kubernetes supports the following Kubernetes versions. You can upgrade your
Kubernetes version to a supported version at any time:
- 1.26 (support ends on March 22, 2024 or when 1.29 becomes supported)
diff --git a/doc/user/clusters/agent/troubleshooting.md b/doc/user/clusters/agent/troubleshooting.md
index d058a583b19..531dac20fb6 100644
--- a/doc/user/clusters/agent/troubleshooting.md
+++ b/doc/user/clusters/agent/troubleshooting.md
@@ -239,4 +239,4 @@ When you install the agent, you might encounter an error that states:
Error: parse error at (gitlab-agent/templates/observability-secret.yaml:1): unclosed action
```
-This error is typically caused by an incompatible version of Helm. To resolve the issue, ensure that you are using a version of Helm [compatible with your version of Kubernetes](index.md#supported-cluster-versions).
+This error is typically caused by an incompatible version of Helm. To resolve the issue, ensure that you are using a version of Helm [compatible with your version of Kubernetes](index.md#gitlab-agent-for-kubernetes-supported-cluster-versions).
diff --git a/doc/user/compliance/license_check_rules.md b/doc/user/compliance/license_check_rules.md
new file mode 100644
index 00000000000..3007d04a8c1
--- /dev/null
+++ b/doc/user/compliance/license_check_rules.md
@@ -0,0 +1,15 @@
+---
+redirect_to: 'license_approval_policies.md'
+remove_date: '2023-07-25'
+---
+
+# License Check Policies (removed) **(ULTIMATE)**
+
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390417) in GitLab 15.9
+and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/397067) in 16.0.
+Use [License Approval Policies](license_approval_policies.md) instead.
+
+<!-- This redirect file can be deleted after <2023-07-25>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/infrastructure/iac/terraform_state.md b/doc/user/infrastructure/iac/terraform_state.md
index 9bddbfdb1dd..1b0065fd165 100644
--- a/doc/user/infrastructure/iac/terraform_state.md
+++ b/doc/user/infrastructure/iac/terraform_state.md
@@ -7,10 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab-managed Terraform state **(FREE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 13.0.
-> - Support for state names that contain periods introduced in GitLab 15.7 [with a flag](../../../administration/feature_flags.md) named `allow_dots_on_tf_state_names`. Disabled by default. [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106861) in GitLab 15.7.
-
-FLAG:
-On self-managed GitLab, by default support for state names that contain periods is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `allow_dots_on_tf_state_names`. On GitLab.com, support for state names that contain periods is available. Requests for state files might generate HTTP 404 errors after enabling this feature. For more information, see [Troubleshooting the Terraform integration with GitLab](troubleshooting.md#state-not-found-if-the-state-name-contains-a-period).
+> - Support for state names that contain periods introduced in GitLab 15.7 [with a flag](../../../administration/feature_flags.md) named `allow_dots_on_tf_state_names`. Disabled by default.
+> - Support for state names that contain periods [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/385597) in GitLab 16.0. Feature flag `allow_dots_on_tf_state_names` removed.
Terraform uses state files to store details about your infrastructure configuration.
With Terraform remote [backends](https://www.terraform.io/language/settings/backends/configuration),
diff --git a/doc/user/infrastructure/iac/troubleshooting.md b/doc/user/infrastructure/iac/troubleshooting.md
index 624bb5ff276..d770c0111d0 100644
--- a/doc/user/infrastructure/iac/troubleshooting.md
+++ b/doc/user/infrastructure/iac/troubleshooting.md
@@ -160,12 +160,3 @@ If your `TF_HTTP_ADDRESS`, `TF_HTTP_LOCK_ADDRESS` and `TF_HTTP_UNLOCK_ADDRESS` a
to update the state names there.
Alternatively, you can [migrate your terraform state](terraform_state.md#migrate-to-a-gitlab-managed-terraform-state).
-
-#### Self-managed GitLab instances
-
-By default, support for state names with periods is not enabled on self-managed GitLab.
-You can enable it from the Rails console:
-
-```ruby
-Feature.enable(:allow_dots_on_tf_state_names)
-```
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 0428a66cd37..da4d2da70fe 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -110,12 +110,9 @@ between the fixed (max. `1280px`) and the fluid (`100%`) application layout.
NOTE:
While `1280px` is the standard max width when using fixed layout, some pages still use 100% width, depending on the content.
-### Dashboard
+### Homepage
-For users who have access to a large number of projects but only keep up with a
-select few, the amount of activity on the your dashboard can be
-overwhelming. From the **Dashboard** dropdown list, select what you'd like displayed on your
-personal dashboard.
+This setting changes the behavior of the tanuki icon in the upper-left corner of GitLab.
### Group overview content
diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md
index f4b806c3047..6c8edb8c3e5 100644
--- a/doc/user/project/clusters/add_eks_clusters.md
+++ b/doc/user/project/clusters/add_eks_clusters.md
@@ -174,7 +174,7 @@ When you create a new cluster, you have the following settings:
| Kubernetes cluster name | Your cluster's name. |
| Environment scope | The [associated environment](multiple_kubernetes_clusters.md#setting-the-environment-scope). |
| Service role | The **EKS IAM role** (**role A**). |
-| Kubernetes version | The [Kubernetes version](../../clusters/agent/index.md#supported-cluster-versions) for your cluster. |
+| Kubernetes version | The [Kubernetes version](../../clusters/agent/index.md#gitlab-agent-for-kubernetes-supported-cluster-versions) for your cluster. |
| Key pair name | The [key pair](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) that you can use to connect to your worker nodes. |
| VPC | The [VPC](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html) to use for your EKS Cluster resources. |
| Subnets | The [subnets](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) in your VPC where your worker nodes run. Two are required. |
diff --git a/doc/user/project/merge_requests/reviews/data_usage.md b/doc/user/project/merge_requests/reviews/data_usage.md
index dd07f0b4a6e..f0eb3c015b6 100644
--- a/doc/user/project/merge_requests/reviews/data_usage.md
+++ b/doc/user/project/merge_requests/reviews/data_usage.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: index, reference
---
-# Suggested Reviewers Data Usage
+# Suggested Reviewers Data Usage **(ULTIMATE SAAS)**
## How it works
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index 184690f9979..8017a195f28 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -55,17 +55,6 @@ module API
def remote_state_handler
::Terraform::RemoteStateHandler.new(user_project, current_user, name: params[:name], lock_id: params[:ID])
end
-
- def not_found_for_dots?
- Feature.disabled?(:allow_dots_on_tf_state_names) && params[:name].include?(".")
- end
-
- # Change the state name to behave like before, https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105674
- # has been introduced. This behavior can be controlled via `allow_dots_on_tf_state_names` FF.
- # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106861
- def legacy_state_name!
- params[:name] = params[:name].split('.').first
- end
end
desc 'Get a Terraform state by its name' do
@@ -83,8 +72,6 @@ module API
end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get do
- legacy_state_name! if not_found_for_dots?
-
remote_state_handler.find_with_lock do |state|
no_content! unless state.latest_file && state.latest_file.exists?
@@ -109,7 +96,6 @@ module API
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post do
authorize! :admin_terraform_state, user_project
- legacy_state_name! if not_found_for_dots?
data = request.body.read
no_content! if data.empty?
@@ -138,7 +124,6 @@ module API
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
delete do
authorize! :admin_terraform_state, user_project
- legacy_state_name! if not_found_for_dots?
remote_state_handler.find_with_lock do |state|
::Terraform::States::TriggerDestroyService.new(state, current_user: current_user).execute
@@ -170,8 +155,6 @@ module API
requires :Path, type: String, desc: 'Terraform path'
end
post '/lock' do
- not_found! if not_found_for_dots?
-
authorize! :admin_terraform_state, user_project
status_code = :ok
@@ -215,8 +198,6 @@ module API
optional :ID, type: String, limit: 255, desc: 'Terraform state lock ID'
end
delete '/lock' do
- not_found! if not_found_for_dots?
-
authorize! :admin_terraform_state, user_project
remote_state_handler.unlock!
diff --git a/lib/gitlab/ci/jwt_v2.rb b/lib/gitlab/ci/jwt_v2.rb
index fdff5035d37..bb49c18f784 100644
--- a/lib/gitlab/ci/jwt_v2.rb
+++ b/lib/gitlab/ci/jwt_v2.rb
@@ -4,6 +4,8 @@ module Gitlab
module Ci
class JwtV2 < Jwt
DEFAULT_AUD = Settings.gitlab.base_url
+ GITLAB_HOSTED_RUNNER = 'gitlab-hosted'
+ SELF_HOSTED_RUNNER = 'self-hosted'
def self.for_build(build, aud: DEFAULT_AUD)
new(build, ttl: build.metadata_timeout, aud: aud).encoded
@@ -38,6 +40,14 @@ module Gitlab
}
end
end
+
+ def custom_claims
+ super.merge(
+ runner_id: build.runner.id,
+ runner_environment: build.runner.gitlab_hosted? ? GITLAB_HOSTED_RUNNER : SELF_HOSTED_RUNNER,
+ sha: build.pipeline.sha
+ )
+ end
end
end
end
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 11420b05dfb..4f12f0cd3b8 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -58,7 +58,6 @@ variables:
POSTGRES_USER: user
POSTGRES_PASSWORD: testing-password
- POSTGRES_ENABLED: "true"
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
DOCKER_DRIVER: overlay2
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 62e14eebc9a..2936d4d21b9 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1860,6 +1860,9 @@ msgstr ""
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
+msgid "AI|There is too much text in the chat. Please try again with a shorter text."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1872,6 +1875,9 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
+msgid "AI|You can ask AI for more information."
+msgstr ""
+
msgid "API"
msgstr ""
@@ -11048,6 +11054,9 @@ msgstr ""
msgid "ComplianceReport|Framework successfully removed"
msgstr ""
+msgid "ComplianceReport|Full target branch name"
+msgstr ""
+
msgid "ComplianceReport|Less than 2 approvers"
msgstr ""
@@ -11063,6 +11072,9 @@ msgstr ""
msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
msgstr ""
+msgid "ComplianceReport|Search target branch"
+msgstr ""
+
msgid "ComplianceReport|Select at least one project to apply the bulk action"
msgstr ""
@@ -16690,12 +16702,21 @@ msgstr ""
msgid "Environments|protected"
msgstr ""
+msgid "Environment|Age"
+msgstr ""
+
msgid "Environment|Auto stop %{time}"
msgstr ""
+msgid "Environment|Cluster IP"
+msgstr ""
+
msgid "Environment|Deployment tier"
msgstr ""
+msgid "Environment|External IP"
+msgstr ""
+
msgid "Environment|Failed"
msgstr ""
@@ -16708,9 +16729,15 @@ msgstr ""
msgid "Environment|Pods"
msgstr ""
+msgid "Environment|Ports"
+msgstr ""
+
msgid "Environment|Running"
msgstr ""
+msgid "Environment|Services"
+msgstr ""
+
msgid "Environment|Succeeded"
msgstr ""
@@ -25906,6 +25933,9 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
+msgid "Legacy Web IDE"
+msgstr ""
+
msgid "Legacy burndown chart"
msgstr ""
@@ -38373,6 +38403,9 @@ msgstr ""
msgid "Runners|Project runners"
msgstr ""
+msgid "Runners|Project › CI/CD Settings › Runners"
+msgstr ""
+
msgid "Runners|Property Name"
msgstr ""
@@ -43617,6 +43650,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "TanukiBot|Tanuki Bot"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -48633,9 +48669,6 @@ msgstr ""
msgid "View log"
msgstr ""
-msgid "View logs"
-msgstr ""
-
msgid "View milestones"
msgstr ""
@@ -50308,9 +50341,18 @@ msgstr ""
msgid "Workspaces|Create workspace"
msgstr ""
+msgid "Workspaces|Creating"
+msgstr ""
+
msgid "Workspaces|Develop anywhere"
msgstr ""
+msgid "Workspaces|Error"
+msgstr ""
+
+msgid "Workspaces|Failed"
+msgstr ""
+
msgid "Workspaces|Failed to create workspace"
msgstr ""
@@ -50320,6 +50362,9 @@ msgstr ""
msgid "Workspaces|New workspace"
msgstr ""
+msgid "Workspaces|Running"
+msgstr ""
+
msgid "Workspaces|Select cluster agent"
msgstr ""
@@ -50329,12 +50374,24 @@ msgstr ""
msgid "Workspaces|Select project"
msgstr ""
+msgid "Workspaces|Starting"
+msgstr ""
+
+msgid "Workspaces|Stopped"
+msgstr ""
+
+msgid "Workspaces|Stopping"
+msgstr ""
+
msgid "Workspaces|To create a workspace for this project, an administrator must configure an agent for the project's group."
msgstr ""
msgid "Workspaces|To create a workspace, add a devfile to this project. A devfile is a configuration file for your workspace."
msgstr ""
+msgid "Workspaces|Unknown state"
+msgstr ""
+
msgid "Workspaces|Workspaces"
msgstr ""
diff --git a/package.json b/package.json
index 67389cf31a9..b884cd07239 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.2.0",
"@gitlab/svgs": "3.40.0",
- "@gitlab/ui": "61.3.0",
+ "@gitlab/ui": "62.4.0",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "0.0.1-dev-20230425040132",
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index 18efa445b26..42552a5e9b1 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -83,7 +83,7 @@ gitlab:
cpu: 400m
memory: 920Mi
limits:
- cpu: 800m
+ cpu: 1000m
memory: 1380Mi
sidekiq:
diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb
index 2edb41b7119..e0e4d0f7bc5 100644
--- a/spec/controllers/projects/runners_controller_spec.rb
+++ b/spec/controllers/projects/runners_controller_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Projects::RunnersController, feature_category: :runner_fleet do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:runner) { create(:ci_runner, :project, projects: [project]) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:params) do
{
@@ -78,6 +78,79 @@ RSpec.describe Projects::RunnersController, feature_category: :runner_fleet do
end
end
+ describe '#register' do
+ subject(:register) { get :register, params: { namespace_id: project.namespace, project_id: project, id: new_runner } }
+
+ context 'when create_runner_workflow_for_namespace is enabled' do
+ before do
+ stub_feature_flags(create_runner_workflow_for_namespace: [project.namespace])
+ end
+
+ context 'when user is maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'when runner can be registered after creation' do
+ let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) }
+
+ it 'renders a :register template' do
+ register
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:register)
+ end
+ end
+
+ context 'when runner cannot be registered after creation' do
+ let_it_be(:new_runner) { runner }
+
+ it 'returns :not_found' do
+ register
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'when user is not maintainer' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when runner can be registered after creation' do
+ let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) }
+
+ it 'returns :not_found' do
+ register
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ context 'when create_runner_workflow_for_namespace is disabled' do
+ let_it_be(:new_runner) { create(:ci_runner, :project, projects: [project], registration_type: :authenticated_user) }
+
+ before do
+ stub_feature_flags(create_runner_workflow_for_namespace: false)
+ end
+
+ context 'when user is maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns :not_found' do
+ register
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
describe '#update' do
it 'updates the runner and ticks the queue' do
new_desc = runner.description.swapcase
diff --git a/spec/factories/customer_relations/contacts.rb b/spec/factories/customer_relations/contacts.rb
index 1896510d362..6410e298bc3 100644
--- a/spec/factories/customer_relations/contacts.rb
+++ b/spec/factories/customer_relations/contacts.rb
@@ -8,10 +8,6 @@ FactoryBot.define do
last_name { generate(:name) }
email { generate(:email) }
- trait :with_organization do
- organization
- end
-
trait :inactive do
state { :inactive }
end
diff --git a/spec/factories/customer_relations/organizations.rb b/spec/factories/customer_relations/organizations.rb
index b6efd46f1a4..789099190ac 100644
--- a/spec/factories/customer_relations/organizations.rb
+++ b/spec/factories/customer_relations/organizations.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :organization, class: 'CustomerRelations::Organization' do
+ factory :crm_organization, class: 'CustomerRelations::Organization' do
group
name { generate(:name) }
diff --git a/spec/features/groups/crm/contacts/create_spec.rb b/spec/features/groups/crm/contacts/create_spec.rb
index 860cadd322d..aa05ef82a8b 100644
--- a/spec/features/groups/crm/contacts/create_spec.rb
+++ b/spec/features/groups/crm/contacts/create_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Create a CRM contact', :js, feature_category: :service_desk do
let(:user) { create(:user) }
let(:group) { create(:group, :crm_enabled) }
- let!(:organization) { create(:organization, group: group, name: 'GitLab') }
+ let!(:crm_organization) { create(:crm_organization, group: group, name: 'GitLab') }
before do
group.add_owner(user)
diff --git a/spec/features/nav/new_nav_invite_members_spec.rb b/spec/features/nav/new_nav_invite_members_spec.rb
new file mode 100644
index 00000000000..4c37d6b4760
--- /dev/null
+++ b/spec/features/nav/new_nav_invite_members_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'new navigation toggle', :js, feature_category: :navigation do
+ include Features::InviteMembersModalHelpers
+
+ let_it_be(:user) { create(:user, use_new_navigation: true) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when inside a group' do
+ let_it_be(:group) { create(:group).tap { |record| record.add_owner(user) } }
+
+ before do
+ visit group_path(group)
+ end
+
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
+ invite_members_from_menu
+
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{group.name} group")
+ end
+ end
+ end
+
+ context 'when inside a project' do
+ let_it_be(:project) { create(:project, :repository).tap { |record| record.add_owner(user) } }
+
+ before do
+ visit project_path(project)
+ end
+
+ it 'the add menu contains invite members dropdown option and opens invite modal' do
+ invite_members_from_menu
+
+ page.within invite_modal_selector do
+ expect(page).to have_content("You're inviting members to the #{project.name} project")
+ end
+ end
+ end
+
+ def invite_members_from_menu
+ page.find('[data-testid="new-menu-toggle"] button').click
+ click_button('Invite team members')
+ end
+end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index cab6aac42e6..54482d141c7 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -31,6 +31,16 @@ RSpec.describe 'Runners', feature_category: :runner_fleet do
expect(page).to have_link(s_('Runners|New project runner'), href: new_project_runner_path(project))
end
+
+ describe 'runner registration', :js do
+ before do
+ visit new_project_runner_path(project)
+ end
+
+ it_behaves_like 'creates runner and shows register page' do
+ let(:register_path_pattern) { register_project_runner_path(project, '.*') }
+ end
+ end
end
context 'when create_runner_workflow_for_namespace is disabled' do
diff --git a/spec/finders/crm/contacts_finder_spec.rb b/spec/finders/crm/contacts_finder_spec.rb
index 43dcced53fd..d0339ce2b18 100644
--- a/spec/finders/crm/contacts_finder_spec.rb
+++ b/spec/finders/crm/contacts_finder_spec.rb
@@ -148,7 +148,7 @@ RSpec.describe Crm::ContactsFinder do
:contact,
group: search_test_group,
email: "a@test.com",
- organization: create(:organization, name: "Company Z")
+ organization: create(:crm_organization, name: "Company Z")
)
end
@@ -157,7 +157,7 @@ RSpec.describe Crm::ContactsFinder do
:contact,
group: search_test_group,
email: "b@test.com",
- organization: create(:organization, name: "Company A")
+ organization: create(:crm_organization, name: "Company A")
)
end
diff --git a/spec/finders/crm/organizations_finder_spec.rb b/spec/finders/crm/organizations_finder_spec.rb
index c89ac3b1cb5..bc174f927a7 100644
--- a/spec/finders/crm/organizations_finder_spec.rb
+++ b/spec/finders/crm/organizations_finder_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:root_group) { create(:group, :crm_enabled) }
let_it_be(:group) { create(:group, parent: root_group) }
- let_it_be(:organization_1) { create(:organization, group: root_group) }
- let_it_be(:organization_2) { create(:organization, group: root_group) }
+ let_it_be(:crm_organization_1) { create(:crm_organization, group: root_group) }
+ let_it_be(:crm_organization_2) { create(:crm_organization, group: root_group) }
context 'when user does not have permissions to see organizations in the group' do
it 'returns an empty array' do
@@ -28,7 +28,7 @@ RSpec.describe Crm::OrganizationsFinder do
context 'when feature flag is enabled' do
it 'returns all group organizations' do
- expect(subject).to match_array([organization_1, organization_2])
+ expect(subject).to match_array([crm_organization_1, crm_organization_2])
end
end
end
@@ -46,7 +46,7 @@ RSpec.describe Crm::OrganizationsFinder do
context 'when customer relations feature is disabled for the group' do
let_it_be(:group) { create(:group) }
- let_it_be(:organization) { create(:organization, group: group) }
+ let_it_be(:crm_organization) { create(:crm_organization, group: group) }
before do
group.add_developer(user)
@@ -62,7 +62,7 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:search_test_a) do
create(
- :organization,
+ :crm_organization,
group: search_test_group,
name: "DEF",
description: "ghi_st",
@@ -72,7 +72,7 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:search_test_b) do
create(
- :organization,
+ :crm_organization,
group: search_test_group,
name: "ABC_st",
description: "JKL",
@@ -134,7 +134,7 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:sort_test_a) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "ABC",
description: "1"
@@ -143,7 +143,7 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:sort_test_b) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "DEF",
description: "2",
@@ -153,7 +153,7 @@ RSpec.describe Crm::OrganizationsFinder do
let_it_be(:sort_test_c) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "GHI",
default_rate: 20
@@ -186,8 +186,8 @@ RSpec.describe Crm::OrganizationsFinder do
describe '.counts_by_state' do
let_it_be(:group) { create(:group, :crm_enabled) }
- let_it_be(:active_organizations) { create_list(:organization, 3, group: group, state: :active) }
- let_it_be(:inactive_organizations) { create_list(:organization, 2, group: group, state: :inactive) }
+ let_it_be(:active_crm_organizations) { create_list(:crm_organization, 3, group: group, state: :active) }
+ let_it_be(:inactive_crm_organizations) { create_list(:crm_organization, 2, group: group, state: :inactive) }
before do
group.add_developer(user)
diff --git a/spec/finders/deployments_finder_spec.rb b/spec/finders/deployments_finder_spec.rb
index 90cd6283130..be7e9a84991 100644
--- a/spec/finders/deployments_finder_spec.rb
+++ b/spec/finders/deployments_finder_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe DeploymentsFinder do
it 'raises an error' do
expect { subject }.to raise_error(
described_class::InefficientQueryError,
- '`updated_at` filter and `updated_at` sorting must be paired')
+ '`updated_at` filter requires `updated_at` sort')
end
end
@@ -178,8 +178,8 @@ RSpec.describe DeploymentsFinder do
'iid' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
- 'updated_at' | 'asc' | described_class::InefficientQueryError
- 'updated_at' | 'desc' | described_class::InefficientQueryError
+ 'updated_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
+ 'updated_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
'finished_at' | 'asc' | described_class::InefficientQueryError
'finished_at' | 'desc' | described_class::InefficientQueryError
'invalid' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
diff --git a/spec/finders/issuables/crm_organization_filter_spec.rb b/spec/finders/issuables/crm_organization_filter_spec.rb
index 2a521dcf721..9a910091fd2 100644
--- a/spec/finders/issuables/crm_organization_filter_spec.rb
+++ b/spec/finders/issuables/crm_organization_filter_spec.rb
@@ -6,11 +6,11 @@ RSpec.describe Issuables::CrmOrganizationFilter do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
- let_it_be(:organization1) { create(:organization, group: group) }
- let_it_be(:organization2) { create(:organization, group: group) }
- let_it_be(:contact1) { create(:contact, group: group, organization: organization1) }
- let_it_be(:contact2) { create(:contact, group: group, organization: organization1) }
- let_it_be(:contact3) { create(:contact, group: group, organization: organization2) }
+ let_it_be(:crm_organization1) { create(:crm_organization, group: group) }
+ let_it_be(:crm_organization2) { create(:crm_organization, group: group) }
+ let_it_be(:contact1) { create(:contact, group: group, organization: crm_organization1) }
+ let_it_be(:contact2) { create(:contact, group: group, organization: crm_organization1) }
+ let_it_be(:contact3) { create(:contact, group: group, organization: crm_organization2) }
let_it_be(:contact1_issue) { create(:issue, project: project) }
let_it_be(:contact2_issue) { create(:issue, project: project) }
@@ -24,14 +24,14 @@ RSpec.describe Issuables::CrmOrganizationFilter do
end
describe 'when an organization has issues' do
- it 'returns all organization1 issues' do
- params = { crm_organization_id: organization1.id }
+ it 'returns all crm_organization1 issues' do
+ params = { crm_organization_id: crm_organization1.id }
expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact1_issue, contact2_issue)
end
- it 'returns all organization2 issues' do
- params = { crm_organization_id: organization2.id }
+ it 'returns all crm_organization2 issues' do
+ params = { crm_organization_id: crm_organization2.id }
expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact3_issue)
end
@@ -39,8 +39,8 @@ RSpec.describe Issuables::CrmOrganizationFilter do
describe 'when an organization has no issues' do
it 'returns no issues' do
- organization3 = create(:organization, group: group)
- params = { crm_organization_id: organization3.id }
+ crm_organization3 = create(:crm_organization, group: group)
+ params = { crm_organization_id: crm_organization3.id }
expect(described_class.new(params: params).filter(issues)).to be_empty
end
diff --git a/spec/frontend/behaviors/shortcuts/keybindings_spec.js b/spec/frontend/behaviors/shortcuts/keybindings_spec.js
index 1f7e1b24e78..65ef6a18864 100644
--- a/spec/frontend/behaviors/shortcuts/keybindings_spec.js
+++ b/spec/frontend/behaviors/shortcuts/keybindings_spec.js
@@ -7,7 +7,7 @@ import {
TOGGLE_PERFORMANCE_BAR,
HIDE_APPEARING_CONTENT,
LOCAL_STORAGE_KEY,
- WEB_IDE_COMMIT,
+ BOLD_TEXT,
} from '~/behaviors/shortcuts/keybindings';
describe('~/behaviors/shortcuts/keybindings', () => {
@@ -67,11 +67,11 @@ describe('~/behaviors/shortcuts/keybindings', () => {
const customization = ['mod+shift+c'];
beforeEach(() => {
- setupCustomizations(JSON.stringify({ [WEB_IDE_COMMIT.id]: customization }));
+ setupCustomizations(JSON.stringify({ [BOLD_TEXT.id]: customization }));
});
it('returns the default keybinding for the command', () => {
- expect(keysFor(WEB_IDE_COMMIT)).toEqual(['mod+enter']);
+ expect(keysFor(BOLD_TEXT)).toEqual(['mod+b']);
});
});
diff --git a/spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js b/spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js
index 6949108fb1f..14e36e74549 100644
--- a/spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js
+++ b/spec/frontend/ci/runner/project_new_runner_app/project_new_runner_app_spec.js
@@ -5,9 +5,16 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
import ProjectRunnerRunnerApp from '~/ci/runner/project_new_runner/project_new_runner_app.vue';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
-import { PROJECT_TYPE, DEFAULT_PLATFORM } from '~/ci/runner/constants';
+import {
+ PARAM_KEY_PLATFORM,
+ PROJECT_TYPE,
+ DEFAULT_PLATFORM,
+ WINDOWS_PLATFORM,
+} from '~/ci/runner/constants';
import RunnerCreateForm from '~/ci/runner/components/runner_create_form.vue';
+import { redirectTo } from '~/lib/utils/url_utility';
import { runnerCreateResult, mockRegistrationToken } from '../mock_data';
const mockProjectId = 'gid://gitlab/Project/72';
@@ -63,12 +70,31 @@ describe('ProjectRunnerRunnerApp', () => {
findRunnerCreateForm().vm.$emit('saved', mockCreatedRunner);
});
- it('shows an alert', () => {
- expect(createAlert).toHaveBeenCalledWith({
+ it('pushes an alert to be shown after redirection', () => {
+ expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
message: s__('Runners|Runner created.'),
variant: VARIANT_SUCCESS,
});
});
+
+ it('redirects to the registration page', () => {
+ const url = `${mockCreatedRunner.ephemeralRegisterUrl}?${PARAM_KEY_PLATFORM}=${DEFAULT_PLATFORM}`;
+
+ expect(redirectTo).toHaveBeenCalledWith(url);
+ });
+ });
+
+ describe('When another platform is selected and a runner is saved', () => {
+ beforeEach(() => {
+ findRunnerPlatformsRadioGroup().vm.$emit('input', WINDOWS_PLATFORM);
+ findRunnerCreateForm().vm.$emit('saved', mockCreatedRunner);
+ });
+
+ it('redirects to the registration page with the platform', () => {
+ const url = `${mockCreatedRunner.ephemeralRegisterUrl}?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`;
+
+ expect(redirectTo).toHaveBeenCalledWith(url);
+ });
});
describe('When runner fails to save', () => {
diff --git a/spec/frontend/ci/runner/project_register_runner_app/project_register_runner_app_spec.js b/spec/frontend/ci/runner/project_register_runner_app/project_register_runner_app_spec.js
new file mode 100644
index 00000000000..240fd82fb3b
--- /dev/null
+++ b/spec/frontend/ci/runner/project_register_runner_app/project_register_runner_app_spec.js
@@ -0,0 +1,120 @@
+import { nextTick } from 'vue';
+import { GlButton } from '@gitlab/ui';
+
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+
+import { updateHistory } from '~/lib/utils/url_utility';
+import { PARAM_KEY_PLATFORM, DEFAULT_PLATFORM, WINDOWS_PLATFORM } from '~/ci/runner/constants';
+import ProjectRegisterRunnerApp from '~/ci/runner/project_register_runner/project_register_runner_app.vue';
+import RegistrationInstructions from '~/ci/runner/components/registration/registration_instructions.vue';
+import PlatformsDrawer from '~/ci/runner/components/registration/platforms_drawer.vue';
+import { runnerForRegistration } from '../mock_data';
+
+const mockRunnerId = runnerForRegistration.data.runner.id;
+const mockRunnersPath = '/group1/project1/-/settings/ci_cd';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ updateHistory: jest.fn(),
+}));
+
+describe('ProjectRegisterRunnerApp', () => {
+ let wrapper;
+
+ const findRegistrationInstructions = () => wrapper.findComponent(RegistrationInstructions);
+ const findPlatformsDrawer = () => wrapper.findComponent(PlatformsDrawer);
+ const findBtn = () => wrapper.findComponent(GlButton);
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(ProjectRegisterRunnerApp, {
+ propsData: {
+ runnerId: mockRunnerId,
+ runnersPath: mockRunnersPath,
+ },
+ });
+ };
+
+ describe('When showing runner details', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('when runner token is available', () => {
+ it('shows registration instructions', () => {
+ expect(findRegistrationInstructions().props()).toEqual({
+ platform: DEFAULT_PLATFORM,
+ runnerId: mockRunnerId,
+ });
+ });
+
+ it('configures platform drawer', () => {
+ expect(findPlatformsDrawer().props()).toEqual({
+ open: false,
+ platform: DEFAULT_PLATFORM,
+ });
+ });
+
+ it('shows runner list button', () => {
+ expect(findBtn().attributes('href')).toBe(mockRunnersPath);
+ expect(findBtn().props('variant')).toBe('confirm');
+ });
+ });
+ });
+
+ describe('When another platform has been selected', () => {
+ beforeEach(() => {
+ setWindowLocation(`?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`);
+
+ createComponent();
+ });
+
+ it('shows registration instructions for the platform', () => {
+ expect(findRegistrationInstructions().props('platform')).toBe(WINDOWS_PLATFORM);
+ });
+ });
+
+ describe('When opening install instructions', () => {
+ beforeEach(() => {
+ createComponent();
+
+ findRegistrationInstructions().vm.$emit('toggleDrawer');
+ });
+
+ it('opens platform drawer', () => {
+ expect(findPlatformsDrawer().props('open')).toBe(true);
+ });
+
+ it('closes platform drawer', async () => {
+ findRegistrationInstructions().vm.$emit('toggleDrawer');
+ await nextTick();
+
+ expect(findPlatformsDrawer().props('open')).toBe(false);
+ });
+
+ it('closes platform drawer from drawer', async () => {
+ findPlatformsDrawer().vm.$emit('close');
+ await nextTick();
+
+ expect(findPlatformsDrawer().props('open')).toBe(false);
+ });
+
+ describe('when selecting a platform', () => {
+ beforeEach(() => {
+ findPlatformsDrawer().vm.$emit('selectPlatform', WINDOWS_PLATFORM);
+ });
+
+ it('updates the url', () => {
+ expect(updateHistory).toHaveBeenCalledTimes(1);
+ expect(updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?${PARAM_KEY_PLATFORM}=${WINDOWS_PLATFORM}`,
+ });
+ });
+
+ it('updates the registration instructions', () => {
+ expect(findRegistrationInstructions().props('platform')).toBe(WINDOWS_PLATFORM);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap b/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
index 788e80de3f6..9c58090344d 100644
--- a/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
+++ b/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
@@ -58,7 +58,7 @@ exports[`Comment templates list item component renders list item 1`] = `
</button>
<div
- class="gl-new-dropdown-panel"
+ class="gl-new-dropdown-panel gl-w-31"
data-testid="base-dropdown-menu"
id="base-dropdown-7"
>
diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js
index 8d91ffe5ffc..22d1fefd657 100644
--- a/spec/frontend/environments/graphql/mock_data.js
+++ b/spec/frontend/environments/graphql/mock_data.js
@@ -812,3 +812,56 @@ const succeededPod = { status: { phase: 'Succeeded' } };
const failedPod = { status: { phase: 'Failed' } };
export const k8sPodsMock = [runningPod, runningPod, pendingPod, succeededPod, failedPod, failedPod];
+
+export const k8sServicesMock = [
+ {
+ metadata: {
+ name: 'my-first-service',
+ namespace: 'default',
+ creationTimestamp: new Date(),
+ },
+ spec: {
+ ports: [
+ {
+ name: 'https',
+ protocol: 'TCP',
+ port: 443,
+ targetPort: 8443,
+ },
+ ],
+ clusterIP: '10.96.0.1',
+ externalIP: '-',
+ type: 'ClusterIP',
+ },
+ },
+ {
+ metadata: {
+ name: 'my-second-service',
+ namespace: 'default',
+ creationTimestamp: '2020-07-03T14:06:04Z',
+ },
+ spec: {
+ ports: [
+ {
+ name: 'http',
+ protocol: 'TCP',
+ appProtocol: 'http',
+ port: 80,
+ targetPort: 'http',
+ nodePort: 31989,
+ },
+ {
+ name: 'https',
+ protocol: 'TCP',
+ appProtocol: 'https',
+ port: 443,
+ targetPort: 'https',
+ nodePort: 32679,
+ },
+ ],
+ clusterIP: '10.105.219.238',
+ externalIP: '-',
+ type: 'NodePort',
+ },
+ },
+];
diff --git a/spec/frontend/environments/graphql/resolvers_spec.js b/spec/frontend/environments/graphql/resolvers_spec.js
index 94bed8d93ab..6300ecd62a7 100644
--- a/spec/frontend/environments/graphql/resolvers_spec.js
+++ b/spec/frontend/environments/graphql/resolvers_spec.js
@@ -19,6 +19,7 @@ import {
folder,
resolvedFolder,
k8sPodsMock,
+ k8sServicesMock,
} from './mock_data';
const ENDPOINT = `${TEST_HOST}/environments`;
@@ -29,6 +30,13 @@ describe('~/frontend/environments/graphql/resolvers', () => {
let mockApollo;
let localState;
+ const configuration = {
+ basePath: 'kas-proxy/',
+ baseOptions: {
+ headers: { 'GitLab-Agent-Id': '1' },
+ },
+ };
+
beforeEach(() => {
mockResolvers = resolvers(ENDPOINT);
mock = new MockAdapter(axios);
@@ -147,12 +155,6 @@ describe('~/frontend/environments/graphql/resolvers', () => {
});
describe('k8sPods', () => {
const namespace = 'default';
- const configuration = {
- basePath: 'kas-proxy/',
- baseOptions: {
- headers: { 'GitLab-Agent-Id': '1' },
- },
- };
const mockPodsListFn = jest.fn().mockImplementation(() => {
return Promise.resolve({
@@ -200,6 +202,38 @@ describe('~/frontend/environments/graphql/resolvers', () => {
);
});
});
+ describe('k8sServices', () => {
+ const mockServicesListFn = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ data: {
+ items: k8sServicesMock,
+ },
+ });
+ });
+
+ beforeEach(() => {
+ jest
+ .spyOn(CoreV1Api.prototype, 'listCoreV1ServiceForAllNamespaces')
+ .mockImplementation(mockServicesListFn);
+ });
+
+ it('should request services from the cluster_client library', async () => {
+ const services = await mockResolvers.Query.k8sServices(null, { configuration });
+
+ expect(mockServicesListFn).toHaveBeenCalled();
+
+ expect(services).toEqual(k8sServicesMock);
+ });
+ it('should throw an error if the API call fails', async () => {
+ jest
+ .spyOn(CoreV1Api.prototype, 'listCoreV1ServiceForAllNamespaces')
+ .mockRejectedValue(new Error('API error'));
+
+ await expect(mockResolvers.Query.k8sServices(null, { configuration })).rejects.toThrow(
+ 'API error',
+ );
+ });
+ });
describe('stopEnvironmentREST', () => {
it('should post to the stop environment path', async () => {
mock.onPost(ENDPOINT).reply(HTTP_STATUS_OK);
diff --git a/spec/frontend/environments/kubernetes_overview_spec.js b/spec/frontend/environments/kubernetes_overview_spec.js
index 1912fd4a82b..6942285261a 100644
--- a/spec/frontend/environments/kubernetes_overview_spec.js
+++ b/spec/frontend/environments/kubernetes_overview_spec.js
@@ -4,6 +4,7 @@ import { GlCollapse, GlButton, GlAlert } from '@gitlab/ui';
import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
import KubernetesAgentInfo from '~/environments/components/kubernetes_agent_info.vue';
import KubernetesPods from '~/environments/components/kubernetes_pods.vue';
+import KubernetesTabs from '~/environments/components/kubernetes_tabs.vue';
import { agent } from './graphql/mock_data';
import { mockKasTunnelUrl } from './mock_data';
@@ -32,6 +33,7 @@ describe('~/environments/components/kubernetes_overview.vue', () => {
const findCollapseButton = () => wrapper.findComponent(GlButton);
const findAgentInfo = () => wrapper.findComponent(KubernetesAgentInfo);
const findKubernetesPods = () => wrapper.findComponent(KubernetesPods);
+ const findKubernetesTabs = () => wrapper.findComponent(KubernetesTabs);
const findAlert = () => wrapper.findComponent(GlAlert);
const createWrapper = () => {
@@ -102,6 +104,12 @@ describe('~/environments/components/kubernetes_overview.vue', () => {
configuration,
});
});
+
+ it('renders kubernetes tabs', () => {
+ expect(findKubernetesTabs().props()).toEqual({
+ configuration,
+ });
+ });
});
describe('on cluster error', () => {
diff --git a/spec/frontend/environments/kubernetes_tabs_spec.js b/spec/frontend/environments/kubernetes_tabs_spec.js
new file mode 100644
index 00000000000..550c7e8b953
--- /dev/null
+++ b/spec/frontend/environments/kubernetes_tabs_spec.js
@@ -0,0 +1,158 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon, GlTabs, GlTab, GlTable, GlPagination } from '@gitlab/ui';
+import { stubComponent } from 'helpers/stub_component';
+import { useFakeDate } from 'helpers/fake_date';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import KubernetesTabs from '~/environments/components/kubernetes_tabs.vue';
+import { SERVICES_LIMIT_PER_PAGE } from '~/environments/constants';
+import { mockKasTunnelUrl } from './mock_data';
+import { k8sServicesMock } from './graphql/mock_data';
+
+Vue.use(VueApollo);
+
+describe('~/environments/components/kubernetes_tabs.vue', () => {
+ let wrapper;
+
+ const configuration = {
+ basePath: mockKasTunnelUrl,
+ baseOptions: {
+ headers: { 'GitLab-Agent-Id': '1' },
+ },
+ };
+
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findTabs = () => wrapper.findComponent(GlTabs);
+ const findTab = (at) => wrapper.findAllComponents(GlTab).at(at);
+ const findTable = () => wrapper.findComponent(GlTable);
+ const findPagination = () => wrapper.findComponent(GlPagination);
+
+ const createApolloProvider = () => {
+ const mockResolvers = {
+ Query: {
+ k8sServices: jest.fn().mockReturnValue(k8sServicesMock),
+ },
+ };
+
+ return createMockApollo([], mockResolvers);
+ };
+
+ const createWrapper = (apolloProvider = createApolloProvider()) => {
+ wrapper = shallowMount(KubernetesTabs, {
+ propsData: { configuration },
+ apolloProvider,
+ stubs: {
+ GlTab,
+ GlTable: stubComponent(GlTable, {
+ props: ['items', 'per-page'],
+ }),
+ },
+ });
+ };
+
+ describe('mounted', () => {
+ it('shows tabs', () => {
+ createWrapper();
+
+ expect(findTabs().exists()).toBe(true);
+ });
+
+ it('renders services tab', () => {
+ createWrapper();
+
+ expect(findTab(0).text()).toMatchInterpolatedText(`${KubernetesTabs.i18n.servicesTitle} 0`);
+ });
+ });
+
+ describe('services tab', () => {
+ useFakeDate(2020, 6, 6);
+ it('shows the loading icon', () => {
+ createWrapper();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ describe('when services data is loaded', () => {
+ beforeEach(async () => {
+ createWrapper();
+ await waitForPromises();
+ });
+
+ it('hides the loading icon when the list of services loaded', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('renders services table when gets services data', () => {
+ expect(findTable().props('perPage')).toBe(SERVICES_LIMIT_PER_PAGE);
+ expect(findTable().props('items')).toMatchObject([
+ {
+ name: 'my-first-service',
+ namespace: 'default',
+ type: 'ClusterIP',
+ clusterIP: '10.96.0.1',
+ externalIP: '-',
+ ports: '443/TCP',
+ age: '0s',
+ },
+ {
+ name: 'my-second-service',
+ namespace: 'default',
+ type: 'NodePort',
+ clusterIP: '10.105.219.238',
+ externalIP: '-',
+ ports: '80:31989/TCP, 443:32679/TCP',
+ age: '2d',
+ },
+ ]);
+ });
+
+ it("doesn't render pagination when services are less then SERVICES_LIMIT_PER_PAGE", async () => {
+ createWrapper();
+ await waitForPromises();
+
+ expect(findPagination().exists()).toBe(false);
+ });
+ });
+
+ it('shows pagination when services are more then SERVICES_LIMIT_PER_PAGE', async () => {
+ const createApolloProviderWithPagination = () => {
+ const mockResolvers = {
+ Query: {
+ k8sServices: jest
+ .fn()
+ .mockReturnValue(
+ Array.from({ length: 6 }, () => k8sServicesMock).flatMap((array) => array),
+ ),
+ },
+ };
+
+ return createMockApollo([], mockResolvers);
+ };
+
+ createWrapper(createApolloProviderWithPagination());
+ await waitForPromises();
+
+ expect(findPagination().exists()).toBe(true);
+ });
+
+ it('emits an error message when gets an error from the cluster_client API', async () => {
+ const error = new Error('Error from the cluster_client API');
+ const createErroredApolloProvider = () => {
+ const mockResolvers = {
+ Query: {
+ k8sServices: jest.fn().mockRejectedValueOnce(error),
+ },
+ };
+
+ return createMockApollo([], mockResolvers);
+ };
+
+ createWrapper(createErroredApolloProvider());
+ await waitForPromises();
+
+ expect(wrapper.emitted('cluster-error')).toEqual([[error]]);
+ });
+ });
+});
diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
index cdb6182e2ae..58c40a49b3c 100644
--- a/spec/frontend/invite_members/components/invite_members_trigger_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlLink, GlDropdownItem } from '@gitlab/ui';
+import { GlButton, GlLink, GlDropdownItem, GlDisclosureDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import eventHub from '~/invite_members/event_hub';
@@ -7,6 +7,7 @@ import {
TRIGGER_DEFAULT_QA_SELECTOR,
TRIGGER_ELEMENT_WITH_EMOJI,
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
+ TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN,
} from '~/invite_members/constants';
import { GlEmoji } from '../mock_data/member_modal';
@@ -23,6 +24,7 @@ const triggerComponent = {
anchor: GlLink,
'text-emoji': GlLink,
'dropdown-text-emoji': GlDropdownItem,
+ 'dropdown-text': GlButton,
};
const createComponent = (props = {}) => {
@@ -34,6 +36,8 @@ const createComponent = (props = {}) => {
},
stubs: {
GlEmoji,
+ GlDisclosureDropdownItem,
+ GlButton,
},
});
};
@@ -116,3 +120,22 @@ describe('dropdown item with emoji', () => {
expect(findEmoji().attributes('data-name')).toBe('shaking_hands');
});
});
+
+describe('disclosure dropdown item', () => {
+ const findTrigger = () => wrapper.findComponent(GlDisclosureDropdownItem);
+
+ beforeEach(() => {
+ createComponent({ triggerElement: TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN });
+ });
+
+ it('renders a trigger button', () => {
+ expect(findTrigger().exists()).toBe(true);
+ expect(findTrigger().text()).toBe(displayText);
+ });
+
+ it('emits modalOpened which clicked', () => {
+ findTrigger().vm.$emit('action');
+
+ expect(wrapper.emitted('modal-opened')).toHaveLength(1);
+ });
+});
diff --git a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
index 0187970efdc..c152a5ef9a8 100644
--- a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -145,7 +145,7 @@ describe('IssuesDashboardApp component', () => {
closed: 2,
all: 3,
},
- tabs: IssuesDashboardApp.IssuableListTabs,
+ tabs: IssuesDashboardApp.issuableListTabs,
urlParams: {
sort: urlSortParams[CREATED_DESC],
state: STATUS_OPEN,
diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js
index 15dde76f49b..61dbc9afeeb 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -29,7 +29,7 @@ import { STATUS_ALL, STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { IssuableListTabs } from '~/vue_shared/issuable/list/constants';
+import { issuableListTabs } from '~/vue_shared/issuable/list/constants';
import EmptyStateWithAnyIssues from '~/issues/list/components/empty_state_with_any_issues.vue';
import EmptyStateWithoutAnyIssues from '~/issues/list/components/empty_state_without_any_issues.vue';
import IssuesListApp from '~/issues/list/components/issues_list_app.vue';
@@ -213,7 +213,7 @@ describe('CE IssuesListApp component', () => {
}),
initialSortBy: CREATED_DESC,
issuables: getIssuesQueryResponse.data.project.issues.nodes,
- tabs: IssuableListTabs,
+ tabs: issuableListTabs,
currentTab: STATUS_OPEN,
tabCounts: {
opened: 1,
diff --git a/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js b/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js
index 0243cbeb7bf..f2a9e3ad9ee 100644
--- a/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js
+++ b/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js
@@ -1,4 +1,4 @@
-import { GlModal, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlModal, GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
@@ -12,8 +12,8 @@ describe('DeleteButton', () => {
let wrapper;
const findModal = () => wrapper.findComponent(GlModal);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDeleteButton = () => wrapper.findComponent(GlDropdownItem);
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findDeleteButton = () => wrapper.findComponent(GlDisclosureDropdownItem);
const findForm = () => wrapper.find('form');
const findModalText = () => wrapper.findByText(MODAL_BODY);
diff --git a/spec/frontend/super_sidebar/components/create_menu_spec.js b/spec/frontend/super_sidebar/components/create_menu_spec.js
index e05b5d30e69..456085e23da 100644
--- a/spec/frontend/super_sidebar/components/create_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/create_menu_spec.js
@@ -1,6 +1,13 @@
import { nextTick } from 'vue';
-import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
+import {
+ GlDisclosureDropdown,
+ GlTooltip,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+} from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
import { createNewMenuGroups } from '../mock_data';
@@ -9,13 +16,24 @@ describe('CreateMenu component', () => {
let wrapper;
const findGlDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findGlDisclosureDropdownGroups = () => wrapper.findAllComponents(GlDisclosureDropdownGroup);
+ const findGlDisclosureDropdownItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
+ const findInviteMembersTrigger = () => wrapper.findComponent(InviteMembersTrigger);
const findGlTooltip = () => wrapper.findComponent(GlTooltip);
+ const closeAndFocusMock = jest.fn();
+
const createWrapper = () => {
wrapper = shallowMountExtended(CreateMenu, {
propsData: {
groups: createNewMenuGroups,
},
+ stubs: {
+ InviteMembersTrigger,
+ GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
+ methods: { closeAndFocus: closeAndFocusMock },
+ }),
+ },
});
};
@@ -35,9 +53,25 @@ describe('CreateMenu component', () => {
it("sets the toggle's label", () => {
expect(findGlDisclosureDropdown().props('toggleText')).toBe(__('Create new...'));
});
+ it('has correct amount of dropdown groups', () => {
+ const items = findGlDisclosureDropdownGroups();
+
+ expect(items.exists()).toBe(true);
+ expect(items).toHaveLength(createNewMenuGroups.length);
+ });
+
+ it('has correct amount of dropdown items', () => {
+ const items = findGlDisclosureDropdownItems();
+ const numberOfMenuItems = createNewMenuGroups
+ .map((group) => group.items.length)
+ .reduce((a, b) => a + b);
- it('passes the groups to the disclosure dropdown', () => {
- expect(findGlDisclosureDropdown().props('items')).toBe(createNewMenuGroups);
+ expect(items.exists()).toBe(true);
+ expect(items).toHaveLength(numberOfMenuItems);
+ });
+
+ it('renders the invite member trigger', () => {
+ expect(findInviteMembersTrigger().exists()).toBe(true);
});
it("sets the toggle ID and tooltip's target", () => {
@@ -59,5 +93,10 @@ describe('CreateMenu component', () => {
expect(findGlTooltip().exists()).toBe(true);
});
+
+ it('closes the dropdown when invite members modal is opened', () => {
+ findInviteMembersTrigger().vm.$emit('modal-opened');
+ expect(closeAndFocusMock).toHaveBeenCalled();
+ });
});
});
diff --git a/spec/frontend/super_sidebar/components/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js
index aa94ca301db..b441c5f531d 100644
--- a/spec/frontend/super_sidebar/components/help_center_spec.js
+++ b/spec/frontend/super_sidebar/components/help_center_spec.js
@@ -7,6 +7,7 @@ import { helpPagePath } from '~/helpers/help_page_helper';
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
+import { helpCenterState } from '~/super_sidebar/constants';
import { mockTracking } from 'helpers/tracking_helper';
import { sidebarData } from '../mock_data';
@@ -99,9 +100,10 @@ describe('HelpCenter component', () => {
describe('with show_tanuki_bot true', () => {
beforeEach(() => {
createWrapper({ ...sidebarData, show_tanuki_bot: true });
+ jest.spyOn(wrapper.vm.$refs.dropdown, 'close');
});
- it('shows Ask the Tanuki Bot with the help items', () => {
+ it('shows Ask the Tanuki Bot with the help items via Portal', () => {
expect(findDropdownGroup(0).props('group').items).toEqual([
expect.objectContaining({
icon: 'tanuki',
@@ -111,6 +113,20 @@ describe('HelpCenter component', () => {
...DEFAULT_HELP_ITEMS,
]);
});
+
+ describe('when Ask the Tanuki Bot button is clicked', () => {
+ beforeEach(() => {
+ findButton('Ask the Tanuki Bot').click();
+ });
+
+ it('closes the dropdown', () => {
+ expect(wrapper.vm.$refs.dropdown.close).toHaveBeenCalled();
+ });
+
+ it('sets helpCenterState.showTanukiBotChatDrawer to true', () => {
+ expect(helpCenterState.showTanukiBotChatDrawer).toBe(true);
+ });
+ });
});
describe('with Gitlab version check feature enabled', () => {
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index 0c9449d98a9..234eb7c315c 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -18,7 +18,7 @@ export const createNewMenuGroups = [
},
{
text: 'Invite members',
- href: '/groups/gitlab-org/-/group_members',
+ component: 'invite_members',
},
],
},
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
index 4bf7d0c57a3..1d78f35615a 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js
@@ -14,7 +14,6 @@ import WorkItemLinkChild from '~/work_items/components/work_item_links/work_item
import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
import { FORM_TYPES } from '~/work_items/constants';
-import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import changeWorkItemParentMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import getWorkItemLinksQuery from '~/work_items/graphql/work_item_links.query.graphql';
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
@@ -24,8 +23,8 @@ import {
workItemHierarchyEmptyResponse,
workItemHierarchyNoUpdatePermissionResponse,
changeWorkItemParentMutationResponse,
+ workItemByIidResponseFactory,
workItemQueryResponse,
- projectWorkItemResponse,
mockWorkItemCommentNote,
} from '../../mock_data';
@@ -46,9 +45,7 @@ describe('WorkItemLinks', () => {
const mutationChangeParentHandler = jest
.fn()
.mockResolvedValue(changeWorkItemParentMutationResponse);
-
- const childWorkItemQueryHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
- const childWorkItemByIidHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
+ const childWorkItemByIidHandler = jest.fn().mockResolvedValue(workItemByIidResponseFactory());
const createComponent = async ({
data = {},
@@ -61,7 +58,6 @@ describe('WorkItemLinks', () => {
[
[getWorkItemLinksQuery, fetchHandler],
[changeWorkItemParentMutation, mutationHandler],
- [workItemQuery, childWorkItemQueryHandler],
[issueDetailsQuery, issueDetailsQueryHandler],
[workItemByIidQuery, childWorkItemByIidHandler],
],
@@ -308,18 +304,10 @@ describe('WorkItemLinks', () => {
expect(childWorkItemByIidHandler).not.toHaveBeenCalled();
});
-
- it('does not fetch work item by id if link is hovered for 250+ ms', async () => {
- firstChild.vm.$emit('mouseover', firstChild.vm.childItem.id);
- jest.advanceTimersByTime(DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
- await waitForPromises();
-
- expect(childWorkItemQueryHandler).not.toHaveBeenCalled();
- });
});
- it('starts prefetching work item by iid if URL contains work item id', async () => {
- setWindowLocation('?work_item_iid=5&iid_path=true');
+ it('starts prefetching work item by iid if URL contains work_item_iid query parameter', async () => {
+ setWindowLocation('?work_item_iid=5');
await createComponent();
expect(childWorkItemByIidHandler).toHaveBeenCalledWith({
@@ -329,7 +317,7 @@ describe('WorkItemLinks', () => {
});
it('does not open the modal if work item iid URL parameter is not found in child items', async () => {
- setWindowLocation('?work_item_iid=555&iid_path=true');
+ setWindowLocation('?work_item_iid=555');
await createComponent();
expect(showModal).not.toHaveBeenCalled();
@@ -337,7 +325,7 @@ describe('WorkItemLinks', () => {
});
it('opens the modal if work item iid URL parameter is found in child items', async () => {
- setWindowLocation('?work_item_iid=2&iid_path=true');
+ setWindowLocation('?work_item_iid=2');
await createComponent();
expect(showModal).toHaveBeenCalled();
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_tree_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_tree_spec.js
index ab69ba7ee1b..f6b70d0161a 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_tree_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_tree_spec.js
@@ -4,11 +4,11 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import WorkItemTree from '~/work_items/components/work_item_links/work_item_tree.vue';
import WorkItemLinksForm from '~/work_items/components/work_item_links/work_item_links_form.vue';
import WorkItemLinkChild from '~/work_items/components/work_item_links/work_item_link_child.vue';
import OkrActionsSplitButton from '~/work_items/components/work_item_links/okr_actions_split_button.vue';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
@@ -17,12 +17,13 @@ import {
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
WORK_ITEM_TYPE_ENUM_KEY_RESULT,
} from '~/work_items/constants';
-import { childrenWorkItems, projectWorkItemResponse } from '../../mock_data';
+import { childrenWorkItems, workItemByIidResponseFactory } from '../../mock_data';
describe('WorkItemTree', () => {
- let getWorkItemQueryHandler;
let wrapper;
+ const getWorkItemQueryHandler = jest.fn().mockResolvedValue(workItemByIidResponseFactory());
+
const findEmptyState = () => wrapper.findByTestId('tree-empty');
const findToggleFormSplitButton = () => wrapper.findComponent(OkrActionsSplitButton);
const findForm = () => wrapper.findComponent(WorkItemLinksForm);
@@ -35,13 +36,9 @@ describe('WorkItemTree', () => {
parentWorkItemType = 'Objective',
confidential = false,
children = childrenWorkItems,
- apolloProvider = null,
} = {}) => {
- getWorkItemQueryHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
-
wrapper = shallowMountExtended(WorkItemTree, {
- apolloProvider:
- apolloProvider || createMockApollo([[workItemByIidQuery, getWorkItemQueryHandler]]),
+ apolloProvider: createMockApollo([[workItemByIidQuery, getWorkItemQueryHandler]]),
propsData: {
workItemType,
parentWorkItemType,
diff --git a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
index f2bbf0949fb..3ee898c2079 100644
--- a/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
+++ b/spec/graphql/mutations/customer_relations/contacts/create_spec.rb
@@ -57,10 +57,10 @@ RSpec.describe Mutations::CustomerRelations::Contacts::Create do
end
end
- context 'when attaching to an organization' do
+ context 'when attaching to an crm_organization' do
context 'when all ok' do
before do
- organization = create(:organization, group: group)
+ organization = create(:crm_organization, group: group)
valid_params[:organization_id] = organization.to_global_id
end
@@ -69,7 +69,7 @@ RSpec.describe Mutations::CustomerRelations::Contacts::Create do
end
end
- context 'when organization does not exist' do
+ context 'when crm_organization does not exist' do
before do
valid_params[:organization_id] = global_id_of(model_name: 'CustomerRelations::Organization', id: non_existing_record_id)
end
@@ -79,10 +79,10 @@ RSpec.describe Mutations::CustomerRelations::Contacts::Create do
end
end
- context 'when organzation belongs to a different group' do
+ context 'when crm_organzation belongs to a different group' do
before do
- organization = create(:organization)
- valid_params[:organization_id] = organization.to_global_id
+ crm_organization = create(:crm_organization)
+ valid_params[:organization_id] = crm_organization.to_global_id
end
it 'returns the relevant error' do
diff --git a/spec/graphql/mutations/customer_relations/organizations/create_spec.rb b/spec/graphql/mutations/customer_relations/organizations/create_spec.rb
index ffc9632350a..cf1ff2d5653 100644
--- a/spec/graphql/mutations/customer_relations/organizations/create_spec.rb
+++ b/spec/graphql/mutations/customer_relations/organizations/create_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Create do
let_it_be(:group) { create(:group, :crm_enabled) }
let(:valid_params) do
- attributes_for(:organization,
+ attributes_for(:crm_organization,
group: group,
description: 'This company is super important!',
default_rate: 1_000
diff --git a/spec/graphql/mutations/customer_relations/organizations/update_spec.rb b/spec/graphql/mutations/customer_relations/organizations/update_spec.rb
index f0f37ee9c47..2fad320b497 100644
--- a/spec/graphql/mutations/customer_relations/organizations/update_spec.rb
+++ b/spec/graphql/mutations/customer_relations/organizations/update_spec.rb
@@ -10,10 +10,10 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Update do
let(:default_rate) { 1000.to_f }
let(:description) { 'VIP' }
let(:does_not_exist_or_no_permission) { Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR }
- let(:organization) { create(:organization, group: group) }
+ let(:crm_organization) { create(:crm_organization, group: group) }
let(:attributes) do
{
- id: organization.to_global_id,
+ id: crm_organization.to_global_id,
name: name,
default_rate: default_rate,
description: description
@@ -27,7 +27,7 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Update do
)
end
- context 'when the user does not have permission to update an organization' do
+ context 'when the user does not have permission to update an crm_organization' do
before do
group.add_reporter(user)
end
@@ -38,7 +38,7 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Update do
end
end
- context 'when the organization does not exist' do
+ context 'when the crm_organization does not exist' do
it 'raises an error' do
attributes[:id] = "gid://gitlab/CustomerRelations::Organization/#{non_existing_record_id}"
@@ -47,12 +47,12 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Update do
end
end
- context 'when the user has permission to update an organization' do
+ context 'when the user has permission to update an crm_organization' do
before_all do
group.add_developer(user)
end
- it 'updates the organization with correct values' do
+ it 'updates the crm_organization with correct values' do
expect(resolve_mutation[:organization]).to have_attributes(attributes)
end
diff --git a/spec/graphql/resolvers/crm/contacts_resolver_spec.rb b/spec/graphql/resolvers/crm/contacts_resolver_spec.rb
index c7c2d11e114..1a53f42633f 100644
--- a/spec/graphql/resolvers/crm/contacts_resolver_spec.rb
+++ b/spec/graphql/resolvers/crm/contacts_resolver_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Resolvers::Crm::ContactsResolver do
last_name: "DEF",
email: "ghi@test.com",
description: "LMNO",
- organization: create(:organization, group: group),
+ organization: create(:crm_organization, group: group),
state: "inactive"
)
end
diff --git a/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb b/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb
index c6ad4beeee0..f6c2040b7d0 100644
--- a/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb
+++ b/spec/graphql/resolvers/crm/organization_state_counts_resolver_spec.rb
@@ -9,10 +9,10 @@ RSpec.describe Resolvers::Crm::OrganizationStateCountsResolver do
let_it_be(:group) { create(:group, :crm_enabled) }
before_all do
- create(:organization, group: group, name: "ABC Corp")
- create(:organization, group: group, name: "123 Corp", state: 'inactive')
- create_list(:organization, 3, group: group)
- create_list(:organization, 2, group: group, state: 'inactive')
+ create(:crm_organization, group: group, name: "ABC Corp")
+ create(:crm_organization, group: group, name: "123 Corp", state: 'inactive')
+ create_list(:crm_organization, 3, group: group)
+ create_list(:crm_organization, 2, group: group, state: 'inactive')
end
describe '#resolve' do
@@ -36,7 +36,7 @@ RSpec.describe Resolvers::Crm::OrganizationStateCountsResolver do
context 'with a group' do
context 'when no filter is provided' do
- it 'returns the count of all organizations' do
+ it 'returns the count of all crm_organizations' do
counts = resolve_counts(group)
expect(counts['active']).to eq(4)
expect(counts['inactive']).to eq(3)
diff --git a/spec/graphql/resolvers/crm/organizations_resolver_spec.rb b/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
index d5980bf3c41..edc1986799a 100644
--- a/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
+++ b/spec/graphql/resolvers/crm/organizations_resolver_spec.rb
@@ -8,18 +8,18 @@ RSpec.describe Resolvers::Crm::OrganizationsResolver do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :crm_enabled) }
- let_it_be(:organization_a) do
+ let_it_be(:crm_organization_a) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "ABC",
state: "inactive"
)
end
- let_it_be(:organization_b) do
+ let_it_be(:crm_organization_b) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "DEF",
state: "active"
@@ -28,23 +28,23 @@ RSpec.describe Resolvers::Crm::OrganizationsResolver do
describe '#resolve' do
context 'with unauthorized user' do
- it 'does not rise an error and returns no organizations' do
+ it 'does not rise an error and returns no crm_organizations' do
expect { resolve_organizations(group) }.not_to raise_error
expect(resolve_organizations(group)).to be_empty
end
end
context 'with authorized user' do
- it 'does not rise an error and returns all organizations in the correct order' do
+ it 'does not rise an error and returns all crm_organizations in the correct order' do
group.add_reporter(user)
expect { resolve_organizations(group) }.not_to raise_error
- expect(resolve_organizations(group)).to eq([organization_a, organization_b])
+ expect(resolve_organizations(group)).to eq([crm_organization_a, crm_organization_b])
end
end
context 'without parent' do
- it 'returns no organizations' do
+ it 'returns no crm_organizations' do
expect(resolve_organizations(nil)).to be_empty
end
end
@@ -55,40 +55,42 @@ RSpec.describe Resolvers::Crm::OrganizationsResolver do
end
context 'when no filter is provided' do
- it 'returns all the organizations in the default order' do
- expect(resolve_organizations(group)).to eq([organization_a, organization_b])
+ it 'returns all the crm_organizations in the default order' do
+ expect(resolve_organizations(group)).to eq([crm_organization_a, crm_organization_b])
end
end
context 'when a sort is provided' do
- it 'returns all the organizations in the correct order' do
- expect(resolve_organizations(group, { sort: 'NAME_DESC' })).to eq([organization_b, organization_a])
+ it 'returns all the crm_organizations in the correct order' do
+ expect(resolve_organizations(group, { sort: 'NAME_DESC' })).to eq([crm_organization_b, crm_organization_a])
end
end
context 'when filtering for all states' do
- it 'returns all the organizations' do
- expect(resolve_organizations(group, { state: 'all' })).to contain_exactly(organization_a, organization_b)
+ it 'returns all the crm_organizations' do
+ expect(resolve_organizations(group, { state: 'all' })).to contain_exactly(
+ crm_organization_a, crm_organization_b
+ )
end
end
context 'when search term is provided' do
- it 'returns the correct organizations' do
- expect(resolve_organizations(group, { search: "def" })).to contain_exactly(organization_b)
+ it 'returns the correct crm_organizations' do
+ expect(resolve_organizations(group, { search: "def" })).to contain_exactly(crm_organization_b)
end
end
context 'when state is provided' do
- it 'returns the correct organizations' do
- expect(resolve_organizations(group, { state: :inactive })).to contain_exactly(organization_a)
+ it 'returns the correct crm_organizations' do
+ expect(resolve_organizations(group, { state: :inactive })).to contain_exactly(crm_organization_a)
end
end
context 'when ids are provided' do
- it 'returns the correct organizations' do
+ it 'returns the correct crm_organizations' do
expect(resolve_organizations(group, {
- ids: [organization_b.to_global_id]
- })).to contain_exactly(organization_b)
+ ids: [crm_organization_b.to_global_id]
+ })).to contain_exactly(crm_organization_b)
end
end
end
diff --git a/spec/graphql/resolvers/project_issues_resolver_spec.rb b/spec/graphql/resolvers/project_issues_resolver_spec.rb
index b2796ad9b18..a510baab5a9 100644
--- a/spec/graphql/resolvers/project_issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_issues_resolver_spec.rb
@@ -359,9 +359,9 @@ RSpec.describe Resolvers::ProjectIssuesResolver do
end
describe 'filtering by crm' do
- let_it_be(:organization) { create(:organization, group: group) }
- let_it_be(:contact1) { create(:contact, group: group, organization: organization) }
- let_it_be(:contact2) { create(:contact, group: group, organization: organization) }
+ let_it_be(:crm_organization) { create(:crm_organization, group: group) }
+ let_it_be(:contact1) { create(:contact, group: group, organization: crm_organization) }
+ let_it_be(:contact2) { create(:contact, group: group, organization: crm_organization) }
let_it_be(:contact3) { create(:contact, group: group) }
let_it_be(:crm_issue1) { create(:issue, project: project) }
let_it_be(:crm_issue2) { create(:issue, project: project) }
@@ -381,9 +381,9 @@ RSpec.describe Resolvers::ProjectIssuesResolver do
end
end
- context 'when filtering by organization' do
+ context 'when filtering by crm_organization' do
it 'returns only the issues for the contact' do
- expect(resolve_issues({ crm_organization_id: organization.id })).to contain_exactly(crm_issue1, crm_issue2)
+ expect(resolve_issues({ crm_organization_id: crm_organization.id })).to contain_exactly(crm_issue1, crm_issue2)
end
end
end
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 5fbda3d77b0..24dc93922a8 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -250,10 +250,13 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
name: "",
items: [
{ href: "/projects/new", text: "New project/repository",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_project") },
{ href: "/groups/new", text: "New group",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_group") },
{ href: "/-/snippets/new", text: "New snippet",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_snippet") }
]
}
@@ -279,10 +282,13 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
name: "In this group",
items: array_including(
{ href: "/projects/new", text: "New project/repository",
+ component: nil,
extraAttrs: extra_attrs.call("new_project") },
{ href: "/groups/new#create-group-pane", text: "New subgroup",
+ component: nil,
extraAttrs: extra_attrs.call("new_subgroup") },
- { href: "", text: "Invite members",
+ { href: nil, text: "Invite members",
+ component: 'invite_members',
extraAttrs: extra_attrs.call("invite") }
)
),
@@ -290,10 +296,13 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
name: "In GitLab",
items: array_including(
{ href: "/projects/new", text: "New project/repository",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_project") },
{ href: "/groups/new", text: "New group",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_group") },
{ href: "/-/snippets/new", text: "New snippet",
+ component: nil,
extraAttrs: extra_attrs.call("general_new_snippet") }
)
)
diff --git a/spec/lib/gitlab/ci/jwt_v2_spec.rb b/spec/lib/gitlab/ci/jwt_v2_spec.rb
index 21fd7e3adcf..5103e92806a 100644
--- a/spec/lib/gitlab/ci/jwt_v2_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_v2_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::JwtV2 do
+RSpec.describe Gitlab::Ci::JwtV2, feature_category: :continuous_integration do
let(:namespace) { build_stubbed(:namespace) }
let(:project) { build_stubbed(:project, namespace: namespace) }
let(:user) do
@@ -13,6 +13,7 @@ RSpec.describe Gitlab::Ci::JwtV2 do
end
let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'auto-deploy-2020-03-19') }
+ let(:runner) { build_stubbed(:ci_runner) }
let(:aud) { described_class::DEFAULT_AUD }
let(:build) do
@@ -20,7 +21,8 @@ RSpec.describe Gitlab::Ci::JwtV2 do
:ci_build,
project: project,
user: user,
- pipeline: pipeline
+ pipeline: pipeline,
+ runner: runner
)
end
@@ -58,5 +60,41 @@ RSpec.describe Gitlab::Ci::JwtV2 do
expect(payload[:aud]).to eq('AWS')
end
end
+
+ describe 'custom claims' do
+ describe 'runner_id' do
+ it 'is the ID of the runner executing the job' do
+ expect(payload[:runner_id]).to eq(runner.id)
+ end
+ end
+
+ describe 'runner_environment' do
+ context 'when runner is gitlab-hosted' do
+ before do
+ allow(runner).to receive(:gitlab_hosted?).and_return(true)
+ end
+
+ it "is #{described_class::GITLAB_HOSTED_RUNNER}" do
+ expect(payload[:runner_environment]).to eq(described_class::GITLAB_HOSTED_RUNNER)
+ end
+ end
+
+ context 'when runner is self-hosted' do
+ before do
+ allow(runner).to receive(:gitlab_hosted?).and_return(false)
+ end
+
+ it "is #{described_class::SELF_HOSTED_RUNNER}" do
+ expect(payload[:runner_environment]).to eq(described_class::SELF_HOSTED_RUNNER)
+ end
+ end
+ end
+
+ describe 'sha' do
+ it 'is the commit revision the project is built for' do
+ expect(payload[:sha]).to eq(pipeline.sha)
+ end
+ end
+ end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 99326dfd02d..970717b1212 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -3842,6 +3842,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
'ID_TOKEN_1' => { aud: 'developers' },
'ID_TOKEN_2' => { aud: 'maintainers' }
})
+ build.runner = build_stubbed(:ci_runner)
end
subject(:runner_vars) { build.variables.to_runner_variables }
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 53a6a0e6a88..65c4174c1ea 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -2093,4 +2093,30 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
end
end
end
+
+ describe '#gitlab_hosted?' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject(:runner) { build_stubbed(:ci_runner) }
+
+ where(:saas, :runner_type, :expected_value) do
+ true | :instance_type | true
+ true | :group_type | false
+ true | :project_type | false
+ false | :instance_type | false
+ false | :group_type | false
+ false | :project_type | false
+ end
+
+ with_them do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(saas)
+ runner.runner_type = runner_type
+ end
+
+ it 'returns the correct value based on saas and runner type' do
+ expect(runner.gitlab_hosted?).to eq(expected_value)
+ end
+ end
+ end
end
diff --git a/spec/models/customer_relations/contact_spec.rb b/spec/models/customer_relations/contact_spec.rb
index 487af404a7c..6beb5323f60 100644
--- a/spec/models/customer_relations/contact_spec.rb
+++ b/spec/models/customer_relations/contact_spec.rb
@@ -241,8 +241,8 @@ RSpec.describe CustomerRelations::Contact, type: :model do
end
describe 'sorting' do
- let_it_be(:organization_a) { create(:organization, name: 'a') }
- let_it_be(:organization_b) { create(:organization, name: 'b') }
+ let_it_be(:crm_organization_a) { create(:crm_organization, name: 'a') }
+ let_it_be(:crm_organization_b) { create(:crm_organization, name: 'b') }
let_it_be(:contact_a) { create(:contact, group: group, first_name: "c", last_name: "d") }
let_it_be(:contact_b) do
create(:contact,
@@ -250,7 +250,7 @@ RSpec.describe CustomerRelations::Contact, type: :model do
first_name: "a",
last_name: "b",
phone: "123",
- organization: organization_a)
+ organization: crm_organization_a)
end
let_it_be(:contact_c) do
@@ -259,7 +259,7 @@ RSpec.describe CustomerRelations::Contact, type: :model do
first_name: "e",
last_name: "d",
phone: "456",
- organization: organization_b)
+ organization: crm_organization_b)
end
describe '.sort_by_name' do
diff --git a/spec/models/customer_relations/organization_spec.rb b/spec/models/customer_relations/organization_spec.rb
index d19a0bdf6c7..7fab9fd0e80 100644
--- a/spec/models/customer_relations/organization_spec.rb
+++ b/spec/models/customer_relations/organization_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
describe 'validations' do
- subject { build(:organization) }
+ subject { build(:crm_organization) }
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:name) }
@@ -21,13 +21,13 @@ RSpec.describe CustomerRelations::Organization, type: :model do
describe '#root_group' do
context 'when root group' do
- subject { build(:organization, group: group) }
+ subject { build(:crm_organization, group: group) }
it { is_expected.to be_valid }
end
context 'when subgroup' do
- subject { build(:organization, group: create(:group, parent: group)) }
+ subject { build(:crm_organization, group: create(:group, parent: group)) }
it { is_expected.to be_invalid }
end
@@ -43,23 +43,25 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
describe '#find_by_name' do
- let!(:organiztion1) { create(:organization, group: group, name: 'Test') }
- let!(:organiztion2) { create(:organization, group: create(:group), name: 'Test') }
+ let!(:crm_organiztion1) { create(:crm_organization, group: group, name: 'Test') }
+ let!(:crm_organiztion2) { create(:crm_organization, group: create(:group), name: 'Test') }
it 'strips name' do
- expect(described_class.find_by_name(group.id, 'TEST')).to eq([organiztion1])
+ expect(described_class.find_by_name(group.id, 'TEST')).to eq([crm_organiztion1])
end
end
describe '#self.move_to_root_group' do
let!(:old_root_group) { create(:group) }
- let!(:organizations) { create_list(:organization, 4, group: old_root_group) }
+ let!(:crm_organizations) { create_list(:crm_organization, 4, group: old_root_group) }
let!(:new_root_group) { create(:group) }
- let!(:contact1) { create(:contact, group: new_root_group, organization: organizations[0]) }
- let!(:contact2) { create(:contact, group: new_root_group, organization: organizations[1]) }
+ let!(:contact1) { create(:contact, group: new_root_group, organization: crm_organizations[0]) }
+ let!(:contact2) { create(:contact, group: new_root_group, organization: crm_organizations[1]) }
- let!(:dupe_organization1) { create(:organization, group: new_root_group, name: organizations[1].name) }
- let!(:dupe_organization2) { create(:organization, group: new_root_group, name: organizations[3].name.upcase) }
+ let!(:dupe_crm_organization1) { create(:crm_organization, group: new_root_group, name: crm_organizations[1].name) }
+ let!(:dupe_crm_organization2) do
+ create(:crm_organization, group: new_root_group, name: crm_organizations[3].name.upcase)
+ end
before do
old_root_group.update!(parent: new_root_group)
@@ -67,22 +69,22 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
it 'moves organizations with unique names and deletes the rest' do
- expect(organizations[0].reload.group_id).to eq(new_root_group.id)
- expect(organizations[2].reload.group_id).to eq(new_root_group.id)
- expect { organizations[1].reload }.to raise_error(ActiveRecord::RecordNotFound)
- expect { organizations[3].reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expect(crm_organizations[0].reload.group_id).to eq(new_root_group.id)
+ expect(crm_organizations[2].reload.group_id).to eq(new_root_group.id)
+ expect { crm_organizations[1].reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expect { crm_organizations[3].reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'updates contact.organization_id for dupes and leaves the rest untouched' do
- expect(contact1.reload.organization_id).to eq(organizations[0].id)
- expect(contact2.reload.organization_id).to eq(dupe_organization1.id)
+ expect(contact1.reload.organization_id).to eq(crm_organizations[0].id)
+ expect(contact2.reload.organization_id).to eq(dupe_crm_organization1.id)
end
end
describe '.search' do
- let_it_be(:organization_a) do
+ let_it_be(:crm_organization_a) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "DEF",
description: "ghi_st",
@@ -90,9 +92,9 @@ RSpec.describe CustomerRelations::Organization, type: :model do
)
end
- let_it_be(:organization_b) do
+ let_it_be(:crm_organization_b) do
create(
- :organization,
+ :crm_organization,
group: group,
name: "ABC_st",
description: "JKL",
@@ -106,7 +108,7 @@ RSpec.describe CustomerRelations::Organization, type: :model do
let(:search_term) { "" }
it 'returns all group organizations' do
- expect(found_organizations).to contain_exactly(organization_a, organization_b)
+ expect(found_organizations).to contain_exactly(crm_organization_a, crm_organization_b)
end
end
@@ -114,42 +116,42 @@ RSpec.describe CustomerRelations::Organization, type: :model do
context 'when searching for name' do
let(:search_term) { "aBc" }
- it { is_expected.to contain_exactly(organization_b) }
+ it { is_expected.to contain_exactly(crm_organization_b) }
end
context 'when searching for description' do
let(:search_term) { "ghI" }
- it { is_expected.to contain_exactly(organization_a) }
+ it { is_expected.to contain_exactly(crm_organization_a) }
end
context 'when searching for name and description' do
let(:search_term) { "_st" }
- it { is_expected.to contain_exactly(organization_a, organization_b) }
+ it { is_expected.to contain_exactly(crm_organization_a, crm_organization_b) }
end
end
end
describe '.search_by_state' do
- let_it_be(:organization_a) { create(:organization, group: group, state: "inactive") }
- let_it_be(:organization_b) { create(:organization, group: group, state: "active") }
+ let_it_be(:crm_organization_a) { create(:crm_organization, group: group, state: "inactive") }
+ let_it_be(:crm_organization_b) { create(:crm_organization, group: group, state: "active") }
context 'when searching for organizations state' do
it 'returns only inactive organizations' do
- expect(group.organizations.search_by_state(:inactive)).to contain_exactly(organization_a)
+ expect(group.organizations.search_by_state(:inactive)).to contain_exactly(crm_organization_a)
end
it 'returns only active organizations' do
- expect(group.organizations.search_by_state(:active)).to contain_exactly(organization_b)
+ expect(group.organizations.search_by_state(:active)).to contain_exactly(crm_organization_b)
end
end
end
describe '.counts_by_state' do
before do
- create_list(:organization, 3, group: group)
- create_list(:organization, 2, group: group, state: 'inactive')
+ create_list(:crm_organization, 3, group: group)
+ create_list(:crm_organization, 2, group: group, state: 'inactive')
end
it 'returns correct organization counts' do
@@ -168,20 +170,20 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
describe 'sorting' do
- let_it_be(:organization_a) { create(:organization, group: group, name: "c", description: "1") }
- let_it_be(:organization_b) { create(:organization, group: group, name: "a") }
- let_it_be(:organization_c) { create(:organization, group: group, name: "b", description: "2") }
+ let_it_be(:crm_organization_a) { create(:crm_organization, group: group, name: "c", description: "1") }
+ let_it_be(:crm_organization_b) { create(:crm_organization, group: group, name: "a") }
+ let_it_be(:crm_organization_c) { create(:crm_organization, group: group, name: "b", description: "2") }
describe '.sort_by_name' do
it 'sorts them by name in ascendent order' do
- expect(group.organizations.sort_by_name).to eq([organization_b, organization_c, organization_a])
+ expect(group.organizations.sort_by_name).to eq([crm_organization_b, crm_organization_c, crm_organization_a])
end
end
describe '.sort_by_field' do
it 'sorts them by description in descending order' do
expect(group.organizations.sort_by_field('description', :desc))
- .to eq([organization_c, organization_a, organization_b])
+ .to eq([crm_organization_c, crm_organization_a, crm_organization_b])
end
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 0bf4540f535..f7f9ec8e7a7 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -3162,11 +3162,11 @@ RSpec.describe Group, feature_category: :subgroups do
describe '.organizations' do
it 'returns organizations belonging to the group' do
- organization1 = create(:organization, group: group)
- create(:organization)
- organization3 = create(:organization, group: group)
+ crm_organization1 = create(:crm_organization, group: group)
+ create(:crm_organization)
+ crm_organization3 = create(:crm_organization, group: group)
- expect(group.organizations).to contain_exactly(organization1, organization3)
+ expect(group.organizations).to contain_exactly(crm_organization1, crm_organization3)
end
end
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index efe76c9cfda..692b4c76ea3 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe API::Deployments, feature_category: :continuous_delivery do
perform_request({ updated_before: 30.minutes.ago, updated_after: 90.minutes.ago, order_by: :id })
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to include('`updated_at` filter and `updated_at` sorting must be paired')
+ expect(json_response['message']).to include('`updated_at` filter requires `updated_at` sort')
end
end
end
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 68c722c5e9d..65afeb2cb56 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -456,6 +456,44 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
it_behaves_like 'has no register url'
end
end
+
+ context 'with a project runner' do
+ context 'with registration available' do
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project1], registration_type: :authenticated_user) }
+
+ it_behaves_like 'has register url' do
+ let(:expected_url) { "http://localhost/#{project1.full_path}/-/runners/#{runner.id}/register" }
+ end
+ end
+
+ context 'with no project' do
+ let(:destroyed_project) { create(:project) }
+ let(:runner) { create(:ci_runner, :project, projects: [destroyed_project], registration_type: :authenticated_user) }
+
+ before do
+ destroyed_project.destroy!
+ end
+
+ it_behaves_like 'has no register url'
+ end
+
+ context 'with no registration available' do
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project1]) }
+
+ it_behaves_like 'has no register url'
+ end
+
+ context 'with no access' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:runner) { create(:ci_runner, :project, projects: [project1], registration_type: :authenticated_user) }
+
+ before do
+ group.add_maintainer(user)
+ end
+
+ it_behaves_like 'has no register url'
+ end
+ end
end
describe 'for runner with status' do
diff --git a/spec/requests/api/graphql/query_spec.rb b/spec/requests/api/graphql/query_spec.rb
index d93077b1c70..0602cfec149 100644
--- a/spec/requests/api/graphql/query_spec.rb
+++ b/spec/requests/api/graphql/query_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Query', feature_category: :shared do
include GraphqlHelpers
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { create(:project, public_builds: false) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:developer) { create(:user) }
@@ -116,4 +116,36 @@ RSpec.describe 'Query', feature_category: :shared do
end
end
end
+
+ describe '.ciPipelineStage' do
+ let_it_be(:ci_stage) { create(:ci_stage, name: 'graphql test stage', project: project) }
+
+ let(:query) do
+ <<~GRAPHQL
+ {
+ ciPipelineStage(id: "#{ci_stage.to_global_id}") {
+ name
+ }
+ }
+ GRAPHQL
+ end
+
+ context 'when the current user has access to the stage' do
+ it 'fetches the stage for the given ID' do
+ project.add_developer(developer)
+
+ post_graphql(query, current_user: developer)
+
+ expect(graphql_data.dig('ciPipelineStage', 'name')).to eq('graphql test stage')
+ end
+ end
+
+ context 'when the current user does not have access to the stage' do
+ it 'returns nil' do
+ post_graphql(query, current_user: developer)
+
+ expect(graphql_data['ciPipelineStage']).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index bce004dcd48..4c9f930df2f 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -114,17 +114,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
end
end
- context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
- let(:state_name) { 'state-name-with-dot' }
- let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}.tfstate" }
-
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: false)
- end
-
- it_behaves_like 'can access terraform state'
- end
-
context 'for a project that does not exist' do
let(:project_id) { '0000' }
@@ -277,21 +266,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
expect(Gitlab::Json.parse(response.body)).to be_empty
end
end
-
- context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
- let(:non_existing_state_name) { 'state-name-with-dot.tfstate' }
-
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: false)
- end
-
- it 'strips characters after the dot' do
- expect { request }.to change { Terraform::State.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(Terraform::State.last.name).to eq('state-name-with-dot')
- end
- end
end
context 'without body' do
@@ -399,18 +373,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
it_behaves_like 'schedules the state for deletion'
end
- context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
- let(:state_name) { 'state-name-with-dot' }
- let(:state_name_with_dot) { "#{state_name}.tfstate" }
- let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name_with_dot}" }
-
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: false)
- end
-
- it_behaves_like 'schedules the state for deletion'
- end
-
context 'with invalid state name' do
let(:state_name) { 'foo/bar' }
@@ -500,30 +462,10 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
context 'with a dot in the state name' do
let(:state_name) { 'test.state' }
- context 'with allow_dots_on_tf_state_names ff enabled' do
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: true)
- end
-
- let(:state_name) { 'test.state' }
-
- it 'locks the terraform state' do
- request
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- context 'with allow_dots_on_tf_state_names ff disabled' do
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: false)
- end
-
- it 'returns 404' do
- request
+ it 'locks the terraform state' do
+ request
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ expect(response).to have_gitlab_http_status(:ok)
end
end
end
@@ -544,7 +486,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
before do
state.lock_xid = '123.456'
state.save!
- stub_feature_flags(allow_dots_on_tf_state_names: true)
end
subject(:request) { delete api("#{state_path}/lock"), headers: auth_header, params: params }
@@ -575,23 +516,6 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
end
end
- context 'with allow_dots_on_tf_state_names ff disabled' do
- before do
- stub_feature_flags(allow_dots_on_tf_state_names: false)
- end
-
- context 'with dots in the state name' do
- let(:lock_id) { '123.456' }
- let(:state_name) { 'test.state' }
-
- it 'returns 404' do
- request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
context 'with no lock id (force-unlock)' do
let(:params) { {} }
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb
index 7b576339c61..6da6ec3379a 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -26,10 +26,13 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category
end
let(:bridge) do
- create(:ci_bridge, status: :pending,
- user: user,
- options: trigger,
- pipeline: upstream_pipeline)
+ create(
+ :ci_bridge,
+ status: :pending,
+ user: user,
+ options: trigger,
+ pipeline: upstream_pipeline
+ )
end
let(:service) { described_class.new(upstream_project, user) }
@@ -704,8 +707,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category
context 'when user does not have access to push protected branch of downstream project' do
before do
- create(:protected_branch, :maintainers_can_push,
- project: downstream_project, name: 'feature')
+ create(:protected_branch, :maintainers_can_push, project: downstream_project, name: 'feature')
end
it 'changes status of the bridge build' do
diff --git a/spec/services/ci/create_pipeline_service/include_spec.rb b/spec/services/ci/create_pipeline_service/include_spec.rb
index 86f71be5971..1280ab4b7bd 100644
--- a/spec/services/ci/create_pipeline_service/include_spec.rb
+++ b/spec/services/ci/create_pipeline_service/include_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService,
-:yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do
+ :yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do
include RepoHelpers
context 'include:' do
diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb
index 082a09db69e..6a1987fcc7c 100644
--- a/spec/services/ci/create_pipeline_service/logger_spec.rb
+++ b/spec/services/ci/create_pipeline_service/logger_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath
- :yaml_processor_feature_flag_corectness,
- feature_category: :continuous_integration do
+ :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
describe 'pipeline logger' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
index 8d04b3d020f..25f6e43d600 100644
--- a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
+++ b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness,
-feature_category: :continuous_integration do
+ feature_category: :continuous_integration do
context 'merge requests handling' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -31,11 +31,13 @@ feature_category: :continuous_integration do
context 'when pushing a change' do
context 'when a merge request already exists' do
let!(:merge_request) do
- create(:merge_request,
- source_project: project,
- source_branch: 'feature',
- target_project: project,
- target_branch: 'master')
+ create(
+ :merge_request,
+ source_project: project,
+ source_branch: 'feature',
+ target_project: project,
+ target_branch: 'master'
+ )
end
it 'does not create a pipeline' do
diff --git a/spec/services/ci/create_pipeline_service/partitioning_spec.rb b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
index a87135cefdd..70c4eb49698 100644
--- a/spec/services/ci/create_pipeline_service/partitioning_spec.rb
+++ b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :aggregate_failures,
-:ci_partitionable, feature_category: :continuous_integration do
+ :ci_partitionable, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
index 31bea10f062..26a9484dbc4 100644
--- a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, :freeze_time,
- :clean_gitlab_redis_rate_limiting,
- :yaml_processor_feature_flag_corectness,
- feature_category: :continuous_integration do
+ :clean_gitlab_redis_rate_limiting,
+ :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
describe 'rate limiting' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index acdbeee40a9..b08dda72a69 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1193,8 +1193,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when pipeline is running for a tag' do
before do
- config = YAML.dump(test: { script: 'test', only: ['branches'] },
- deploy: { script: 'deploy', only: ['tags'] })
+ config = YAML.dump(
+ test: { script: 'test', only: ['branches'] },
+ deploy: { script: 'deploy', only: ['tags'] }
+ )
stub_ci_pipeline_yaml_file(config)
end
@@ -1369,11 +1371,13 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
describe 'Pipeline for external pull requests' do
let(:response) do
- execute_service(source: source,
- external_pull_request: pull_request,
- ref: ref_name,
- source_sha: source_sha,
- target_sha: target_sha)
+ execute_service(
+ source: source,
+ external_pull_request: pull_request,
+ ref: ref_name,
+ source_sha: source_sha,
+ target_sha: target_sha
+ )
end
let(:pipeline) { response.payload }
@@ -1525,11 +1529,13 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
describe 'Pipelines for merge requests' do
let(:response) do
- execute_service(source: source,
- merge_request: merge_request,
- ref: ref_name,
- source_sha: source_sha,
- target_sha: target_sha)
+ execute_service(
+ source: source,
+ merge_request: merge_request,
+ ref: ref_name,
+ source_sha: source_sha,
+ target_sha: target_sha
+ )
end
let(:pipeline) { response.payload }
diff --git a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
index d1ec2a1d3a6..cdbb0c0f8ce 100644
--- a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::JobArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state,
-feature_category: :build_artifacts do
+ feature_category: :build_artifacts do
include ExclusiveLeaseHelpers
let(:service) { described_class.new }
diff --git a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
index 5355bec2d6c..af0c9b0833d 100644
--- a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
+++ b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb
@@ -33,13 +33,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
.with(test_event_name_1, values: user1.id)
.and_call_original
- expect { track_artifact_report }
- .to change {
- counter.unique_events(event_names: test_event_name_1,
- start_date: start_time,
- end_date: end_time)
- }
- .by 1
+ expect { track_artifact_report }.to change {
+ counter.unique_events(event_names: test_event_name_1, start_date: start_time, end_date: end_time)
+ }.by 1
end
end
@@ -81,13 +77,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
expect do
described_class.new.execute(pipeline1)
described_class.new.execute(pipeline2)
- end
- .to change {
- counter.unique_events(event_names: test_event_name_1,
- start_date: start_time,
- end_date: end_time)
- }
- .by 1
+ end.to change {
+ counter.unique_events(event_names: test_event_name_1, start_date: start_time, end_date: end_time)
+ }.by 1
end
end
@@ -109,13 +101,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
expect do
described_class.new.execute(pipeline1)
described_class.new.execute(pipeline2)
- end
- .to change {
- counter.unique_events(event_names: test_event_name_1,
- start_date: start_time,
- end_date: end_time)
- }
- .by 2
+ end.to change {
+ counter.unique_events(event_names: test_event_name_1, start_date: start_time, end_date: end_time)
+ }.by 2
end
end
@@ -134,13 +122,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
.with(test_event_name_2, values: user1.id)
.and_call_original
- expect { track_artifact_report }
- .to change {
- counter.unique_events(event_names: test_event_name_2,
- start_date: start_time,
- end_date: end_time)
- }
- .by 1
+ expect { track_artifact_report }.to change {
+ counter.unique_events(event_names: test_event_name_2, start_date: start_time, end_date: end_time)
+ }.by 1
end
end
@@ -158,13 +142,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
expect do
described_class.new.execute(pipeline1)
described_class.new.execute(pipeline2)
- end
- .to change {
- counter.unique_events(event_names: test_event_name_2,
- start_date: start_time,
- end_date: end_time)
- }
- .by 1
+ end.to change {
+ counter.unique_events(event_names: test_event_name_2, start_date: start_time, end_date: end_time)
+ }.by 1
end
end
@@ -186,13 +166,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :
expect do
described_class.new.execute(pipeline1)
described_class.new.execute(pipeline2)
- end
- .to change {
- counter.unique_events(event_names: test_event_name_2,
- start_date: start_time,
- end_date: end_time)
- }
- .by 2
+ end.to change {
+ counter.unique_events(event_names: test_event_name_2, start_date: start_time, end_date: end_time)
+ }.by 2
end
end
end
diff --git a/spec/services/ci/list_config_variables_service_spec.rb b/spec/services/ci/list_config_variables_service_spec.rb
index febb1533b0f..07c9085b83a 100644
--- a/spec/services/ci/list_config_variables_service_spec.rb
+++ b/spec/services/ci/list_config_variables_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::ListConfigVariablesService,
-:use_clean_rails_memory_store_caching, feature_category: :secrets_management do
+ :use_clean_rails_memory_store_caching, feature_category: :secrets_management do
include ReactiveCachingHelpers
let(:ci_config) { {} }
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
index d0496acc6fe..8c52603e769 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -646,8 +646,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category
# Users need ability to merge into a branch in order to trigger
# protected manual actions.
#
- create(:protected_branch, :developers_can_merge,
- name: 'master', project: project)
+ create(:protected_branch, :developers_can_merge, name: 'master', project: project)
end
it 'properly processes entire pipeline' do
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index f439538b4cc..46b6622d6ec 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -16,8 +16,7 @@ RSpec.describe Ci::PlayBuildService, '#execute', feature_category: :continuous_i
let(:project) { create(:project) }
it 'allows user to play build if protected branch rules are met' do
- create(:protected_branch, :developers_can_merge,
- name: build.ref, project: project)
+ create(:protected_branch, :developers_can_merge, name: build.ref, project: project)
service.execute(build)
diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb
index 1aca4ffec2d..dd8e037b129 100644
--- a/spec/services/ci/play_manual_stage_service_spec.rb
+++ b/spec/services/ci/play_manual_stage_service_spec.rb
@@ -11,10 +11,7 @@ RSpec.describe Ci::PlayManualStageService, '#execute', feature_category: :contin
let(:stage_status) { 'manual' }
let(:stage) do
- create(:ci_stage,
- pipeline: pipeline,
- project: project,
- name: 'test')
+ create(:ci_stage, pipeline: pipeline, project: project, name: 'test')
end
before do
diff --git a/spec/services/ci/process_sync_events_service_spec.rb b/spec/services/ci/process_sync_events_service_spec.rb
index c042a9bd46e..84b6d7d96f6 100644
--- a/spec/services/ci/process_sync_events_service_spec.rb
+++ b/spec/services/ci/process_sync_events_service_spec.rb
@@ -147,8 +147,7 @@ RSpec.describe Ci::ProcessSyncEventsService, feature_category: :continuous_integ
context 'when the FFs use_traversal_ids and use_traversal_ids_for_ancestors are disabled' do
before do
- stub_feature_flags(use_traversal_ids: false,
- use_traversal_ids_for_ancestors: false)
+ stub_feature_flags(use_traversal_ids: false, use_traversal_ids_for_ancestors: false)
end
it_behaves_like 'event consuming'
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index fed66bc535d..f15f4a16d4f 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -51,11 +51,13 @@ RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
let_it_be(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
let_it_be(:job_to_clone) do
- create(:ci_build, :failed, :picked, :expired, :erased, :queued, :coverage, :tags,
- :allowed_to_fail, :on_tag, :triggered, :teardown_environment, :resource_group,
- description: 'my-job', ci_stage: stage,
- pipeline: pipeline, auto_canceled_by: another_pipeline,
- scheduled_at: 10.seconds.since)
+ create(
+ :ci_build, :failed, :picked, :expired, :erased, :queued, :coverage, :tags,
+ :allowed_to_fail, :on_tag, :triggered, :teardown_environment, :resource_group,
+ description: 'my-job', ci_stage: stage,
+ pipeline: pipeline, auto_canceled_by: another_pipeline,
+ scheduled_at: 10.seconds.since
+ )
end
before do
@@ -236,8 +238,7 @@ RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
context 'when a build with a deployment is retried' do
let!(:job) do
- create(:ci_build, :with_deployment, :deploy_to_production,
- pipeline: pipeline, ci_stage: stage)
+ create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline, ci_stage: stage)
end
it 'creates a new deployment' do
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 51a894640ab..fc2c66e7f73 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -19,8 +19,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuo
before do
project.add_developer(user)
- create(:protected_branch, :developers_can_merge,
- name: pipeline.ref, project: project)
+ create(:protected_branch, :developers_can_merge, name: pipeline.ref, project: project)
end
context 'when there are already retried jobs present' do
@@ -408,8 +407,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuo
context 'when user is not allowed to trigger manual action' do
before do
project.add_developer(user)
- create(:protected_branch, :maintainers_can_push,
- name: pipeline.ref, project: project)
+ create(:protected_branch, :maintainers_can_push, name: pipeline.ref, project: project)
end
context 'when there is a failed manual action present' do
@@ -490,11 +488,15 @@ RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuo
end
def create_processable(type, name, status, stage, **opts)
- create(type, name: name,
- status: status,
- ci_stage: stage,
- stage_idx: stage.position,
- pipeline: pipeline, **opts) do |_job|
+ create(
+ type,
+ name: name,
+ status: status,
+ ci_stage: stage,
+ stage_idx: stage.position,
+ pipeline: pipeline,
+ **opts
+ ) do |_job|
::Ci::ProcessPipelineService.new(pipeline).execute
end
end
diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb
index e3ae1d93e5e..33f9efcb89f 100644
--- a/spec/services/ci/run_scheduled_build_service_spec.rb
+++ b/spec/services/ci/run_scheduled_build_service_spec.rb
@@ -13,8 +13,7 @@ RSpec.describe Ci::RunScheduledBuildService, feature_category: :continuous_integ
before do
project.add_developer(user)
- create(:protected_branch, :developers_can_merge,
- name: pipeline.ref, project: project)
+ create(:protected_branch, :developers_can_merge, name: pipeline.ref, project: project)
end
context 'when build is scheduled' do
diff --git a/spec/services/customer_relations/contacts/create_service_spec.rb b/spec/services/customer_relations/contacts/create_service_spec.rb
index 610143586e3..91aa51385e7 100644
--- a/spec/services/customer_relations/contacts/create_service_spec.rb
+++ b/spec/services/customer_relations/contacts/create_service_spec.rb
@@ -50,8 +50,8 @@ RSpec.describe CustomerRelations::Contacts::CreateService, feature_category: :se
end
it 'returns an error when the organization belongs to a different group' do
- organization = create(:organization)
- params[:organization_id] = organization.id
+ crm_organization = create(:crm_organization)
+ params[:organization_id] = crm_organization.id
expect(response).to be_error
expect(response.message).to match_array([not_found_or_does_not_belong])
diff --git a/spec/services/customer_relations/organizations/create_service_spec.rb b/spec/services/customer_relations/organizations/create_service_spec.rb
index 3b1ae5606b1..8748fe44763 100644
--- a/spec/services/customer_relations/organizations/create_service_spec.rb
+++ b/spec/services/customer_relations/organizations/create_service_spec.rb
@@ -7,11 +7,11 @@ RSpec.describe CustomerRelations::Organizations::CreateService, feature_category
let_it_be(:user) { create(:user) }
let(:group) { create(:group, :crm_enabled) }
- let(:params) { attributes_for(:organization, group: group) }
+ let(:params) { attributes_for(:crm_organization, group: group) }
subject(:response) { described_class.new(group: group, current_user: user, params: params).execute }
- it 'creates an organization' do
+ it 'creates a crm_organization' do
group.add_developer(user)
expect(response).to be_success
@@ -24,7 +24,7 @@ RSpec.describe CustomerRelations::Organizations::CreateService, feature_category
expect(response.message).to match_array(['You have insufficient permissions to create an organization for this group'])
end
- it 'returns an error when the organization is not persisted' do
+ it 'returns an error when the crm_organization is not persisted' do
group.add_developer(user)
params[:name] = nil
diff --git a/spec/services/customer_relations/organizations/update_service_spec.rb b/spec/services/customer_relations/organizations/update_service_spec.rb
index ac71a211bf8..f11b99b101e 100644
--- a/spec/services/customer_relations/organizations/update_service_spec.rb
+++ b/spec/services/customer_relations/organizations/update_service_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category: :service_desk do
let_it_be(:user) { create(:user) }
- let(:organization) { create(:organization, name: 'Test', group: group, state: 'active') }
+ let(:crm_organization) { create(:crm_organization, name: 'Test', group: group, state: 'active') }
- subject(:update) { described_class.new(group: group, current_user: user, params: params).execute(organization) }
+ subject(:update) { described_class.new(group: group, current_user: user, params: params).execute(crm_organization) }
describe '#execute' do
context 'when the user has no permission' do
@@ -33,7 +33,7 @@ RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category
context 'when name is changed' do
let(:params) { { name: 'GitLab' } }
- it 'updates the organization' do
+ it 'updates the crm_organization' do
response = update
expect(response).to be_success
@@ -42,7 +42,7 @@ RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category
end
context 'when activating' do
- let(:organization) { create(:organization, state: 'inactive') }
+ let(:crm_organization) { create(:crm_organization, state: 'inactive') }
let(:params) { { active: true } }
it 'updates the contact' do
@@ -56,7 +56,7 @@ RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category
context 'when deactivating' do
let(:params) { { active: false } }
- it 'updates the organization' do
+ it 'updates the crm_organization' do
response = update
expect(response).to be_success
@@ -64,7 +64,7 @@ RSpec.describe CustomerRelations::Organizations::UpdateService, feature_category
end
end
- context 'when the organization is invalid' do
+ context 'when the crm_organization is invalid' do
let(:params) { { name: nil } }
it 'returns an error' do
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index 27da948079e..475cd250e7c 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -890,7 +890,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline, feature_category: :subg
let(:subsub_project) { create(:project, group: subsubgroup) }
let!(:contacts) { create_list(:contact, 4, group: root_group) }
- let!(:organizations) { create_list(:organization, 2, group: root_group) }
+ let!(:organizations) { create_list(:crm_organization, 2, group: root_group) }
before do
create(:issue_customer_relations_contact, contact: contacts[0], issue: create(:issue, project: root_project))
diff --git a/spec/support/protected_branch_helpers.rb b/spec/support/protected_branch_helpers.rb
index b34b9ec4641..d983d03fd2e 100644
--- a/spec/support/protected_branch_helpers.rb
+++ b/spec/support/protected_branch_helpers.rb
@@ -2,18 +2,10 @@
module ProtectedBranchHelpers
def set_allowed_to(operation, option = 'Maintainers', form: '.js-new-protected-branch')
- within form do
- select_elem = find(".js-allowed-to-#{operation}")
- select_elem.click
-
- wait_for_requests
-
- within('.dropdown-content') do
+ within(form) do
+ within_select(".js-allowed-to-#{operation}") do
Array(option).each { |opt| click_on(opt) }
end
-
- # Enhanced select is used in EE, therefore an extra click is needed.
- select_elem.click if select_elem['aria-expanded'] == 'true'
end
end
@@ -32,4 +24,15 @@ module ProtectedBranchHelpers
click_on "Protect"
wait_for_requests
end
+
+ def within_select(selector, &block)
+ select_input = find(selector)
+ select_input.click
+ wait_for_requests
+
+ within('.dropdown.show .dropdown-menu', &block)
+
+ # Enhanced select is used in EE, therefore an extra click is needed.
+ select_input.click if select_input['aria-expanded'] == 'true'
+ end
end
diff --git a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
index 1585ef0e7fc..095c8639d15 100644
--- a/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
+++ b/spec/support/shared_contexts/graphql/types/query_type_shared_context.rb
@@ -7,6 +7,7 @@ RSpec.shared_context 'with FOSS query type fields' do
:board_list,
:ci_application_settings,
:ci_config,
+ :ci_pipeline_stage,
:ci_variables,
:container_repository,
:current_user,
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
index db63521d1ee..2d3f1949716 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
@@ -1,126 +1,67 @@
# frozen_string_literal: true
RSpec.shared_examples "protected branches > access control > CE" do
+ let(:no_one) { ProtectedRef::AccessLevel.humanize(::Gitlab::Access::NO_ACCESS) }
+
ProtectedRef::AccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can push to" do
visit project_protected_branches_path(project)
set_protected_branch_name('master')
-
- find(".js-allowed-to-merge").click
- within('[data-testid="allowed-to-merge-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
- within('.js-new-protected-branch') do
- allowed_to_push_button = find(".js-allowed-to-push")
-
- unless allowed_to_push_button.text == access_type_name
- allowed_to_push_button.click
- within(".dropdown.show .dropdown-menu") { click_on access_type_name }
- end
- end
-
+ set_allowed_to('merge', no_one)
+ set_allowed_to('push', access_type_name)
click_on_protect
- wait_for_requests
expect(ProtectedBranch.count).to eq(1)
expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to eq([access_type_id])
end
- it "allows updating protected branches so that #{access_type_name} can push to them" do
+ it "allows creating protected branches that #{access_type_name} can merge to" do
visit project_protected_branches_path(project)
set_protected_branch_name('master')
-
- find(".js-allowed-to-merge").click
- within('[data-testid="allowed-to-merge-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
- find(".js-allowed-to-push").click
- within('[data-testid="allowed-to-push-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
+ set_allowed_to('merge', access_type_name)
+ set_allowed_to('push', no_one)
click_on_protect
expect(ProtectedBranch.count).to eq(1)
-
- within(".protected-branches-list") do
- find(".js-allowed-to-push").click
-
- within('.js-allowed-to-push-container') do
- expect(first("li")).to have_content("Roles")
- find(:link, access_type_name).click
- end
-
- find(".js-allowed-to-push").click
- end
-
- wait_for_requests
-
- expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id)
+ expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to eq([access_type_id])
end
- end
- ProtectedRef::AccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
- it "allows creating protected branches that #{access_type_name} can merge to" do
+ it "allows updating protected branches so that #{access_type_name} can push to them" do
visit project_protected_branches_path(project)
set_protected_branch_name('master')
+ set_allowed_to('merge', no_one)
+ set_allowed_to('push', no_one)
+ click_on_protect
- within('.js-new-protected-branch') do
- allowed_to_merge_button = find(".js-allowed-to-merge")
+ expect(ProtectedBranch.count).to eq(1)
- unless allowed_to_merge_button.text == access_type_name
- allowed_to_merge_button.click
- within(".dropdown.show .dropdown-menu") { click_on access_type_name }
+ within(".protected-branches-list") do
+ within_select(".js-allowed-to-push") do
+ click_on(access_type_name)
end
end
- find(".js-allowed-to-push").click
- within('[data-testid="allowed-to-push-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
- click_on_protect
+ wait_for_requests
- expect(ProtectedBranch.count).to eq(1)
- expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to eq([access_type_id])
+ expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id)
end
it "allows updating protected branches so that #{access_type_name} can merge to them" do
visit project_protected_branches_path(project)
set_protected_branch_name('master')
-
- find(".js-allowed-to-merge").click
- within('[data-testid="allowed-to-merge-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
- find(".js-allowed-to-push").click
- within('[data-testid="allowed-to-push-dropdown"]') do
- expect(first("li")).to have_content("Roles")
- find(:link, 'No one').click
- end
-
+ set_allowed_to('merge', no_one)
+ set_allowed_to('push', no_one)
click_on_protect
expect(ProtectedBranch.count).to eq(1)
within(".protected-branches-list") do
- find(".js-allowed-to-merge").click
-
- within('.js-allowed-to-merge-container') do
- expect(first("li")).to have_content("Roles")
- find(:link, access_type_name).click
+ within_select(".js-allowed-to-merge") do
+ click_on(access_type_name)
end
end
diff --git a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
index c68d53db01e..67fed00b5ca 100644
--- a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
+++ b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
@@ -988,9 +988,9 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
let_it_be(:root_group) { create(:group) }
let_it_be(:group) { create(:group, parent: root_group) }
let_it_be(:project_crm) { create(:project, :public, group: group) }
- let_it_be(:organization) { create(:organization, group: root_group) }
- let_it_be(:contact1) { create(:contact, group: root_group, organization: organization) }
- let_it_be(:contact2) { create(:contact, group: root_group, organization: organization) }
+ let_it_be(:crm_organization) { create(:crm_organization, group: root_group) }
+ let_it_be(:contact1) { create(:contact, group: root_group, organization: crm_organization) }
+ let_it_be(:contact2) { create(:contact, group: root_group, organization: crm_organization) }
let_it_be(:contact1_item1) { create(factory, project: project_crm) }
let_it_be(:contact1_item2) { create(factory, project: project_crm) }
@@ -1028,10 +1028,10 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
end
context 'filtering by crm organization' do
- let(:params) { { project_id: project_crm.id, crm_organization_id: organization.id } }
+ let(:params) { { project_id: project_crm.id, crm_organization_id: crm_organization.id } }
context 'when the user can read crm organization' do
- it 'returns for that organization' do
+ it 'returns for that crm organization' do
root_group.add_reporter(user)
expect(items).to contain_exactly(contact1_item1, contact1_item2, contact2_item1)
@@ -1039,7 +1039,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
end
context 'when the user can not read crm organization' do
- it 'does not filter by organization' do
+ it 'does not filter by crm organization' do
expect(items).to match_array(all_project_issues)
end
end
diff --git a/yarn.lock b/yarn.lock
index ceb4171621d..fbf5b697039 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1115,10 +1115,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.40.0.tgz#f1ebb2fcdbb1181550d53f0db827eca1f5060af0"
integrity sha512-9CVkIbV0VnIFfVBjWcW8+nHzpMhHhC73C9mGPEktEPfpEbaaRws2UywgDEH+C2B8Ba1QdBo/aFr68RDu2VwvfA==
-"@gitlab/ui@61.3.0":
- version "61.3.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-61.3.0.tgz#5b1f9c7a01d7571150a796ca5f02fe44f9604fc4"
- integrity sha512-jOaEGjvtrVT7IZhtu/VZNmlodGgrE/UllciNfJxzm4nbbWMHlALspFp8btt/zxGxiI33oQJLS2qTCEu0QVVZHA==
+"@gitlab/ui@62.4.0":
+ version "62.4.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-62.4.0.tgz#827e2506a2880fb8d9899b9c18c1d5dfae79a9a7"
+ integrity sha512-FouJu0o3Za2Hz6WjnZSN+LTMSjpaBCE3SZ5HSBoz0be/WKjS3CX5WW3Qp2NMvNs59xe4V0xg3uWI2g/X0edjTw==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.23.1"