summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/review-apps/qa.gitlab-ci.yml2
-rw-r--r--.rubocop_todo/gitlab/strong_memoize_attr.yml2
-rw-r--r--.rubocop_todo/layout/line_length.yml11
-rw-r--r--.rubocop_todo/rspec/context_wording.yml7
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml2
-rw-r--r--.rubocop_todo/style/percent_literal_delimiters.yml2
-rw-r--r--.rubocop_todo/style/string_concatenation.yml1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue2
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue47
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue27
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue4
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js2
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher.vue7
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/groups_list.vue15
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/pinned_section.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/projects_list.vue15
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar.vue9
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue4
-rw-r--r--app/assets/stylesheets/framework/header.scss7
-rw-r--r--app/assets/stylesheets/framework/system_messages.scss21
-rw-r--r--app/assets/stylesheets/page_bundles/design_management.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/search.scss12
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss2
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss2
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss3
-rw-r--r--app/assets/stylesheets/utilities.scss6
-rw-r--r--app/finders/clusters/agent_authorizations_finder.rb69
-rw-r--r--app/finders/clusters/agents/authorizations/ci_access/finder.rb75
-rw-r--r--app/helpers/sidebars_helper.rb29
-rw-r--r--app/models/ci/build_metadata.rb2
-rw-r--r--app/models/ci/pipeline.rb2
-rw-r--r--app/models/clusters/agent.rb8
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/group_authorization.rb24
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb27
-rw-r--r--app/models/clusters/agents/authorizations/ci_access/project_authorization.rb24
-rw-r--r--app/models/clusters/agents/group_authorization.rb20
-rw-r--r--app/models/clusters/agents/implicit_authorization.rb23
-rw-r--r--app/models/clusters/agents/project_authorization.rb20
-rw-r--r--app/models/concerns/clusters/agents/authorization_config_scopes.rb25
-rw-r--r--app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb29
-rw-r--r--app/services/ci/generate_kubeconfig_service.rb2
-rw-r--r--app/services/clusters/agents/authorizations/ci_access/filter_service.rb54
-rw-r--r--app/services/clusters/agents/authorizations/ci_access/refresh_service.rb106
-rw-r--r--app/services/clusters/agents/authorize_proxy_user_service.rb4
-rw-r--r--app/services/clusters/agents/filter_authorizations_service.rb50
-rw-r--r--app/services/clusters/agents/refresh_authorization_service.rb102
-rw-r--r--app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json (renamed from app/validators/json_schemas/cluster_agent_authorization_configuration.json)0
-rw-r--r--app/views/search/_results.html.haml10
-rw-r--r--app/views/search/show.html.haml8
-rw-r--r--config/feature_categories.yml3
-rw-r--r--db/docs/agent_group_authorizations.yml2
-rw-r--r--db/docs/agent_project_authorizations.yml2
-rw-r--r--db/docs/pm_checkpoints.yml2
-rw-r--r--db/docs/pm_licenses.yml2
-rw-r--r--db/docs/pm_package_version_licenses.yml2
-rw-r--r--db/docs/pm_package_versions.yml2
-rw-r--r--db/docs/pm_packages.yml2
-rw-r--r--db/docs/project_security_settings.yml2
-rw-r--r--db/docs/vulnerability_advisories.yml3
-rw-r--r--db/post_migrate/20230405072302_remove_p_ci_builds_metadata_partition_id_default.rb13
-rw-r--r--db/post_migrate/20230411153310_cleanup_bigint_conversion_for_sent_notifications.rb16
-rw-r--r--db/schema_migrations/202304050723021
-rw-r--r--db/schema_migrations/202304111533101
-rw-r--r--db/structure.sql16
-rw-r--r--doc/administration/audit_events.md42
-rw-r--r--doc/api/runners.md6
-rw-r--r--doc/integration/jira/dvcs/index.md4
-rw-r--r--doc/user/application_security/container_scanning/index.md3
-rw-r--r--doc/user/application_security/dependency_scanning/index.md3
-rw-r--r--doc/user/project/web_ide_beta/index.md4
-rw-r--r--lib/api/ci/jobs.rb6
-rw-r--r--lib/api/entities/clusters/agent_authorization.rb13
-rw-r--r--lib/api/entities/clusters/agents/authorizations/ci_access.rb17
-rw-r--r--lib/api/internal/kubernetes.rb2
-rw-r--r--lib/gitlab/slug/environment.rb2
-rw-r--r--locale/gitlab.pot12
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb12
-rwxr-xr-xscripts/review_apps/k8s-resources-count-checks.sh9
-rw-r--r--spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb (renamed from spec/factories/clusters/agents/group_authorizations.rb)2
-rw-r--r--spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb (renamed from spec/factories/clusters/agents/project_authorizations.rb)2
-rw-r--r--spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb (renamed from spec/finders/clusters/agent_authorizations_finder_spec.rb)30
-rw-r--r--spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap4
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/experiments/show/components/experiment_header_spec.js55
-rw-r--r--spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js12
-rw-r--r--spec/frontend/search/sidebar/components/scope_navigation_spec.js18
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_spec.js11
-rw-r--r--spec/frontend/super_sidebar/components/groups_list_spec.js5
-rw-r--r--spec/frontend/super_sidebar/components/merge_request_menu_spec.js1
-rw-r--r--spec/frontend/super_sidebar/components/projects_list_spec.js5
-rw-r--r--spec/frontend/super_sidebar/components/super_sidebar_spec.js12
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js2
-rw-r--r--spec/frontend/super_sidebar/mock_data.js9
-rw-r--r--spec/frontend/whats_new/utils/notification_spec.js5
-rw-r--r--spec/helpers/sidebars_helper_spec.rb25
-rw-r--r--spec/lib/api/entities/clusters/agents/authorizations/ci_access_spec.rb (renamed from spec/lib/api/entities/clusters/agent_authorization_spec.rb)8
-rw-r--r--spec/lib/gitlab/slug/environment_spec.rb59
-rw-r--r--spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb21
-rw-r--r--spec/models/ci/pipeline_spec.rb4
-rw-r--r--spec/models/clusters/agent_spec.rb8
-rw-r--r--spec/models/clusters/agents/authorizations/ci_access/group_authorization_spec.rb (renamed from spec/models/clusters/agents/group_authorization_spec.rb)4
-rw-r--r--spec/models/clusters/agents/authorizations/ci_access/implicit_authorization_spec.rb (renamed from spec/models/clusters/agents/implicit_authorization_spec.rb)2
-rw-r--r--spec/models/clusters/agents/authorizations/ci_access/project_authorization_spec.rb (renamed from spec/models/clusters/agents/project_authorization_spec.rb)4
-rw-r--r--spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb21
-rw-r--r--spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb21
-rw-r--r--spec/models/note_spec.rb16
-rw-r--r--spec/requests/api/ci/jobs_spec.rb14
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb4
-rw-r--r--spec/scripts/review_apps/automated_cleanup_spec.rb23
-rw-r--r--spec/services/ci/generate_kubeconfig_service_spec.rb12
-rw-r--r--spec/services/clusters/agents/authorizations/ci_access/filter_service_spec.rb (renamed from spec/services/clusters/agents/filter_authorizations_service_spec.rb)16
-rw-r--r--spec/services/clusters/agents/authorizations/ci_access/refresh_service_spec.rb (renamed from spec/services/clusters/agents/refresh_authorization_service_spec.rb)34
-rw-r--r--spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb2
-rw-r--r--spec/support/finder_collection_allowlist.yml2
-rw-r--r--spec/support/rspec_order_todo.yml1
-rw-r--r--spec/tooling/lib/tooling/kubernetes_client_spec.rb177
-rw-r--r--spec/views/search/_results.html.haml_spec.rb6
-rw-r--r--spec/views/search/show.html.haml_spec.rb6
-rw-r--r--tooling/lib/tooling/kubernetes_client.rb39
122 files changed, 955 insertions, 891 deletions
diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 97462b9a4dd..3c9742f59e6 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -11,7 +11,7 @@ include:
- local: .gitlab/ci/package-and-test/rules.gitlab-ci.yml
- local: .gitlab/ci/package-and-test/variables.gitlab-ci.yml
- project: gitlab-org/quality/pipeline-common
- ref: 2.2.0
+ ref: 3.0.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
diff --git a/.gitlab/ci/review-apps/qa.gitlab-ci.yml b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
index 917184e0b5b..ab6737b8278 100644
--- a/.gitlab/ci/review-apps/qa.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
@@ -1,6 +1,6 @@
include:
- project: gitlab-org/quality/pipeline-common
- ref: 2.2.0
+ ref: 3.0.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml
index 06efefef2f1..f05e7ba35af 100644
--- a/.rubocop_todo/gitlab/strong_memoize_attr.yml
+++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml
@@ -180,7 +180,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/services/ci/pipelines/hook_service.rb'
- 'app/services/ci/queue/build_queue_service.rb'
- 'app/services/ci/update_build_state_service.rb'
- - 'app/services/clusters/agents/refresh_authorization_service.rb'
+ - 'app/services/clusters/agents/authorizations/ci_access/refresh_service.rb'
- 'app/services/clusters/integrations/prometheus_health_check_service.rb'
- 'app/services/concerns/alert_management/alert_processing.rb'
- 'app/services/concerns/incident_management/settings.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index a59997afc55..9f11c94f242 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -105,7 +105,7 @@ Layout/LineLength:
- 'app/controllers/users_controller.rb'
- 'app/finders/analytics/cycle_analytics/stage_finder.rb'
- 'app/finders/ci/runners_finder.rb'
- - 'app/finders/clusters/agent_authorizations_finder.rb'
+ - 'app/finders/clusters/agents/authorizations/ci_access/finder.rb'
- 'app/finders/group_descendants_finder.rb'
- 'app/finders/group_members_finder.rb'
- 'app/finders/group_projects_finder.rb'
@@ -507,6 +507,7 @@ Layout/LineLength:
- 'app/services/ci/runners/register_runner_service.rb'
- 'app/services/ci/runners/unregister_runner_service.rb'
- 'app/services/clusters/agent_tokens/create_service.rb'
+ - 'app/services/clusters/agents/authorizations/ci_access/refresh_service.rb'
- 'app/services/clusters/agents/delete_service.rb'
- 'app/services/clusters/build_kubernetes_namespace_service.rb'
- 'app/services/clusters/integrations/create_service.rb'
@@ -2038,7 +2039,7 @@ Layout/LineLength:
- 'ee/spec/models/ci/minutes/namespace_monthly_usage_spec.rb'
- 'ee/spec/models/ci/minutes/project_monthly_usage_spec.rb'
- 'ee/spec/models/ci/pipeline_spec.rb'
- - 'ee/spec/models/concerns/ee/clusters/agents/authorization_config_scopes_spec.rb'
+ - 'ee/spec/models/concerns/ee/clusters/agents/authorizations/ci_access/config_scopes_spec.rb'
- 'ee/spec/models/concerns/ee/issuable_spec.rb'
- 'ee/spec/models/concerns/ee/noteable_spec.rb'
- 'ee/spec/models/concerns/ee/project_security_scanners_information_spec.rb'
@@ -3516,6 +3517,8 @@ Layout/LineLength:
- 'spec/factories/ci/job_artifacts.rb'
- 'spec/factories/ci/pipelines.rb'
- 'spec/factories/ci/reports/codequality_degradations.rb'
+ - 'spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb'
+ - 'spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb'
- 'spec/factories/container_repositories.rb'
- 'spec/factories/dependency_proxy.rb'
- 'spec/factories/deployments.rb'
@@ -3744,6 +3747,7 @@ Layout/LineLength:
- 'spec/finders/ci/pipelines_finder_spec.rb'
- 'spec/finders/ci/pipelines_for_merge_request_finder_spec.rb'
- 'spec/finders/ci/runners_finder_spec.rb'
+ - 'spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb'
- 'spec/finders/clusters/agent_authorizations_finder_spec.rb'
- 'spec/finders/clusters_finder_spec.rb'
- 'spec/finders/deploy_tokens/tokens_finder_spec.rb'
@@ -4570,7 +4574,7 @@ Layout/LineLength:
- 'spec/models/concerns/cache_markdown_field_spec.rb'
- 'spec/models/concerns/cacheable_attributes_spec.rb'
- 'spec/models/concerns/ci/artifactable_spec.rb'
- - 'spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb'
+ - 'spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb'
- 'spec/models/concerns/deployment_platform_spec.rb'
- 'spec/models/concerns/group_descendant_spec.rb'
- 'spec/models/concerns/id_in_ordered_spec.rb'
@@ -5020,6 +5024,7 @@ Layout/LineLength:
- 'spec/services/ci/test_failure_history_service_spec.rb'
- 'spec/services/ci/unlock_artifacts_service_spec.rb'
- 'spec/services/ci/update_pending_build_service_spec.rb'
+ - 'spec/services/clusters/agents/authorizations/ci_access/filter_service_spec.rb'
- 'spec/services/clusters/create_service_spec.rb'
- 'spec/services/clusters/integrations/prometheus_health_check_service_spec.rb'
- 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index 63b24a04c56..a7ec2fcd55a 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -181,7 +181,7 @@ RSpec/ContextWording:
- 'ee/spec/finders/dast_site_profiles_finder_spec.rb'
- 'ee/spec/finders/dast_site_validations_finder_spec.rb'
- 'ee/spec/finders/ee/alert_management/http_integrations_finder_spec.rb'
- - 'ee/spec/finders/ee/clusters/agent_authorizations_finder_spec.rb'
+ - 'ee/spec/finders/ee/clusters/agents/authorizations/ci_access/finder_spec.rb'
- 'ee/spec/finders/ee/clusters/agents_finder_spec.rb'
- 'ee/spec/finders/ee/group_members_finder_spec.rb'
- 'ee/spec/finders/ee/namespaces/projects_finder_spec.rb'
@@ -1343,6 +1343,7 @@ RSpec/ContextWording:
- 'spec/finders/ci/pipelines_finder_spec.rb'
- 'spec/finders/ci/runners_finder_spec.rb'
- 'spec/finders/cluster_ancestors_finder_spec.rb'
+ - 'spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb'
- 'spec/finders/clusters/agent_authorizations_finder_spec.rb'
- 'spec/finders/clusters/agents_finder_spec.rb'
- 'spec/finders/clusters/kubernetes_namespace_finder_spec.rb'
@@ -1528,7 +1529,7 @@ RSpec/ContextWording:
- 'spec/initializers/validate_database_config_spec.rb'
- 'spec/lib/api/entities/application_setting_spec.rb'
- 'spec/lib/api/entities/basic_project_details_spec.rb'
- - 'spec/lib/api/entities/clusters/agent_authorization_spec.rb'
+ - 'spec/lib/api/entities/clusters/agents/authorizations/ci_access_spec.rb'
- 'spec/lib/api/entities/nuget/dependency_group_spec.rb'
- 'spec/lib/api/entities/user_spec.rb'
- 'spec/lib/api/every_api_endpoint_spec.rb'
@@ -2685,7 +2686,7 @@ RSpec/ContextWording:
- 'spec/services/ci/update_pending_build_service_spec.rb'
- 'spec/services/clusters/agent_tokens/track_usage_service_spec.rb'
- 'spec/services/clusters/agents/delete_expired_events_service_spec.rb'
- - 'spec/services/clusters/agents/refresh_authorization_service_spec.rb'
+ - 'spec/services/clusters/agents/authorizations/ci_access/refresh_service_spec.rb'
- 'spec/services/clusters/build_kubernetes_namespace_service_spec.rb'
- 'spec/services/clusters/create_service_spec.rb'
- 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index 5790af0ac12..c4b8c206433 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -4544,7 +4544,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb'
- 'spec/lib/gitlab/slash_commands/presenters/run_spec.rb'
- 'spec/lib/gitlab/slash_commands/run_spec.rb'
- - 'spec/lib/gitlab/slug/environment_spec.rb'
- 'spec/lib/gitlab/snippet_search_results_spec.rb'
- 'spec/lib/gitlab/sourcegraph_spec.rb'
- 'spec/lib/gitlab/spamcheck/client_spec.rb'
@@ -5239,7 +5238,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/namespaces/user_namespace_spec.rb'
- 'spec/models/network/graph_spec.rb'
- 'spec/models/note_diff_file_spec.rb'
- - 'spec/models/note_spec.rb'
- 'spec/models/notification_setting_spec.rb'
- 'spec/models/oauth_access_grant_spec.rb'
- 'spec/models/oauth_access_token_spec.rb'
diff --git a/.rubocop_todo/style/percent_literal_delimiters.yml b/.rubocop_todo/style/percent_literal_delimiters.yml
index cd15e2aa858..b3fbf73a75f 100644
--- a/.rubocop_todo/style/percent_literal_delimiters.yml
+++ b/.rubocop_todo/style/percent_literal_delimiters.yml
@@ -54,7 +54,7 @@ Style/PercentLiteralDelimiters:
- 'app/models/ci/pipeline.rb'
- 'app/models/clusters/platforms/kubernetes.rb'
- 'app/models/commit.rb'
- - 'app/models/concerns/clusters/agents/authorization_config_scopes.rb'
+ - 'app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb'
- 'app/models/concerns/diff_positionable_note.rb'
- 'app/models/concerns/enums/prometheus_metric.rb'
- 'app/models/concerns/issuable.rb'
diff --git a/.rubocop_todo/style/string_concatenation.yml b/.rubocop_todo/style/string_concatenation.yml
index 8e0858e982c..8209781e78a 100644
--- a/.rubocop_todo/style/string_concatenation.yml
+++ b/.rubocop_todo/style/string_concatenation.yml
@@ -121,7 +121,6 @@ Style/StringConcatenation:
- 'lib/gitlab/route_map.rb'
- 'lib/gitlab/sanitizers/exception_message.rb'
- 'lib/gitlab/sidekiq_logging/json_formatter.rb'
- - 'lib/gitlab/slug/environment.rb'
- 'lib/gitlab/sql/set_operator.rb'
- 'lib/gitlab/ssh_public_key.rb'
- 'lib/gitlab/throttle.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index d91a6d82185..d906aafc5a7 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-9255b4522513ee91d7fef535137d57deb498bbf8
+28c0539251cf00a675b78e987ff30b7741425653
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index 0251ffe28f9..2f2b2ed1a90 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -332,7 +332,7 @@ export default {
<template>
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue
new file mode 100644
index 00000000000..5b840a5ed43
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue
@@ -0,0 +1,47 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
+import { __ } from '~/locale';
+import { visitUrl } from '~/lib/utils/url_utility';
+
+export default {
+ name: 'ExperimentHeader',
+ components: {
+ DeleteButton,
+ GlButton,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ deleteInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ methods: {
+ downloadCsv() {
+ const currentPath = window.location.pathname;
+ const currentSearch = window.location.search;
+
+ visitUrl(`${currentPath}.csv${currentSearch}`);
+ },
+ },
+ i18n: {
+ downloadAsCsvLabel: __('Download as CSV'),
+ },
+};
+</script>
+
+<template>
+ <div class="detail-page-header gl-flex-wrap-wrap">
+ <div class="detail-page-header-body">
+ <h1 class="page-title gl-font-size-h-display flex-fill">{{ title }}</h1>
+
+ <gl-button @click="downloadCsv">{{ $options.i18n.downloadAsCsvLabel }}</gl-button>
+
+ <delete-button v-bind="deleteInfo" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
index 40b9e0723e9..acb5fc7cad2 100644
--- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
@@ -12,7 +12,7 @@ import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue';
import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue';
-import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
+import ExperimentHeader from './components/experiment_header.vue';
import {
LIST_KEY_CREATED_AT,
BASE_SORT_FIELDS,
@@ -31,7 +31,7 @@ export default {
IncubationAlert,
RegistrySearch,
KeysetPagination,
- DeleteButton,
+ ExperimentHeader,
},
props: {
experiment: {
@@ -130,6 +130,14 @@ export default {
hasItems() {
return this.candidates.length > 0;
},
+ deleteButtonInfo() {
+ return {
+ deletePath: this.experiment.path,
+ deleteConfirmationText: translations.DELETE_EXPERIMENT_CONFIRMATION_MESSAGE,
+ actionPrimaryText: translations.DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL,
+ modalTitle: translations.DELETE_EXPERIMENT_MODAL_TITLE,
+ };
+ },
},
methods: {
submitFilters() {
@@ -163,20 +171,7 @@ export default {
:link-to-feedback-issue="$options.constants.FEATURE_FEEDBACK_ISSUE"
/>
- <div class="detail-page-header gl-flex-wrap-wrap">
- <div class="detail-page-header-body">
- <h1 class="page-title gl-font-size-h-display flex-fill">
- {{ experiment.name }}
- </h1>
-
- <delete-button
- :delete-path="experiment.path"
- :delete-confirmation-text="$options.i18n.DELETE_EXPERIMENT_CONFIRMATION_MESSAGE"
- :action-primary-text="$options.i18n.DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL"
- :modal-title="$options.i18n.DELETE_EXPERIMENT_MODAL_TITLE"
- />
- </div>
- </div>
+ <experiment-header :title="experiment.name" :delete-info="deleteButtonInfo" />
<registry-search
:filters="filters"
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
index 02a3870f499..1c81f652387 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -22,7 +22,9 @@ export default {
...mapState(['navigation', 'urlQuery']),
},
created() {
- this.fetchSidebarCount();
+ if (this.urlQuery?.search) {
+ this.fetchSidebarCount();
+ }
},
methods: {
...mapActions(['fetchSidebarCount']),
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
index 395629dc70c..f123494fba2 100644
--- a/app/assets/javascripts/search/sidebar/constants/index.js
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -12,7 +12,7 @@ export const NAV_LINK_DEFAULT_CLASSES = [
'gl-justify-content-space-between',
];
export const NAV_LINK_COUNT_DEFAULT_CLASSES = ['gl-font-sm', 'gl-font-weight-normal'];
-export const HR_DEFAULT_CLASSES = ['gl-my-5', 'gl-mx-5', 'gl-border-gray-100'];
+export const HR_DEFAULT_CLASSES = ['gl-m-5', 'gl-border-gray-100'];
export const ONLY_SHOW_MD = ['gl-display-none', 'gl-md-display-block'];
export const TRACKING_LABEL_CHECKBOX = 'Checkbox';
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher.vue b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
index 5c1cebe0195..fa9da6cef9d 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
@@ -150,7 +150,12 @@ export default {
{{ $options.i18n.switchTo }}
</div>
<ul :aria-label="$options.i18n.switchTo" class="gl-p-0">
- <nav-item v-for="item in persistentLinks" :key="item.link" :item="item" />
+ <nav-item
+ v-for="item in persistentLinks"
+ :key="item.link"
+ :item="item"
+ :link-classes="{ [item.link_classes]: item.link_classes }"
+ />
</ul>
</li>
<projects-list
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
index 451e12df697..e56ef9e410b 100644
--- a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
+++ b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
@@ -38,7 +38,7 @@ export default {
<button
v-collapse-toggle.context-switcher
type="button"
- class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8"
+ class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8"
>
<span
v-if="context.icon"
diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue
index eb256e4971b..4fa15f1cd76 100644
--- a/app/assets/javascripts/super_sidebar/components/groups_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/groups_list.vue
@@ -36,11 +36,14 @@ export default {
storageKey() {
return `${this.username}/frequent-groups`;
},
- viewAllItem() {
+ viewAllProps() {
return {
- link: this.viewAllLink,
- title: s__('Navigation|View all your groups'),
- icon: 'group',
+ item: {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all your groups'),
+ icon: 'group',
+ },
+ linkClasses: { 'dashboard-shortcuts-groups': true },
};
},
},
@@ -61,7 +64,7 @@ export default {
:search-results="searchResults"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</search-results>
<frequent-items-list
@@ -72,7 +75,7 @@ export default {
:pristine-text="$options.i18n.pristineText"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</frequent-items-list>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 3a3eb72a4a8..53698a808a7 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -146,7 +146,7 @@ export default {
<component
:is="elem"
v-bind="linkProps"
- class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-text-decoration-none!"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-mb-1 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none!"
:class="computedLinkClasses"
data-qa-selector="nav_item_link"
data-testid="nav-item-link"
diff --git a/app/assets/javascripts/super_sidebar/components/pinned_section.vue b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
index d1c0e757a91..193de143c2b 100644
--- a/app/assets/javascripts/super_sidebar/components/pinned_section.vue
+++ b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
@@ -60,7 +60,7 @@ export default {
<section class="gl-mx-2">
<a
href="#"
- class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-py-3 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-text-decoration-none!"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-py-3 gl-px-0 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none!"
@click.prevent="expanded = !expanded"
>
<div class="gl-flex-shrink-0 gl-w-6 gl-mx-3">
diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue
index b7a29a78d5f..78860e35eb1 100644
--- a/app/assets/javascripts/super_sidebar/components/projects_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/projects_list.vue
@@ -36,11 +36,14 @@ export default {
storageKey() {
return `${this.username}/frequent-projects`;
},
- viewAllItem() {
+ viewAllProps() {
return {
- link: this.viewAllLink,
- title: s__('Navigation|View all your projects'),
- icon: 'project',
+ item: {
+ link: this.viewAllLink,
+ title: s__('Navigation|View all your projects'),
+ icon: 'project',
+ },
+ linkClasses: { 'dashboard-shortcuts-projects': true },
};
},
},
@@ -62,7 +65,7 @@ export default {
:search-results="searchResults"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</search-results>
<frequent-items-list
@@ -73,7 +76,7 @@ export default {
:pristine-text="$options.i18n.pristineText"
>
<template #view-all-items>
- <nav-item :item="viewAllItem" />
+ <nav-item v-bind="viewAllProps" />
</template>
</frequent-items-list>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index 302b6a9d4b0..2a95d2c37c4 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -108,5 +108,14 @@ export default {
</div>
</div>
</aside>
+ <a
+ v-for="shortcutLink in sidebarData.shortcut_links"
+ :key="shortcutLink.href"
+ :href="shortcutLink.href"
+ :class="shortcutLink.css_class"
+ class="gl-display-none"
+ >
+ {{ shortcutLink.title }}
+ </a>
</div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index 498c082ddb2..b69ebc6be17 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -137,7 +137,7 @@ export default {
<div class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2">
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.issues"
- class="gl-flex-basis-third"
+ class="gl-flex-basis-third dashboard-shortcuts-issues"
icon="issues"
:count="sidebarData.assigned_open_issues_count"
:href="sidebarData.issues_dashboard_path"
@@ -165,7 +165,7 @@ export default {
</merge-request-menu>
<counter
v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.todoList"
- class="gl-flex-basis-third"
+ class="gl-flex-basis-third shortcuts-todos"
icon="todo-done"
:count="sidebarData.todos_pending_count"
href="/dashboard/todos"
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 0d18835ac0f..22c6fb04d3b 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -8,7 +8,7 @@ $search-input-field-x-min-width: 200px;
min-height: $header-height;
border: 0;
position: fixed;
- top: 0;
+ top: $calc-application-bars-height;
left: 0;
right: 0;
border-radius: 0;
@@ -479,11 +479,6 @@ $search-input-field-x-min-width: 200px;
visibility: visible;
}
-.with-performance-bar .navbar-gitlab,
-.with-performance-bar .fixed-top {
- top: $performance-bar-height;
-}
-
.navbar-empty {
justify-content: center;
height: $header-height;
diff --git a/app/assets/stylesheets/framework/system_messages.scss b/app/assets/stylesheets/framework/system_messages.scss
index db59a482c64..946a241e6dd 100644
--- a/app/assets/stylesheets/framework/system_messages.scss
+++ b/app/assets/stylesheets/framework/system_messages.scss
@@ -36,27 +36,6 @@
}
}
-// System Header
-.with-system-header {
- // main navigation
- // login page
- .navbar-gitlab,
- .fixed-top {
- top: $system-header-height;
- }
-
- // Performance Bar
- // System Header
- &.with-performance-bar {
- // main navigation
- header.navbar-gitlab,
- .fixed-top {
- top: $performance-bar-height + $system-header-height;
- }
-
- }
-}
-
// System Footer
.with-system-footer {
// navless pages' footer eg: login page
diff --git a/app/assets/stylesheets/page_bundles/design_management.scss b/app/assets/stylesheets/page_bundles/design_management.scss
index 143682e1cd7..f56eb4ae6fb 100644
--- a/app/assets/stylesheets/page_bundles/design_management.scss
+++ b/app/assets/stylesheets/page_bundles/design_management.scss
@@ -20,10 +20,7 @@ $t-gray-a-16-design-pin: rgba($black, 0.16);
.design-detail {
background-color: rgba($modal-backdrop-bg, $modal-backdrop-opacity);
-
- .with-performance-bar & {
- top: 35px;
- }
+ bottom: $calc-application-footer-height;
.comment-indicator {
border-radius: 50%;
diff --git a/app/assets/stylesheets/page_bundles/search.scss b/app/assets/stylesheets/page_bundles/search.scss
index cde570cfb0f..d37e87b5cd5 100644
--- a/app/assets/stylesheets/page_bundles/search.scss
+++ b/app/assets/stylesheets/page_bundles/search.scss
@@ -21,18 +21,18 @@ $border-radius-medium: 3px;
}
}
+.language-filter-checkbox {
+ .custom-control-label {
+ flex-grow: 1;
+ }
+}
+
.search-sidebar {
@include media-breakpoint-up(md) {
min-width: $search-sidebar-min-width;
max-width: $search-sidebar-max-width;
}
- .language-filter-checkbox {
- .custom-control-label {
- flex-grow: 1;
- }
- }
-
.language-filter-max-height {
max-height: $language-filter-max-height;
}
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index de2a2ddcf32..5219cd62775 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -750,7 +750,7 @@ kbd {
min-height: var(--header-height, 48px);
border: 0;
position: fixed;
- top: 0;
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
left: 0;
right: 0;
border-radius: 0;
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index e0a71a1c306..16bf2c20bbc 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -750,7 +750,7 @@ kbd {
min-height: var(--header-height, 48px);
border: 0;
position: fixed;
- top: 0;
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
left: 0;
right: 0;
border-radius: 0;
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 3663c97f41a..fcdcab5caeb 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -769,6 +769,9 @@ svg {
fill: currentColor;
}
+.fixed-top {
+ top: calc(var(--system-header-height) + var(--performance-bar-height));
+}
.gl-display-flex {
display: flex;
}
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 66c543aa654..e5f99879166 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -39,6 +39,12 @@
.border-radius-small { border-radius: $border-radius-small; }
.box-shadow-default { box-shadow: 0 2px 4px 0 $black-transparent; }
+// Override Bootstrap class with offset for system-header and
+// performance bar when present
+.fixed-top {
+ top: $calc-application-bars-height;
+}
+
.gl-children-ml-sm-3 > * {
@include media-breakpoint-up(sm) {
@include gl-ml-3;
diff --git a/app/finders/clusters/agent_authorizations_finder.rb b/app/finders/clusters/agent_authorizations_finder.rb
deleted file mode 100644
index 70c0868cc7f..00000000000
--- a/app/finders/clusters/agent_authorizations_finder.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- class AgentAuthorizationsFinder
- def initialize(project)
- @project = project
- end
-
- def execute
- # closest, most-specific authorization for a given agent wins
- (project_authorizations + implicit_authorizations + group_authorizations)
- .uniq(&:agent_id)
- end
-
- private
-
- attr_reader :project
-
- def implicit_authorizations
- project.cluster_agents.map do |agent|
- Clusters::Agents::ImplicitAuthorization.new(agent: agent)
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def project_authorizations
- namespace_ids = project.group ? all_namespace_ids : project.namespace_id
-
- Clusters::Agents::ProjectAuthorization
- .where(project_id: project.id)
- .joins(agent: :project)
- .preload(agent: :project)
- .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
- .with_available_ci_access_fields(project)
- .to_a
- end
-
- def group_authorizations
- return [] unless project.group
-
- authorizations = Clusters::Agents::GroupAuthorization.arel_table
-
- ordered_ancestors_cte = Gitlab::SQL::CTE.new(
- :ordered_ancestors,
- project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
- )
-
- cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
- authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
- ).join_sources
-
- Clusters::Agents::GroupAuthorization
- .with(ordered_ancestors_cte.to_arel)
- .joins(cte_join_sources)
- .joins(agent: :project)
- .with_available_ci_access_fields(project)
- .where(projects: { namespace_id: all_namespace_ids })
- .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
- .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
- .preload(agent: :project)
- .to_a
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def all_namespace_ids
- project.root_ancestor.self_and_descendants.select(:id)
- end
- end
-end
diff --git a/app/finders/clusters/agents/authorizations/ci_access/finder.rb b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
new file mode 100644
index 00000000000..97d378669a4
--- /dev/null
+++ b/app/finders/clusters/agents/authorizations/ci_access/finder.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class Finder
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ # closest, most-specific authorization for a given agent wins
+ (project_authorizations + implicit_authorizations + group_authorizations)
+ .uniq(&:agent_id)
+ end
+
+ private
+
+ attr_reader :project
+
+ def implicit_authorizations
+ project.cluster_agents.map do |agent|
+ Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: agent)
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def project_authorizations
+ namespace_ids = project.group ? all_namespace_ids : project.namespace_id
+
+ Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
+ .where(project_id: project.id)
+ .joins(agent: :project)
+ .preload(agent: :project)
+ .where(cluster_agents: { projects: { namespace_id: namespace_ids } })
+ .with_available_ci_access_fields(project)
+ .to_a
+ end
+
+ def group_authorizations
+ return [] unless project.group
+
+ authorizations = Clusters::Agents::Authorizations::CiAccess::GroupAuthorization.arel_table
+
+ ordered_ancestors_cte = Gitlab::SQL::CTE.new(
+ :ordered_ancestors,
+ project.group.self_and_ancestors(hierarchy_order: :asc).reselect(:id)
+ )
+
+ cte_join_sources = authorizations.join(ordered_ancestors_cte.table).on(
+ authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
+ ).join_sources
+
+ Clusters::Agents::Authorizations::CiAccess::GroupAuthorization
+ .with(ordered_ancestors_cte.to_arel)
+ .joins(cte_join_sources)
+ .joins(agent: :project)
+ .with_available_ci_access_fields(project)
+ .where(projects: { namespace_id: all_namespace_ids })
+ .order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
+ .select('DISTINCT ON (agent_id) agent_group_authorizations.*')
+ .preload(agent: :project)
+ .to_a
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def all_namespace_ids
+ project.root_ancestor.self_and_descendants.select(:id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index a6eddb4d529..8af4204e5e1 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -89,7 +89,8 @@ module SidebarsHelper
panel_type: panel_type,
update_pins_url: pins_url,
is_impersonating: impersonating?,
- stop_impersonation_path: admin_impersonation_path
+ stop_impersonation_path: admin_impersonation_path,
+ shortcut_links: shortcut_links
}
end
@@ -180,7 +181,8 @@ module SidebarsHelper
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_assigned',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-merge_requests'
}
},
{
@@ -190,7 +192,8 @@ module SidebarsHelper
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_to_review',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-review_requests'
}
}
]
@@ -334,6 +337,26 @@ module SidebarsHelper
def impersonating?
!!session[:impersonator_id]
end
+
+ def shortcut_links
+ [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ }
+ ]
+ end
end
SidebarsHelper.prepend_mod_with('SidebarsHelper')
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index 4b2be446fe3..b98fdba44ec 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -11,9 +11,11 @@ module Ci
include ChronicDurationAttribute
include Gitlab::Utils::StrongMemoize
include IgnorableColumns
+ include SafelyChangeColumnDefault
self.table_name = 'p_ci_builds_metadata'
self.primary_key = 'id'
+ columns_changing_default :partition_id
partitionable scope: :build
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 8c7b0193199..f5a2911fc59 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -1334,7 +1334,7 @@ module Ci
def cluster_agent_authorizations
strong_memoize(:cluster_agent_authorizations) do
- ::Clusters::AgentAuthorizationsFinder.new(project).execute
+ ::Clusters::Agents::Authorizations::CiAccess::Finder.new(project).execute
end
end
diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb
index 3478bb69707..4e2de06577d 100644
--- a/app/models/clusters/agent.rb
+++ b/app/models/clusters/agent.rb
@@ -12,11 +12,11 @@ module Clusters
has_many :agent_tokens, -> { order_last_used_at_desc }, class_name: 'Clusters::AgentToken', inverse_of: :agent
- has_many :group_authorizations, class_name: 'Clusters::Agents::GroupAuthorization'
- has_many :authorized_groups, class_name: '::Group', through: :group_authorizations, source: :group
+ has_many :ci_access_group_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::GroupAuthorization'
+ has_many :ci_access_authorized_groups, class_name: '::Group', through: :ci_access_group_authorizations, source: :group
- has_many :project_authorizations, class_name: 'Clusters::Agents::ProjectAuthorization'
- has_many :authorized_projects, class_name: '::Project', through: :project_authorizations, source: :project
+ has_many :ci_access_project_authorizations, class_name: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization'
+ has_many :ci_access_authorized_projects, class_name: '::Project', through: :ci_access_project_authorizations, source: :project
has_many :activity_events, -> { in_timeline_order }, class_name: 'Clusters::Agents::ActivityEvent', inverse_of: :agent
diff --git a/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb
new file mode 100644
index 00000000000..4261fd6570f
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/group_authorization.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class GroupAuthorization < ApplicationRecord
+ include ConfigScopes
+
+ self.table_name = 'agent_group_authorizations'
+
+ belongs_to :agent, class_name: 'Clusters::Agent', optional: false
+ belongs_to :group, class_name: '::Group', optional: false
+
+ validates :config, json_schema: { filename: 'clusters_agents_authorizations_ci_access_config' }
+
+ def config_project
+ agent.project
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb
new file mode 100644
index 00000000000..b996ae3f92b
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/implicit_authorization.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class ImplicitAuthorization
+ attr_reader :agent
+
+ delegate :id, to: :agent, prefix: true
+
+ def initialize(agent:)
+ @agent = agent
+ end
+
+ def config_project
+ agent.project
+ end
+
+ def config
+ {}
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb b/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb
new file mode 100644
index 00000000000..7742d109cdb
--- /dev/null
+++ b/app/models/clusters/agents/authorizations/ci_access/project_authorization.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class ProjectAuthorization < ApplicationRecord
+ include ConfigScopes
+
+ self.table_name = 'agent_project_authorizations'
+
+ belongs_to :agent, class_name: 'Clusters::Agent', optional: false
+ belongs_to :project, class_name: '::Project', optional: false
+
+ validates :config, json_schema: { filename: 'clusters_agents_authorizations_ci_access_config' }
+
+ def config_project
+ agent.project
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/agents/group_authorization.rb b/app/models/clusters/agents/group_authorization.rb
deleted file mode 100644
index 58ba874ab53..00000000000
--- a/app/models/clusters/agents/group_authorization.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class GroupAuthorization < ApplicationRecord
- include ::Clusters::Agents::AuthorizationConfigScopes
-
- self.table_name = 'agent_group_authorizations'
-
- belongs_to :agent, class_name: 'Clusters::Agent', optional: false
- belongs_to :group, class_name: '::Group', optional: false
-
- validates :config, json_schema: { filename: 'cluster_agent_authorization_configuration' }
-
- def config_project
- agent.project
- end
- end
- end
-end
diff --git a/app/models/clusters/agents/implicit_authorization.rb b/app/models/clusters/agents/implicit_authorization.rb
deleted file mode 100644
index a365ccdc568..00000000000
--- a/app/models/clusters/agents/implicit_authorization.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class ImplicitAuthorization
- attr_reader :agent
-
- delegate :id, to: :agent, prefix: true
-
- def initialize(agent:)
- @agent = agent
- end
-
- def config_project
- agent.project
- end
-
- def config
- {}
- end
- end
- end
-end
diff --git a/app/models/clusters/agents/project_authorization.rb b/app/models/clusters/agents/project_authorization.rb
deleted file mode 100644
index b9b44741936..00000000000
--- a/app/models/clusters/agents/project_authorization.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class ProjectAuthorization < ApplicationRecord
- include ::Clusters::Agents::AuthorizationConfigScopes
-
- self.table_name = 'agent_project_authorizations'
-
- belongs_to :agent, class_name: 'Clusters::Agent', optional: false
- belongs_to :project, class_name: '::Project', optional: false
-
- validates :config, json_schema: { filename: 'cluster_agent_authorization_configuration' }
-
- def config_project
- agent.project
- end
- end
- end
-end
diff --git a/app/models/concerns/clusters/agents/authorization_config_scopes.rb b/app/models/concerns/clusters/agents/authorization_config_scopes.rb
deleted file mode 100644
index 0a0406c3389..00000000000
--- a/app/models/concerns/clusters/agents/authorization_config_scopes.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- module AuthorizationConfigScopes
- extend ActiveSupport::Concern
-
- included do
- scope :with_available_ci_access_fields, ->(project) {
- where("config->'access_as' IS NULL")
- .or(where("config->'access_as' = '{}'"))
- .or(where("config->'access_as' ?| array[:fields]", fields: available_ci_access_fields(project)))
- }
- end
-
- class_methods do
- def available_ci_access_fields(_project)
- %w(agent)
- end
- end
- end
- end
-end
-
-Clusters::Agents::AuthorizationConfigScopes.prepend_mod
diff --git a/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
new file mode 100644
index 00000000000..eef68bfd349
--- /dev/null
+++ b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ module ConfigScopes
+ extend ActiveSupport::Concern
+
+ included do
+ scope :with_available_ci_access_fields, ->(project) {
+ where("config->'access_as' IS NULL")
+ .or(where("config->'access_as' = '{}'"))
+ .or(where("config->'access_as' ?| array[:fields]", fields: available_ci_access_fields(project)))
+ }
+ end
+
+ class_methods do
+ def available_ci_access_fields(_project)
+ %w(agent)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+Clusters::Agents::Authorizations::CiAccess::ConfigScopes.prepend_mod
diff --git a/app/services/ci/generate_kubeconfig_service.rb b/app/services/ci/generate_kubeconfig_service.rb
index 1c6aaa9d1ff..56e22a64529 100644
--- a/app/services/ci/generate_kubeconfig_service.rb
+++ b/app/services/ci/generate_kubeconfig_service.rb
@@ -41,7 +41,7 @@ module Ci
attr_reader :pipeline, :token, :environment, :template
def agent_authorizations
- ::Clusters::Agents::FilterAuthorizationsService.new(
+ ::Clusters::Agents::Authorizations::CiAccess::FilterService.new(
pipeline.cluster_agent_authorizations,
environment: environment
).execute
diff --git a/app/services/clusters/agents/authorizations/ci_access/filter_service.rb b/app/services/clusters/agents/authorizations/ci_access/filter_service.rb
new file mode 100644
index 00000000000..cd08aaa12d4
--- /dev/null
+++ b/app/services/clusters/agents/authorizations/ci_access/filter_service.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class FilterService
+ def initialize(authorizations, filter_params)
+ @authorizations = authorizations
+ @filter_params = filter_params
+
+ @environments_matcher = {}
+ end
+
+ def execute
+ filter_by_environment(authorizations)
+ end
+
+ private
+
+ attr_reader :authorizations, :filter_params
+
+ def filter_by_environment(auths)
+ return auths unless filter_by_environment?
+
+ auths.select do |auth|
+ next true if auth.config['environments'].blank?
+
+ auth.config['environments'].any? { |environment_pattern| matches_environment?(environment_pattern) }
+ end
+ end
+
+ def filter_by_environment?
+ filter_params.has_key?(:environment)
+ end
+
+ def environment_filter
+ @environment_filter ||= filter_params[:environment]
+ end
+
+ def matches_environment?(environment_pattern)
+ return false if environment_filter.nil?
+
+ environments_matcher(environment_pattern).match?(environment_filter)
+ end
+
+ def environments_matcher(environment_pattern)
+ @environments_matcher[environment_pattern] ||= ::Gitlab::Ci::EnvironmentMatcher.new(environment_pattern)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb b/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb
new file mode 100644
index 00000000000..047a0725a2c
--- /dev/null
+++ b/app/services/clusters/agents/authorizations/ci_access/refresh_service.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ module Authorizations
+ module CiAccess
+ class RefreshService
+ include Gitlab::Utils::StrongMemoize
+
+ AUTHORIZED_ENTITY_LIMIT = 100
+
+ delegate :project, to: :agent, private: true
+ delegate :root_ancestor, to: :project, private: true
+
+ def initialize(agent, config:)
+ @agent = agent
+ @config = config
+ end
+
+ def execute
+ refresh_projects!
+ refresh_groups!
+
+ true
+ end
+
+ private
+
+ attr_reader :agent, :config
+
+ def refresh_projects!
+ if allowed_project_configurations.present?
+ project_ids = allowed_project_configurations.map { |config| config.fetch(:project_id) }
+
+ agent.with_lock do
+ agent.ci_access_project_authorizations.upsert_all(allowed_project_configurations, unique_by: [:agent_id, :project_id])
+ agent.ci_access_project_authorizations.where.not(project_id: project_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
+ end
+ else
+ agent.ci_access_project_authorizations.delete_all(:delete_all)
+ end
+ end
+
+ def refresh_groups!
+ if allowed_group_configurations.present?
+ group_ids = allowed_group_configurations.map { |config| config.fetch(:group_id) }
+
+ agent.with_lock do
+ agent.ci_access_group_authorizations.upsert_all(allowed_group_configurations, unique_by: [:agent_id, :group_id])
+ agent.ci_access_group_authorizations.where.not(group_id: group_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
+ end
+ else
+ agent.ci_access_group_authorizations.delete_all(:delete_all)
+ end
+ end
+
+ def allowed_project_configurations
+ strong_memoize(:allowed_project_configurations) do
+ project_entries = extract_config_entries(entity: 'projects')
+
+ if project_entries
+ allowed_projects.where_full_path_in(project_entries.keys).map do |project|
+ { project_id: project.id, config: project_entries[project.full_path.downcase] }
+ end
+ end
+ end
+ end
+
+ def allowed_group_configurations
+ strong_memoize(:allowed_group_configurations) do
+ group_entries = extract_config_entries(entity: 'groups')
+
+ if group_entries
+ allowed_groups.where_full_path_in(group_entries.keys).map do |group|
+ { group_id: group.id, config: group_entries[group.full_path.downcase] }
+ end
+ end
+ end
+ end
+
+ def extract_config_entries(entity:)
+ config.dig('ci_access', entity)
+ &.first(AUTHORIZED_ENTITY_LIMIT)
+ &.index_by { |config| config.delete('id').downcase }
+ end
+
+ def allowed_projects
+ root_ancestor.all_projects
+ end
+
+ def allowed_groups
+ if group_root_ancestor?
+ root_ancestor.self_and_descendants
+ else
+ ::Group.none
+ end
+ end
+
+ def group_root_ancestor?
+ root_ancestor.group_namespace?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/agents/authorize_proxy_user_service.rb b/app/services/clusters/agents/authorize_proxy_user_service.rb
index ec6645b2db4..ba90d61a7ef 100644
--- a/app/services/clusters/agents/authorize_proxy_user_service.rb
+++ b/app/services/clusters/agents/authorize_proxy_user_service.rb
@@ -57,7 +57,7 @@ module Clusters
def authorized_projects(user_access)
strong_memoize_with(:authorized_projects, user_access) do
user_access.fetch(:projects, [])
- .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .first(::Clusters::Agents::Authorizations::CiAccess::RefreshService::AUTHORIZED_ENTITY_LIMIT)
.map { |project| ::Project.find_by_full_path(project[:id]) }
.select { |project| current_user.can?(:use_k8s_proxies, project) }
end
@@ -66,7 +66,7 @@ module Clusters
def authorized_groups(user_access)
strong_memoize_with(:authorized_groups, user_access) do
user_access.fetch(:groups, [])
- .first(::Clusters::Agents::RefreshAuthorizationService::AUTHORIZED_ENTITY_LIMIT)
+ .first(::Clusters::Agents::Authorizations::CiAccess::RefreshService::AUTHORIZED_ENTITY_LIMIT)
.map { |group| ::Group.find_by_full_path(group[:id]) }
.select { |group| current_user.can?(:use_k8s_proxies, group) }
end
diff --git a/app/services/clusters/agents/filter_authorizations_service.rb b/app/services/clusters/agents/filter_authorizations_service.rb
deleted file mode 100644
index 68517ceec04..00000000000
--- a/app/services/clusters/agents/filter_authorizations_service.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class FilterAuthorizationsService
- def initialize(authorizations, filter_params)
- @authorizations = authorizations
- @filter_params = filter_params
-
- @environments_matcher = {}
- end
-
- def execute
- filter_by_environment(authorizations)
- end
-
- private
-
- attr_reader :authorizations, :filter_params
-
- def filter_by_environment(auths)
- return auths unless filter_by_environment?
-
- auths.select do |auth|
- next true if auth.config['environments'].blank?
-
- auth.config['environments'].any? { |environment_pattern| matches_environment?(environment_pattern) }
- end
- end
-
- def filter_by_environment?
- filter_params.has_key?(:environment)
- end
-
- def environment_filter
- @environment_filter ||= filter_params[:environment]
- end
-
- def matches_environment?(environment_pattern)
- return false if environment_filter.nil?
-
- environments_matcher(environment_pattern).match?(environment_filter)
- end
-
- def environments_matcher(environment_pattern)
- @environments_matcher[environment_pattern] ||= ::Gitlab::Ci::EnvironmentMatcher.new(environment_pattern)
- end
- end
- end
-end
diff --git a/app/services/clusters/agents/refresh_authorization_service.rb b/app/services/clusters/agents/refresh_authorization_service.rb
deleted file mode 100644
index 23ececef6a1..00000000000
--- a/app/services/clusters/agents/refresh_authorization_service.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Agents
- class RefreshAuthorizationService
- include Gitlab::Utils::StrongMemoize
-
- AUTHORIZED_ENTITY_LIMIT = 100
-
- delegate :project, to: :agent, private: true
- delegate :root_ancestor, to: :project, private: true
-
- def initialize(agent, config:)
- @agent = agent
- @config = config
- end
-
- def execute
- refresh_projects!
- refresh_groups!
-
- true
- end
-
- private
-
- attr_reader :agent, :config
-
- def refresh_projects!
- if allowed_project_configurations.present?
- project_ids = allowed_project_configurations.map { |config| config.fetch(:project_id) }
-
- agent.with_lock do
- agent.project_authorizations.upsert_all(allowed_project_configurations, unique_by: [:agent_id, :project_id])
- agent.project_authorizations.where.not(project_id: project_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
- end
- else
- agent.project_authorizations.delete_all(:delete_all)
- end
- end
-
- def refresh_groups!
- if allowed_group_configurations.present?
- group_ids = allowed_group_configurations.map { |config| config.fetch(:group_id) }
-
- agent.with_lock do
- agent.group_authorizations.upsert_all(allowed_group_configurations, unique_by: [:agent_id, :group_id])
- agent.group_authorizations.where.not(group_id: group_ids).delete_all # rubocop: disable CodeReuse/ActiveRecord
- end
- else
- agent.group_authorizations.delete_all(:delete_all)
- end
- end
-
- def allowed_project_configurations
- strong_memoize(:allowed_project_configurations) do
- project_entries = extract_config_entries(entity: 'projects')
-
- if project_entries
- allowed_projects.where_full_path_in(project_entries.keys).map do |project|
- { project_id: project.id, config: project_entries[project.full_path.downcase] }
- end
- end
- end
- end
-
- def allowed_group_configurations
- strong_memoize(:allowed_group_configurations) do
- group_entries = extract_config_entries(entity: 'groups')
-
- if group_entries
- allowed_groups.where_full_path_in(group_entries.keys).map do |group|
- { group_id: group.id, config: group_entries[group.full_path.downcase] }
- end
- end
- end
- end
-
- def extract_config_entries(entity:)
- config.dig('ci_access', entity)
- &.first(AUTHORIZED_ENTITY_LIMIT)
- &.index_by { |config| config.delete('id').downcase }
- end
-
- def allowed_projects
- root_ancestor.all_projects
- end
-
- def allowed_groups
- if group_root_ancestor?
- root_ancestor.self_and_descendants
- else
- ::Group.none
- end
- end
-
- def group_root_ancestor?
- root_ancestor.group_namespace?
- end
- end
- end
-end
diff --git a/app/validators/json_schemas/cluster_agent_authorization_configuration.json b/app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json
index f3de0b7043b..f3de0b7043b 100644
--- a/app/validators/json_schemas/cluster_agent_authorization_configuration.json
+++ b/app/validators/json_schemas/clusters_agents_authorizations_ci_access_config.json
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 3280dcf2cd4..99558f61b25 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,9 +1,5 @@
-- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
-
= render_if_exists 'shared/promotions/promote_advanced_search'
-.results.gl-md-display-flex.gl-mt-0
- #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
- .gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
- = render partial: 'search/results_status' if @search_objects.present?
- = render partial: 'search/results_list'
+.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
+ = render partial: 'search/results_status' unless @search_objects.to_a.empty?
+ = render partial: 'search/results_list'
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 826d78c470d..934f59ea586 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -1,12 +1,14 @@
- @hide_top_links = true
- breadcrumb_title _('Search')
- page_title @search_term
+- nav 'search'
- if params[:group_id].present?
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
= hidden_field_tag :project_id, params[:project_id]
- group_attributes = @group&.attributes&.slice('id', 'name')&.merge(full_name: @group&.full_name)
- project_attributes = @project&.attributes&.slice('id', 'namespace_id', 'name')&.merge(name_with_namespace: @project&.name_with_namespace)
+- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
- if @search_results && !(@search_results.respond_to?(:failed?) && @search_results.failed?)
- if @search_service_presenter.without_count?
@@ -20,5 +22,7 @@
= render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "elasticsearch-enabled": @search_service_presenter.advanced_search_enabled?.to_s, "default-branch-name": @project&.default_branch } }
-- if @search_term
- = render 'search/results'
+.results.gl-md-display-flex.gl-mt-0
+ #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
+ - if @search_term
+ = render 'search/results'
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index eb20a65caf7..296fb69b83f 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -43,7 +43,6 @@
- dependency_firewall
- dependency_management
- dependency_proxy
-- dependency_scanning
- deployment_management
- design_management
- design_system
@@ -80,7 +79,6 @@
- interactive_application_security_testing
- internationalization
- kubernetes_management
-- license_compliance
- logging
- merge_trains
- metrics
@@ -123,6 +121,7 @@
- service_desk
- service_ping
- sm_provisioning
+- software_composition_analysis
- source_code_management
- static_application_security_testing
- subgroups
diff --git a/db/docs/agent_group_authorizations.yml b/db/docs/agent_group_authorizations.yml
index 61c8733383a..c300ed3ba08 100644
--- a/db/docs/agent_group_authorizations.yml
+++ b/db/docs/agent_group_authorizations.yml
@@ -1,7 +1,7 @@
---
table_name: agent_group_authorizations
classes:
-- Clusters::Agents::GroupAuthorization
+- Clusters::Agents::Authorizations::CiAccess::GroupAuthorization
feature_categories:
- kubernetes_management
description: Configuration for a group that is authorized to use a particular cluster agent
diff --git a/db/docs/agent_project_authorizations.yml b/db/docs/agent_project_authorizations.yml
index e595c84b5d5..98a74b9f9b7 100644
--- a/db/docs/agent_project_authorizations.yml
+++ b/db/docs/agent_project_authorizations.yml
@@ -1,7 +1,7 @@
---
table_name: agent_project_authorizations
classes:
-- Clusters::Agents::ProjectAuthorization
+- Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
feature_categories:
- kubernetes_management
description: Configuration for a project that is authorized to use a particular cluster agent
diff --git a/db/docs/pm_checkpoints.yml b/db/docs/pm_checkpoints.yml
index e360e8ad356..2e42077943d 100644
--- a/db/docs/pm_checkpoints.yml
+++ b/db/docs/pm_checkpoints.yml
@@ -3,7 +3,7 @@ table_name: pm_checkpoints
classes:
- PackageMetadata::Checkpoint
feature_categories:
-- license_compliance
+- software_composition_analysis
description: Tracks position of last synced file.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109713
milestone: '15.9'
diff --git a/db/docs/pm_licenses.yml b/db/docs/pm_licenses.yml
index 55ef2719cbc..31d9ae7a179 100644
--- a/db/docs/pm_licenses.yml
+++ b/db/docs/pm_licenses.yml
@@ -3,7 +3,7 @@ table_name: pm_licenses
classes:
- PackageMetadata::License
feature_categories:
- - license_compliance
+ - software_composition_analysis
description: Tracks licenses referenced by public package registries.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102794
milestone: '15.6'
diff --git a/db/docs/pm_package_version_licenses.yml b/db/docs/pm_package_version_licenses.yml
index 439162ecf9d..1e3f21c4383 100644
--- a/db/docs/pm_package_version_licenses.yml
+++ b/db/docs/pm_package_version_licenses.yml
@@ -3,7 +3,7 @@ table_name: pm_package_version_licenses
classes:
- PackageMetadata::PackageVersionLicense
feature_categories:
- - license_compliance
+ - software_composition_analysis
description: Tracks licenses under which a given package version has been published.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102794
milestone: '15.6'
diff --git a/db/docs/pm_package_versions.yml b/db/docs/pm_package_versions.yml
index 7b015ddc174..b216d58ce99 100644
--- a/db/docs/pm_package_versions.yml
+++ b/db/docs/pm_package_versions.yml
@@ -3,7 +3,7 @@ table_name: pm_package_versions
classes:
- PackageMetadata::PackageVersion
feature_categories:
-- license_compliance
+- software_composition_analysis
description: Tracks package versions served by public package registries.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102794
milestone: '15.6'
diff --git a/db/docs/pm_packages.yml b/db/docs/pm_packages.yml
index 35932b37990..b114e75791f 100644
--- a/db/docs/pm_packages.yml
+++ b/db/docs/pm_packages.yml
@@ -3,7 +3,7 @@ table_name: pm_packages
classes:
- PackageMetadata::Package
feature_categories:
-- license_compliance
+- software_composition_analysis
description: Tracks packages served by public package registries.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102794
milestone: '15.6'
diff --git a/db/docs/project_security_settings.yml b/db/docs/project_security_settings.yml
index 99a767978fb..af559d11164 100644
--- a/db/docs/project_security_settings.yml
+++ b/db/docs/project_security_settings.yml
@@ -3,7 +3,7 @@ table_name: project_security_settings
classes:
- ProjectSecuritySetting
feature_categories:
-- dependency_scanning
+- software_composition_analysis
- container_scanning
description: Project settings related to security features.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32577
diff --git a/db/docs/vulnerability_advisories.yml b/db/docs/vulnerability_advisories.yml
index 18029e784b5..6ce7f30aa7c 100644
--- a/db/docs/vulnerability_advisories.yml
+++ b/db/docs/vulnerability_advisories.yml
@@ -4,8 +4,7 @@ classes:
- Vulnerabilities::Advisory
feature_categories:
- container_scanning
-- dependency_scanning
-- license_compliance
+- software_composition_analysis
description: Stores vulnerability advisories
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95622
milestone: '15.4'
diff --git a/db/post_migrate/20230405072302_remove_p_ci_builds_metadata_partition_id_default.rb b/db/post_migrate/20230405072302_remove_p_ci_builds_metadata_partition_id_default.rb
new file mode 100644
index 00000000000..303210d85c7
--- /dev/null
+++ b/db/post_migrate/20230405072302_remove_p_ci_builds_metadata_partition_id_default.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class RemovePCiBuildsMetadataPartitionIdDefault < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ change_column_default :p_ci_builds_metadata, :partition_id, from: 100, to: nil
+ end
+
+ def down
+ change_column_default :p_ci_builds_metadata, :partition_id, from: nil, to: 100
+ end
+end
diff --git a/db/post_migrate/20230411153310_cleanup_bigint_conversion_for_sent_notifications.rb b/db/post_migrate/20230411153310_cleanup_bigint_conversion_for_sent_notifications.rb
new file mode 100644
index 00000000000..e5f690a0a5a
--- /dev/null
+++ b/db/post_migrate/20230411153310_cleanup_bigint_conversion_for_sent_notifications.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CleanupBigintConversionForSentNotifications < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ TABLE = :sent_notifications
+ COLUMNS = [:id]
+
+ def up
+ cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def down
+ restore_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+end
diff --git a/db/schema_migrations/20230405072302 b/db/schema_migrations/20230405072302
new file mode 100644
index 00000000000..cfa7bf7f175
--- /dev/null
+++ b/db/schema_migrations/20230405072302
@@ -0,0 +1 @@
+d93a103c002a536d11f75256f20e2b8708ec760286f65d89ab5abe446fe629d4 \ No newline at end of file
diff --git a/db/schema_migrations/20230411153310 b/db/schema_migrations/20230411153310
new file mode 100644
index 00000000000..14f317ccf08
--- /dev/null
+++ b/db/schema_migrations/20230411153310
@@ -0,0 +1 @@
+f4472433ac5b74296409a04790d64ed56551358c98428ebb2e5f15d2f3e2db31 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 4a656b18fec..b6e93ad1f95 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -309,15 +309,6 @@ BEGIN
END;
$$;
-CREATE FUNCTION trigger_7f4fcd5aa322() RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-BEGIN
- NEW."id_convert_to_bigint" := NEW."id";
- RETURN NEW;
-END;
-$$;
-
CREATE FUNCTION trigger_909cf0a06094() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -13054,7 +13045,7 @@ CREATE TABLE p_ci_builds_metadata (
id bigint NOT NULL,
runtime_runner_features jsonb DEFAULT '{}'::jsonb NOT NULL,
id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL,
- partition_id bigint DEFAULT 100 NOT NULL,
+ partition_id bigint NOT NULL,
debug_trace_enabled boolean DEFAULT false NOT NULL
)
PARTITION BY LIST (partition_id);
@@ -13083,7 +13074,7 @@ CREATE TABLE ci_builds_metadata (
id bigint DEFAULT nextval('ci_builds_metadata_id_seq'::regclass) NOT NULL,
runtime_runner_features jsonb DEFAULT '{}'::jsonb NOT NULL,
id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL,
- partition_id bigint DEFAULT 100 NOT NULL,
+ partition_id bigint NOT NULL,
debug_trace_enabled boolean DEFAULT false NOT NULL
);
ALTER TABLE ONLY p_ci_builds_metadata ATTACH PARTITION ci_builds_metadata FOR VALUES IN ('100');
@@ -22292,7 +22283,6 @@ CREATE SEQUENCE self_managed_prometheus_alert_events_id_seq
ALTER SEQUENCE self_managed_prometheus_alert_events_id_seq OWNED BY self_managed_prometheus_alert_events.id;
CREATE TABLE sent_notifications (
- id_convert_to_bigint integer DEFAULT 0 NOT NULL,
project_id integer,
noteable_id integer,
noteable_type character varying,
@@ -34227,8 +34217,6 @@ CREATE TRIGGER trigger_482bac5ec48a BEFORE INSERT OR UPDATE ON system_note_metad
CREATE TRIGGER trigger_775287b6d67a BEFORE INSERT OR UPDATE ON note_diff_files FOR EACH ROW EXECUTE FUNCTION trigger_775287b6d67a();
-CREATE TRIGGER trigger_7f4fcd5aa322 BEFORE INSERT OR UPDATE ON sent_notifications FOR EACH ROW EXECUTE FUNCTION trigger_7f4fcd5aa322();
-
CREATE TRIGGER trigger_909cf0a06094 BEFORE INSERT OR UPDATE ON award_emoji FOR EACH ROW EXECUTE FUNCTION trigger_909cf0a06094();
CREATE TRIGGER trigger_bfc6e47be8cc BEFORE INSERT OR UPDATE ON snippet_user_mentions FOR EACH ROW EXECUTE FUNCTION trigger_bfc6e47be8cc();
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index e48112af870..53630e915bb 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -324,30 +324,28 @@ GitLab generates audit events when a cluster agent token is created or revoked.
### Instance events **(PREMIUM SELF)**
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16826) in GitLab 13.5, audit events for failed second-factor authentication attempt.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276250) in GitLab 13.6, audit events for when a user is approved using the Admin Area.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276921) in GitLab 13.6, audit events for when a user's personal access token is successfully or unsuccessfully created or revoked.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298783) in GitLab 13.9, audit events for when a user requests access to an instance or is rejected using the Admin Area.
+
The following user actions on a GitLab instance generate instance audit events:
-- Sign-in events and the authentication type (such as standard, LDAP, or OmniAuth)
-- Failed sign-ins
-- Added SSH key
-- Added or removed email
-- Changed password
-- Ask for password reset
-- Grant OAuth access
-- Started or stopped user impersonation
-- Changed username. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7797) in GitLab 12.8.
-- User was deleted. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/251) in GitLab 12.8.
-- User was added. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/251) in GitLab 12.8.
-- User requests access to an instance. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298783) in GitLab 13.9.
-- User was approved using the Admin Area. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276250) in GitLab 13.6.
-- User was rejected using the Admin Area. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298783) in GitLab 13.9.
-- User was blocked using the Admin Area. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/251) in GitLab 12.8.
-- User was blocked using the API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25872) in GitLab 12.9.
-- Failed second-factor authentication attempt. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16826) in
- GitLab 13.5.
-- A user's personal access token was successfully created or revoked.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276921) in GitLab 13.6.
-- A failed attempt to create or revoke a user's personal access token.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276921) in GitLab 13.6.
+- Sign-in events and the authentication type such as standard, LDAP, or OmniAuth.
+- Failed sign-ins.
+- Added SSH key.
+- Added or removed email.
+- Changed password.
+- Ask for password reset.
+- Grant OAuth access.
+- Started or stopped user impersonation.
+- Changed username.
+- User was added or deleted.
+- User requests access to an instance.
+- User was approved, rejected, or blocked using the Admin Area.
+- User was blocked using the API.
+- Failed second-factor authentication attempt.
+- A user's personal access token was successfully or unsuccessfully created or revoked.
- Administrator added or removed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/323905) in GitLab 14.1.
- Removed SSH key. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1.
- Added or removed GPG key. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1.
diff --git a/doc/api/runners.md b/doc/api/runners.md
index be69b762555..1a722163c41 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -774,7 +774,7 @@ Example response:
}
```
-## Reset instance's runner registration token
+## Reset instance's runner registration token (deprecated)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104691) in GitLab 15.7.
@@ -793,7 +793,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/runners/reset_registration_token"
```
-## Reset project's runner registration token
+## Reset project's runner registration token (deprecated)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104691) in GitLab 15.7.
@@ -812,7 +812,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/projects/9/runners/reset_registration_token"
```
-## Reset group's runner registration token
+## Reset group's runner registration token (deprecated)
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104691) in GitLab 15.7.
diff --git a/doc/integration/jira/dvcs/index.md b/doc/integration/jira/dvcs/index.md
index 16b7f5d6217..7d10efa52fd 100644
--- a/doc/integration/jira/dvcs/index.md
+++ b/doc/integration/jira/dvcs/index.md
@@ -149,8 +149,8 @@ For more information, see [Install the GitLab for Jira Cloud app](../connect-app
### Feature comparison of DVCS and GitLab for Jira Cloud app
-| Feature | DVCS (Jira Cloud) | GitLab for Jira Cloud app |
-|--------------------|--------------------|---------------------------------------|
+| Feature | DVCS | GitLab for Jira Cloud app |
+|--------------------|------------------------|---------------------------|
| Smart Commits | **{check-circle}** Yes | **{check-circle}** Yes |
| Sync MRs | **{check-circle}** Yes | **{check-circle}** Yes |
| Sync branches | **{check-circle}** Yes | **{check-circle}** Yes |
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 22e36122b88..793c9a89ec0 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -22,6 +22,9 @@ vulnerabilities. By including an extra Container Scanning job in your pipeline t
vulnerabilities and displays them in a merge request, you can use GitLab to audit your Docker-based
apps.
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [Container Scanning](https://www.youtube.com/watch?v=C0jn2eN5MAs).
+
Container Scanning is often considered part of Software Composition Analysis (SCA). SCA can contain
aspects of inspecting the items your code uses. These items typically include application and system
dependencies that are almost always imported from external sources, rather than sourced from items
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index f9db8d4409e..6b2824e675e 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -35,6 +35,9 @@ vulnerability.
![Dependency scanning Widget](img/dependency_scanning_v13_2.png)
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [Dependency Scanning](https://www.youtube.com/watch?v=TBnfbGk4c4o).
+
## Dependency Scanning compared to Container Scanning
GitLab offers both Dependency Scanning and Container Scanning
diff --git a/doc/user/project/web_ide_beta/index.md b/doc/user/project/web_ide_beta/index.md
index 5aeb34f7aa7..3051ee3bbfd 100644
--- a/doc/user/project/web_ide_beta/index.md
+++ b/doc/user/project/web_ide_beta/index.md
@@ -48,9 +48,9 @@ To open the Web IDE Beta from a merge request:
1. Go to your merge request.
1. In the upper-right corner, select **Code > Open in Web IDE**.
-The Web IDE Beta opens modified and created files in separate tabs and displays changes side by side with the original source. To optimize loading time, only the top 10 files (by number of lines changed) are opened automatically.
+The Web IDE Beta opens new and modified files in separate tabs and displays changes side by side with the original source. To optimize loading time, only the top 10 files (by number of lines changed) are opened automatically.
-In the file tree, any modified or created file in the merge request is indicated by an icon next to the filename. To view changes to a file, right-click the filename and select **Compare with merge request base**.
+In the file tree, any new or modified file in the merge request is indicated by an icon next to the filename. To view changes to a file, right-click the filename and select **Compare with merge request base**.
## Open a file in the Web IDE Beta
diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb
index 30d12864bf8..2e377f41b66 100644
--- a/lib/api/ci/jobs.rb
+++ b/lib/api/ci/jobs.rb
@@ -266,14 +266,14 @@ module API
persisted_environment = current_authenticated_job.actual_persisted_environment
environment = { tier: persisted_environment.tier, slug: persisted_environment.slug } if persisted_environment
- agent_authorizations = ::Clusters::Agents::FilterAuthorizationsService.new(
- ::Clusters::AgentAuthorizationsFinder.new(project).execute,
+ agent_authorizations = ::Clusters::Agents::Authorizations::CiAccess::FilterService.new(
+ ::Clusters::Agents::Authorizations::CiAccess::Finder.new(project).execute,
environment: persisted_environment&.name
).execute
# See https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_ci_access.md#apiv4joballowed_agents-api
{
- allowed_agents: Entities::Clusters::AgentAuthorization.represent(agent_authorizations),
+ allowed_agents: Entities::Clusters::Agents::Authorizations::CiAccess.represent(agent_authorizations),
job: { id: current_authenticated_job.id },
pipeline: { id: pipeline.id },
project: { id: project.id, groups: project_groups },
diff --git a/lib/api/entities/clusters/agent_authorization.rb b/lib/api/entities/clusters/agent_authorization.rb
deleted file mode 100644
index 7bbe0f1ec45..00000000000
--- a/lib/api/entities/clusters/agent_authorization.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module Entities
- module Clusters
- class AgentAuthorization < Grape::Entity
- expose :agent_id, as: :id
- expose :config_project, with: Entities::ProjectIdentity
- expose :config, as: :configuration
- end
- end
- end
-end
diff --git a/lib/api/entities/clusters/agents/authorizations/ci_access.rb b/lib/api/entities/clusters/agents/authorizations/ci_access.rb
new file mode 100644
index 00000000000..2eefc4361b1
--- /dev/null
+++ b/lib/api/entities/clusters/agents/authorizations/ci_access.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Clusters
+ module Agents
+ module Authorizations
+ class CiAccess < Grape::Entity
+ expose :agent_id, as: :id
+ expose :config_project, with: Entities::ProjectIdentity
+ expose :config, as: :configuration
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index bf9612db6bf..94764d0dda3 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -129,7 +129,7 @@ module API
post '/', feature_category: :kubernetes_management, urgency: :low do
agent = ::Clusters::Agent.find(params[:agent_id])
- ::Clusters::Agents::RefreshAuthorizationService.new(agent, config: params[:agent_config]).execute
+ ::Clusters::Agents::Authorizations::CiAccess::RefreshService.new(agent, config: params[:agent_config]).execute
no_content!
end
diff --git a/lib/gitlab/slug/environment.rb b/lib/gitlab/slug/environment.rb
index fd70def8e7c..892d5350db5 100644
--- a/lib/gitlab/slug/environment.rb
+++ b/lib/gitlab/slug/environment.rb
@@ -21,7 +21,7 @@ module Gitlab
slugified = name.to_s.downcase.gsub(/[^a-z0-9]/, '-')
# Must start with a letter
- slugified = 'env-' + slugified unless slugified.match?(/^[a-z]/)
+ slugified = "env-#{slugified}" unless slugified.match?(/^[a-z]/)
# Repeated dashes are invalid (OpenShift limitation)
slugified.squeeze!('-')
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2aab5dd5da6..689a1464a62 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15493,6 +15493,9 @@ msgstr ""
msgid "Download artifacts"
msgstr ""
+msgid "Download as CSV"
+msgstr ""
+
msgid "Download codes"
msgstr ""
@@ -39929,6 +39932,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Create Issue"
+msgstr ""
+
msgid "SecurityReports|Create Jira issue"
msgstr ""
@@ -39998,6 +40004,9 @@ msgstr ""
msgid "SecurityReports|Image"
msgstr ""
+msgid "SecurityReports|Investigate this vulnerability by creating an issue"
+msgstr ""
+
msgid "SecurityReports|Issue"
msgstr ""
@@ -40151,6 +40160,9 @@ msgstr ""
msgid "SecurityReports|There was an error creating the issue."
msgstr ""
+msgid "SecurityReports|There was an error creating the issue. Please try again."
+msgstr ""
+
msgid "SecurityReports|There was an error creating the merge request."
msgstr ""
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
index 36472056e76..154a73462bb 100755
--- a/scripts/review_apps/automated_cleanup.rb
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -183,12 +183,6 @@ module ReviewApps
kubernetes.cleanup_namespaces_by_created_at(created_before: threshold_time(days: days)) unless dry_run
end
- def perform_stale_pvc_cleanup!(days:)
- puts "Dry-run mode." if dry_run
-
- kubernetes.cleanup_pvcs_by_created_at(created_before: threshold_time(days: days)) unless dry_run
- end
-
private
attr_reader :api_endpoint, :dry_run, :gitlab_token, :project_path
@@ -322,10 +316,4 @@ if $PROGRAM_NAME == __FILE__
timed('Stale Namespace cleanup') do
automated_cleanup.perform_stale_namespace_cleanup!(days: 3)
end
-
- puts
-
- timed('Stale PVC cleanup') do
- automated_cleanup.perform_stale_pvc_cleanup!(days: 30)
- end
end
diff --git a/scripts/review_apps/k8s-resources-count-checks.sh b/scripts/review_apps/k8s-resources-count-checks.sh
index b63fa043065..7ce98f8d164 100755
--- a/scripts/review_apps/k8s-resources-count-checks.sh
+++ b/scripts/review_apps/k8s-resources-count-checks.sh
@@ -15,6 +15,9 @@ function k8s_resource_count() {
SERVICES_COUNT_THRESHOLD=3000
REVIEW_APPS_COUNT_THRESHOLD=200
+# One review app currently deploys 4 PVCs
+PVCS_COUNT_THRESHOLD=$((REVIEW_APPS_COUNT_THRESHOLD * 4))
+
exit_with_error=false
# In the current GKE cluster configuration, we should never go higher than 4096 services per cluster.
@@ -36,6 +39,12 @@ if [ "$(echo $(($namespaces_count - $review_apps_count)) | sed 's/-//')" -gt 30
exit_with_error=true
fi
+pvcs_count=$(kubectl get pvc -A | wc -l | xargs)
+if [ "${pvcs_count}" -gt "${PVCS_COUNT_THRESHOLD}" ]; then
+ >&2 echo "❌ [ERROR] PVCs are above ${PVCS_COUNT_THRESHOLD} (currently at ${pvcs_count})"
+ exit_with_error=true
+fi
+
if [ "${exit_with_error}" = true ] ; then
exit 1
fi
diff --git a/spec/factories/clusters/agents/group_authorizations.rb b/spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb
index abe25794234..659114eef8e 100644
--- a/spec/factories/clusters/agents/group_authorizations.rb
+++ b/spec/factories/clusters/agents/authorizations/ci_access/group_authorizations.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :agent_group_authorization, class: 'Clusters::Agents::GroupAuthorization' do
+ factory :agent_ci_access_group_authorization, class: 'Clusters::Agents::Authorizations::CiAccess::GroupAuthorization' do
association :agent, factory: :cluster_agent
group
diff --git a/spec/factories/clusters/agents/project_authorizations.rb b/spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb
index eecbfe95bfc..10d4f8fb946 100644
--- a/spec/factories/clusters/agents/project_authorizations.rb
+++ b/spec/factories/clusters/agents/authorizations/ci_access/project_authorizations.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :agent_project_authorization, class: 'Clusters::Agents::ProjectAuthorization' do
+ factory :agent_ci_access_project_authorization, class: 'Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization' do
association :agent, factory: :cluster_agent
project
diff --git a/spec/finders/clusters/agent_authorizations_finder_spec.rb b/spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb
index f680792d6c4..c311b19139f 100644
--- a/spec/finders/clusters/agent_authorizations_finder_spec.rb
+++ b/spec/finders/clusters/agents/authorizations/ci_access/finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::AgentAuthorizationsFinder do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::Finder, feature_category: :kubernetes_management do
describe '#execute' do
let_it_be(:top_level_group) { create(:group) }
let_it_be(:subgroup1) { create(:group, parent: top_level_group) }
@@ -54,34 +54,34 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
let(:unrelated_agent) { create(:cluster_agent) }
before do
- create(:agent_project_authorization, agent: unrelated_agent, project: requesting_project)
+ create(:agent_ci_access_project_authorization, agent: unrelated_agent, project: requesting_project)
end
it { is_expected.to be_empty }
end
context 'agent configuration project shares a root namespace, but does not belong to an ancestor of the given project' do
- let!(:project_authorization) { create(:agent_project_authorization, agent: non_ancestor_agent, project: requesting_project) }
+ let!(:project_authorization) { create(:agent_ci_access_project_authorization, agent: non_ancestor_agent, project: requesting_project) }
it { is_expected.to match_array([project_authorization]) }
end
context 'with project authorizations present' do
- let!(:authorization) { create(:agent_project_authorization, agent: production_agent, project: requesting_project) }
+ let!(:authorization) { create(:agent_ci_access_project_authorization, agent: production_agent, project: requesting_project) }
it { is_expected.to match_array [authorization] }
end
context 'with overlapping authorizations' do
let!(:agent) { create(:cluster_agent, project: requesting_project) }
- let!(:project_authorization) { create(:agent_project_authorization, agent: agent, project: requesting_project) }
- let!(:group_authorization) { create(:agent_group_authorization, agent: agent, group: bottom_level_group) }
+ let!(:project_authorization) { create(:agent_ci_access_project_authorization, agent: agent, project: requesting_project) }
+ let!(:group_authorization) { create(:agent_ci_access_group_authorization, agent: agent, group: bottom_level_group) }
it { is_expected.to match_array [project_authorization] }
end
it_behaves_like 'access_as' do
- let!(:authorization) { create(:agent_project_authorization, agent: production_agent, project: requesting_project, config: config) }
+ let!(:authorization) { create(:agent_ci_access_project_authorization, agent: production_agent, project: requesting_project, config: config) }
end
end
@@ -92,7 +92,7 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
expect(subject.count).to eq(1)
authorization = subject.first
- expect(authorization).to be_a(Clusters::Agents::ImplicitAuthorization)
+ expect(authorization).to be_a(Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization)
expect(authorization.agent).to eq(associated_agent)
end
end
@@ -102,15 +102,15 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
let(:unrelated_agent) { create(:cluster_agent) }
before do
- create(:agent_group_authorization, agent: unrelated_agent, group: top_level_group)
+ create(:agent_ci_access_group_authorization, agent: unrelated_agent, group: top_level_group)
end
it { is_expected.to be_empty }
end
context 'multiple agents are authorized for the same group' do
- let!(:staging_auth) { create(:agent_group_authorization, agent: staging_agent, group: bottom_level_group) }
- let!(:production_auth) { create(:agent_group_authorization, agent: production_agent, group: bottom_level_group) }
+ let!(:staging_auth) { create(:agent_ci_access_group_authorization, agent: staging_agent, group: bottom_level_group) }
+ let!(:production_auth) { create(:agent_ci_access_group_authorization, agent: production_agent, group: bottom_level_group) }
it 'returns authorizations for all agents' do
expect(subject).to contain_exactly(staging_auth, production_auth)
@@ -118,8 +118,8 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
end
context 'a single agent is authorized to more than one matching group' do
- let!(:bottom_level_auth) { create(:agent_group_authorization, agent: production_agent, group: bottom_level_group) }
- let!(:top_level_auth) { create(:agent_group_authorization, agent: production_agent, group: top_level_group) }
+ let!(:bottom_level_auth) { create(:agent_ci_access_group_authorization, agent: production_agent, group: bottom_level_group) }
+ let!(:top_level_auth) { create(:agent_ci_access_group_authorization, agent: production_agent, group: top_level_group) }
it 'picks the authorization for the closest group to the requesting project' do
expect(subject).to contain_exactly(bottom_level_auth)
@@ -127,13 +127,13 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
end
context 'agent configuration project does not belong to an ancestor of the authorized group' do
- let!(:group_authorization) { create(:agent_group_authorization, agent: non_ancestor_agent, group: bottom_level_group) }
+ let!(:group_authorization) { create(:agent_ci_access_group_authorization, agent: non_ancestor_agent, group: bottom_level_group) }
it { is_expected.to match_array([group_authorization]) }
end
it_behaves_like 'access_as' do
- let!(:authorization) { create(:agent_group_authorization, agent: production_agent, group: top_level_group, config: config) }
+ let!(:authorization) { create(:agent_ci_access_group_authorization, agent: production_agent, group: top_level_group, config: config) }
end
end
end
diff --git a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
index d86fbf81d20..18b63082e4a 100644
--- a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Design management design index page renders design index 1`] = `
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
@@ -115,7 +115,7 @@ exports[`Design management design index page renders design index 1`] = `
exports[`Design management design index page with error GlAlert is rendered in correct position with correct content 1`] = `
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/components/experiment_header_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/components/experiment_header_spec.js
new file mode 100644
index 00000000000..b56755043fb
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/components/experiment_header_spec.js
@@ -0,0 +1,55 @@
+import { GlButton } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ExperimentHeader from '~/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue';
+import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import * as urlHelpers from '~/lib/utils/url_utility';
+import { MOCK_EXPERIMENT } from '../mock_data';
+
+const DELETE_INFO = {
+ deletePath: '/delete',
+ deleteConfirmationText: 'MODAL_BODY',
+ actionPrimaryText: 'Delete!',
+ modalTitle: 'MODAL_TITLE',
+};
+
+describe('~/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue', () => {
+ let wrapper;
+
+ const createWrapper = () => {
+ wrapper = mountExtended(ExperimentHeader, {
+ propsData: { title: MOCK_EXPERIMENT.name, deleteInfo: DELETE_INFO },
+ });
+ };
+
+ const findDeleteButton = () => wrapper.findComponent(DeleteButton);
+ const findButton = () => wrapper.findComponent(GlButton);
+
+ beforeEach(createWrapper);
+
+ describe('Delete', () => {
+ it('shows delete button', () => {
+ expect(findDeleteButton().exists()).toBe(true);
+ });
+
+ it('passes the right props', () => {
+ expect(findDeleteButton().props()).toMatchObject(DELETE_INFO);
+ });
+ });
+
+ describe('CSV download', () => {
+ it('shows download CSV button', () => {
+ expect(findDeleteButton().exists()).toBe(true);
+ });
+
+ it('calls the action to download the CSV', () => {
+ setWindowLocation('https://blah.com/something/1?name=query&orderBy=name');
+ jest.spyOn(urlHelpers, 'visitUrl').mockImplementation(() => {});
+
+ findButton().vm.$emit('click');
+
+ expect(urlHelpers.visitUrl).toHaveBeenCalledTimes(1);
+ expect(urlHelpers.visitUrl).toHaveBeenCalledWith('/something/1.csv?name=query&orderBy=name');
+ });
+ });
+});
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
index da011feee66..38b3d96ed11 100644
--- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
@@ -1,10 +1,10 @@
import { GlAlert, GlTableLite, GlLink, GlEmptyState } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import MlExperimentsShow from '~/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue';
+import ExperimentHeader from '~/ml/experiment_tracking/routes/experiments/show/components/experiment_header.vue';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import Pagination from '~/vue_shared/components/incubation/pagination.vue';
import setWindowLocation from 'helpers/set_window_location_helper';
-import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue';
import * as urlHelpers from '~/lib/utils/url_utility';
import { MOCK_START_CURSOR, MOCK_PAGE_INFO, MOCK_CANDIDATES, MOCK_EXPERIMENT } from './mock_data';
@@ -36,7 +36,7 @@ describe('MlExperimentsShow', () => {
const findTableRows = () => findTable().findAll('tbody > tr');
const findNthTableRow = (idx) => findTableRows().at(idx);
const findColumnInRow = (row, col) => findNthTableRow(row).findAll('td').at(col);
- const findDeleteButton = () => wrapper.findComponent(DeleteButton);
+ const findExperimentHeader = () => wrapper.findComponent(ExperimentHeader);
const hrefInRowAndColumn = (row, col) =>
findColumnInRow(row, col).findComponent(GlLink).attributes().href;
@@ -60,8 +60,12 @@ describe('MlExperimentsShow', () => {
expect(findPagination().exists()).toBe(false);
});
- it('shows delete button', () => {
- expect(findDeleteButton().exists()).toBe(true);
+ it('shows experiment header', () => {
+ expect(findExperimentHeader().exists()).toBe(true);
+ });
+
+ it('passes the correct title to experiment header', () => {
+ expect(findExperimentHeader().props('title')).toBe(MOCK_EXPERIMENT.name);
});
it('does not show table', () => {
diff --git a/spec/frontend/search/sidebar/components/scope_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
index 3b2d528e1d7..e8737384f27 100644
--- a/spec/frontend/search/sidebar/components/scope_navigation_spec.js
+++ b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
@@ -121,4 +121,22 @@ describe('ScopeNavigation', () => {
expect(findGlNavItemActive().findComponent(GlIcon).exists()).toBe(true);
});
});
+
+ describe.each`
+ searchTherm | hasBeenCalled
+ ${null} | ${0}
+ ${'test'} | ${1}
+ `('fetchSidebarCount', ({ searchTherm, hasBeenCalled }) => {
+ beforeEach(() => {
+ createComponent({
+ urlQuery: {
+ search: searchTherm,
+ },
+ });
+ });
+
+ it('is only called when search term is set', () => {
+ expect(actionSpies.fetchSidebarCount).toHaveBeenCalledTimes(hasBeenCalled);
+ });
+ });
});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js
index 434f7263eb9..11da6ef1243 100644
--- a/spec/frontend/super_sidebar/components/context_switcher_spec.js
+++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js
@@ -25,7 +25,9 @@ jest.mock('~/super_sidebar/utils', () => ({
}));
const focusInputMock = jest.fn();
-const persistentLinks = [{ title: 'Explore', link: '/explore', icon: 'compass' }];
+const persistentLinks = [
+ { title: 'Explore', link: '/explore', icon: 'compass', link_classes: 'persistent-link-class' },
+];
const username = 'root';
const projectsPath = 'projectsPath';
const groupsPath = 'groupsPath';
@@ -94,8 +96,13 @@ describe('ContextSwitcher component', () => {
it('renders the persistent links', () => {
const navItems = findNavItems();
+ const firstNavItem = navItems.at(0);
+
expect(navItems.length).toBe(persistentLinks.length);
- expect(navItems.at(0).props('item')).toBe(persistentLinks[0]);
+ expect(firstNavItem.props('item')).toBe(persistentLinks[0]);
+ expect(firstNavItem.props('linkClasses')).toEqual({
+ [persistentLinks[0].link_classes]: persistentLinks[0].link_classes,
+ });
});
it('passes the placeholder to the search box', () => {
diff --git a/spec/frontend/super_sidebar/components/groups_list_spec.js b/spec/frontend/super_sidebar/components/groups_list_spec.js
index 4b61991a5db..4fa3303c12f 100644
--- a/spec/frontend/super_sidebar/components/groups_list_spec.js
+++ b/spec/frontend/super_sidebar/components/groups_list_spec.js
@@ -19,11 +19,14 @@ describe('GroupsList component', () => {
const itRendersViewAllItem = () => {
it('renders the "View all..." item', () => {
- expect(findViewAllLink().props('item')).toEqual({
+ const link = findViewAllLink();
+
+ expect(link.props('item')).toEqual({
icon: 'group',
link: viewAllLink,
title: s__('Navigation|View all your groups'),
});
+ expect(link.props('linkClasses')).toEqual({ 'dashboard-shortcuts-groups': true });
});
};
diff --git a/spec/frontend/super_sidebar/components/merge_request_menu_spec.js b/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
index 75998ee6c55..9c8fd0556f1 100644
--- a/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
@@ -38,6 +38,7 @@ describe('MergeRequestMenu component', () => {
expect(link.attributes('data-track-action')).toBe(extraAttrs['data-track-action']);
expect(link.attributes('data-track-label')).toBe(extraAttrs['data-track-label']);
expect(link.attributes('data-track-property')).toBe(extraAttrs['data-track-property']);
+ expect(link.attributes('class')).toContain(extraAttrs.class);
});
it('renders item count string in badge', () => {
diff --git a/spec/frontend/super_sidebar/components/projects_list_spec.js b/spec/frontend/super_sidebar/components/projects_list_spec.js
index 284b88ef27e..93a414e1e8c 100644
--- a/spec/frontend/super_sidebar/components/projects_list_spec.js
+++ b/spec/frontend/super_sidebar/components/projects_list_spec.js
@@ -19,11 +19,14 @@ describe('ProjectsList component', () => {
const itRendersViewAllItem = () => {
it('renders the "View all..." item', () => {
- expect(findViewAllLink().props('item')).toEqual({
+ const link = findViewAllLink();
+
+ expect(link.props('item')).toEqual({
icon: 'project',
link: viewAllLink,
title: s__('Navigation|View all your projects'),
});
+ expect(link.props('linkClasses')).toEqual({ 'dashboard-shortcuts-projects': true });
});
};
diff --git a/spec/frontend/super_sidebar/components/super_sidebar_spec.js b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
index 6eae650a2a1..d39fa741574 100644
--- a/spec/frontend/super_sidebar/components/super_sidebar_spec.js
+++ b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
@@ -67,8 +67,20 @@ describe('SuperSidebar component', () => {
});
it("does not call the context switcher's focusInput method initially", () => {
+ createWrapper();
+
expect(focusInputMock).not.toHaveBeenCalled();
});
+
+ it('renders hidden shortcut links', () => {
+ createWrapper();
+ const [linkAttrs] = sidebarData.shortcut_links;
+ const link = wrapper.find(`.${linkAttrs.css_class}`);
+
+ expect(link.exists()).toBe(true);
+ expect(link.attributes('href')).toBe(linkAttrs.href);
+ expect(link.attributes('class')).toContain('gl-display-none');
+ });
});
describe('when opening the context switcher', () => {
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index 6da49b45829..2ff731aa102 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -73,6 +73,7 @@ describe('UserBar component', () => {
expect(isuesCounter.attributes('data-track-action')).toBe('click_link');
expect(isuesCounter.attributes('data-track-label')).toBe('issues_link');
expect(isuesCounter.attributes('data-track-property')).toBe('nav_core_menu');
+ expect(isuesCounter.attributes('class')).toContain('dashboard-shortcuts-issues');
});
it('renders merge requests counter', () => {
@@ -92,6 +93,7 @@ describe('UserBar component', () => {
expect(todosCounter.attributes('data-track-action')).toBe('click_link');
expect(todosCounter.attributes('data-track-label')).toBe('todos_link');
expect(todosCounter.attributes('data-track-property')).toBe('nav_core_menu');
+ expect(todosCounter.attributes('class')).toContain('shortcuts-todos');
});
it('renders branding logo', () => {
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index 990a4110d4b..0c9449d98a9 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -53,6 +53,7 @@ export const mergeRequestMenuGroup = [
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_assigned',
'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-merge_requests',
},
},
{
@@ -63,6 +64,7 @@ export const mergeRequestMenuGroup = [
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_to_review',
'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-review_requests',
},
},
],
@@ -104,6 +106,13 @@ export const sidebarData = {
panel_type: 'your_work',
update_pins_url: 'path/to/pins',
stop_impersonation_path: '/admin/impersonation',
+ shortcut_links: [
+ {
+ title: 'Shortcut link',
+ href: '/shortcut-link',
+ css_class: 'shortcut-link-class',
+ },
+ ],
};
export const userMenuMockStatus = {
diff --git a/spec/frontend/whats_new/utils/notification_spec.js b/spec/frontend/whats_new/utils/notification_spec.js
index dac02ee07bd..8b5663ee764 100644
--- a/spec/frontend/whats_new/utils/notification_spec.js
+++ b/spec/frontend/whats_new/utils/notification_spec.js
@@ -1,4 +1,5 @@
-import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import htmlWhatsNewNotification from 'test_fixtures_static/whats_new_notification.html';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { setNotification, getVersionDigest } from '~/whats_new/utils/notification';
@@ -12,7 +13,7 @@ describe('~/whats_new/utils/notification', () => {
const getAppEl = () => wrapper.querySelector('.app');
beforeEach(() => {
- loadHTMLFixture('static/whats_new_notification.html');
+ setHTMLFixture(htmlWhatsNewNotification);
wrapper = document.querySelector('.whats-new-notification-fixture-root');
});
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index c7d5c0cfc4f..3ebfc2c2bb5 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -139,7 +139,24 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
},
pinned_items: %w[foo bar],
panel_type: panel_type,
- update_pins_url: pins_url
+ update_pins_url: pins_url,
+ shortcut_links: [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ }
+ ]
})
end
@@ -155,7 +172,8 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_assigned',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-merge_requests'
}
},
{
@@ -165,7 +183,8 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
extraAttrs: {
'data-track-action': 'click_link',
'data-track-label': 'merge_requests_to_review',
- 'data-track-property': 'nav_core_menu'
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-review_requests'
}
}
]
diff --git a/spec/lib/api/entities/clusters/agent_authorization_spec.rb b/spec/lib/api/entities/clusters/agents/authorizations/ci_access_spec.rb
index 3a1deb43bf8..5f41ae6af4b 100644
--- a/spec/lib/api/entities/clusters/agent_authorization_spec.rb
+++ b/spec/lib/api/entities/clusters/agents/authorizations/ci_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Entities::Clusters::AgentAuthorization do
+RSpec.describe API::Entities::Clusters::Agents::Authorizations::CiAccess, feature_category: :kubernetes_management do
subject { described_class.new(authorization).as_json }
shared_examples 'generic authorization' do
@@ -16,20 +16,20 @@ RSpec.describe API::Entities::Clusters::AgentAuthorization do
end
context 'project authorization' do
- let(:authorization) { create(:agent_project_authorization) }
+ let(:authorization) { create(:agent_ci_access_project_authorization) }
include_examples 'generic authorization'
end
context 'group authorization' do
- let(:authorization) { create(:agent_group_authorization) }
+ let(:authorization) { create(:agent_ci_access_group_authorization) }
include_examples 'generic authorization'
end
context 'implicit authorization' do
let(:agent) { create(:cluster_agent) }
- let(:authorization) { Clusters::Agents::ImplicitAuthorization.new(agent: agent) }
+ let(:authorization) { Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: agent) }
include_examples 'generic authorization'
end
diff --git a/spec/lib/gitlab/slug/environment_spec.rb b/spec/lib/gitlab/slug/environment_spec.rb
index e8f0fba27b2..8e23ad118d4 100644
--- a/spec/lib/gitlab/slug/environment_spec.rb
+++ b/spec/lib/gitlab/slug/environment_spec.rb
@@ -1,38 +1,41 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'rspec-parameterized'
-RSpec.describe Gitlab::Slug::Environment do
+RSpec.describe Gitlab::Slug::Environment, feature_category: :environment_management do
describe '#generate' do
- {
- "staging-12345678901234567" => "staging-123456789-q517sa",
- "9-staging-123456789012345" => "env-9-staging-123-q517sa",
- "staging-1234567890123456" => "staging-1234567890123456",
- "staging-1234567890123456-" => "staging-123456789-q517sa",
- "production" => "production",
- "PRODUCTION" => "production-q517sa",
- "review/1-foo" => "review-1-foo-q517sa",
- "1-foo" => "env-1-foo-q517sa",
- "1/foo" => "env-1-foo-q517sa",
- "foo-" => "foo",
- "foo--bar" => "foo-bar-q517sa",
- "foo**bar" => "foo-bar-q517sa",
- "*-foo" => "env-foo-q517sa",
- "staging-12345678-" => "staging-12345678",
- "staging-12345678-01234567" => "staging-12345678-q517sa",
- "" => "env-q517sa",
- nil => "env-q517sa"
- }.each do |name, matcher|
- before do
- # ('a' * 64).to_i(16).to_s(36).last(6) gives 'q517sa'
- allow(Digest::SHA2).to receive(:hexdigest).with(name).and_return('a' * 64)
- end
+ using RSpec::Parameterized::TableSyntax
- it "returns a slug matching #{matcher}, given #{name}" do
- slug = described_class.new(name).generate
+ subject { described_class.new(name).generate }
- expect(slug).to match(/\A#{matcher}\z/)
- end
+ before do
+ # ('a' * 64).to_i(16).to_s(36).last(6) gives 'q517sa'
+ allow(Digest::SHA2).to receive(:hexdigest).with(name.to_s).and_return('a' * 64)
+ end
+
+ where(:name, :slug) do
+ "staging-12345678901234567" | "staging-123456789-q517sa"
+ "9-staging-123456789012345" | "env-9-staging-123-q517sa"
+ "staging-1234567890123456" | "staging-1234567890123456"
+ "staging-1234567890123456-" | "staging-123456789-q517sa"
+ "production" | "production"
+ "PRODUCTION" | "production-q517sa"
+ "review/1-foo" | "review-1-foo-q517sa"
+ "1-foo" | "env-1-foo-q517sa"
+ "1/foo" | "env-1-foo-q517sa"
+ "foo-" | "foo"
+ "foo--bar" | "foo-bar-q517sa"
+ "foo**bar" | "foo-bar-q517sa"
+ "*-foo" | "env-foo-q517sa"
+ "staging-12345678-" | "staging-12345678"
+ "staging-12345678-01234567" | "staging-12345678-q517sa"
+ "" | "env-q517sa"
+ nil | "env-q517sa"
+ end
+
+ with_them do
+ it { is_expected.to eq(slug) }
end
end
end
diff --git a/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb b/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb
new file mode 100644
index 00000000000..5780aa365da
--- /dev/null
+++ b/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!('cleanup_bigint_conversion_for_sent_notifications')
+
+RSpec.describe CleanupBigintConversionForSentNotifications, feature_category: :database do
+ let(:sent_notifications) { table(:sent_notifications) }
+
+ it 'correctly migrates up and down' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(sent_notifications.column_names).to include('id_convert_to_bigint')
+ }
+
+ migration.after -> {
+ sent_notifications.reset_column_information
+ expect(sent_notifications.column_names).not_to include('id_convert_to_bigint')
+ }
+ end
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index ee1410ade91..afb39dec208 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -5468,11 +5468,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
describe '#cluster_agent_authorizations' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
- let(:authorization) { instance_double(Clusters::Agents::GroupAuthorization) }
+ let(:authorization) { instance_double(Clusters::Agents::Authorizations::CiAccess::GroupAuthorization) }
let(:finder) { double(execute: [authorization]) }
it 'retrieves authorization records from the finder and caches the result' do
- expect(Clusters::AgentAuthorizationsFinder).to receive(:new).once
+ expect(Clusters::Agents::Authorizations::CiAccess::Finder).to receive(:new).once
.with(pipeline.project)
.and_return(finder)
diff --git a/spec/models/clusters/agent_spec.rb b/spec/models/clusters/agent_spec.rb
index de67bdb32aa..df8ad861aff 100644
--- a/spec/models/clusters/agent_spec.rb
+++ b/spec/models/clusters/agent_spec.rb
@@ -8,10 +8,10 @@ RSpec.describe Clusters::Agent do
it { is_expected.to belong_to(:created_by_user).class_name('User').optional }
it { is_expected.to belong_to(:project).class_name('::Project') }
it { is_expected.to have_many(:agent_tokens).class_name('Clusters::AgentToken').order(Clusters::AgentToken.arel_table[:last_used_at].desc.nulls_last) }
- it { is_expected.to have_many(:group_authorizations).class_name('Clusters::Agents::GroupAuthorization') }
- it { is_expected.to have_many(:authorized_groups).through(:group_authorizations) }
- it { is_expected.to have_many(:project_authorizations).class_name('Clusters::Agents::ProjectAuthorization') }
- it { is_expected.to have_many(:authorized_projects).through(:project_authorizations).class_name('::Project') }
+ it { is_expected.to have_many(:ci_access_group_authorizations).class_name('Clusters::Agents::Authorizations::CiAccess::GroupAuthorization') }
+ it { is_expected.to have_many(:ci_access_authorized_groups).through(:ci_access_group_authorizations) }
+ it { is_expected.to have_many(:ci_access_project_authorizations).class_name('Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization') }
+ it { is_expected.to have_many(:ci_access_authorized_projects).through(:ci_access_project_authorizations).class_name('::Project') }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_length_of(:name).is_at_most(63) }
diff --git a/spec/models/clusters/agents/group_authorization_spec.rb b/spec/models/clusters/agents/authorizations/ci_access/group_authorization_spec.rb
index baeb8f5464e..2864d6583bd 100644
--- a/spec/models/clusters/agents/group_authorization_spec.rb
+++ b/spec/models/clusters/agents/authorizations/ci_access/group_authorization_spec.rb
@@ -2,14 +2,14 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::GroupAuthorization do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::GroupAuthorization, feature_category: :kubernetes_management do
it { is_expected.to belong_to(:agent).class_name('Clusters::Agent').required }
it { is_expected.to belong_to(:group).class_name('::Group').required }
it { expect(described_class).to validate_jsonb_schema(['config']) }
describe '#config_project' do
- let(:record) { create(:agent_group_authorization) }
+ let(:record) { create(:agent_ci_access_group_authorization) }
it { expect(record.config_project).to eq(record.agent.project) }
end
diff --git a/spec/models/clusters/agents/implicit_authorization_spec.rb b/spec/models/clusters/agents/authorizations/ci_access/implicit_authorization_spec.rb
index 1f4c5b1ac9e..9a4f0c28687 100644
--- a/spec/models/clusters/agents/implicit_authorization_spec.rb
+++ b/spec/models/clusters/agents/authorizations/ci_access/implicit_authorization_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::ImplicitAuthorization do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
subject { described_class.new(agent: agent) }
diff --git a/spec/models/clusters/agents/project_authorization_spec.rb b/spec/models/clusters/agents/authorizations/ci_access/project_authorization_spec.rb
index 9ba259356c7..9e2b25e415e 100644
--- a/spec/models/clusters/agents/project_authorization_spec.rb
+++ b/spec/models/clusters/agents/authorizations/ci_access/project_authorization_spec.rb
@@ -2,14 +2,14 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::ProjectAuthorization do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization, feature_category: :kubernetes_management do
it { is_expected.to belong_to(:agent).class_name('Clusters::Agent').required }
it { is_expected.to belong_to(:project).class_name('Project').required }
it { expect(described_class).to validate_jsonb_schema(['config']) }
describe '#config_project' do
- let(:record) { create(:agent_project_authorization) }
+ let(:record) { create(:agent_ci_access_project_authorization) }
it { expect(record.config_project).to eq(record.agent.project) }
end
diff --git a/spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb b/spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb
deleted file mode 100644
index a4d1a33b3d5..00000000000
--- a/spec/models/concerns/clusters/agents/authorization_config_scopes_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Agents::AuthorizationConfigScopes do
- describe '.with_available_ci_access_fields' do
- let(:project) { create(:project) }
-
- let!(:agent_authorization_0) { create(:agent_project_authorization, project: project) }
- let!(:agent_authorization_1) { create(:agent_project_authorization, project: project, config: { access_as: {} }) }
- let!(:agent_authorization_2) { create(:agent_project_authorization, project: project, config: { access_as: { agent: {} } }) }
- let!(:impersonate_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { impersonate: {} } }) }
- let!(:ci_user_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_user: {} } }) }
- let!(:ci_job_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { ci_job: {} } }) }
- let!(:unexpected_authorization) { create(:agent_project_authorization, project: project, config: { access_as: { unexpected: {} } }) }
-
- subject { Clusters::Agents::ProjectAuthorization.with_available_ci_access_fields(project) }
-
- it { is_expected.to contain_exactly(agent_authorization_0, agent_authorization_1, agent_authorization_2) }
- end
-end
diff --git a/spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb b/spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb
new file mode 100644
index 00000000000..c632c639273
--- /dev/null
+++ b/spec/models/concerns/clusters/agents/authorizations/ci_access/config_scopes_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::ConfigScopes, feature_category: :kubernetes_management do
+ describe '.with_available_ci_access_fields' do
+ let(:project) { create(:project) }
+
+ let!(:agent_authorization_0) { create(:agent_ci_access_project_authorization, project: project) }
+ let!(:agent_authorization_1) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: {} }) }
+ let!(:agent_authorization_2) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: { agent: {} } }) }
+ let!(:impersonate_authorization) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: { impersonate: {} } }) }
+ let!(:ci_user_authorization) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: { ci_user: {} } }) }
+ let!(:ci_job_authorization) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: { ci_job: {} } }) }
+ let!(:unexpected_authorization) { create(:agent_ci_access_project_authorization, project: project, config: { access_as: { unexpected: {} } }) }
+
+ subject { Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization.with_available_ci_access_fields(project) }
+
+ it { is_expected.to contain_exactly(agent_authorization_0, agent_authorization_1, agent_authorization_2) }
+ end
+end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index ed2bf26e129..bcfcfa05ddf 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Note do
+RSpec.describe Note, feature_category: :team_planning do
include RepoHelpers
describe 'associations' do
@@ -799,20 +799,22 @@ RSpec.describe Note do
describe '#system_note_with_references?' do
it 'falsey for user-generated notes' do
- note = create(:note, system: false)
+ note = build_stubbed(:note, system: false)
expect(note.system_note_with_references?).to be_falsy
end
context 'when the note might contain cross references' do
SystemNoteMetadata.new.cross_reference_types.each do |type|
- let(:note) { create(:note, :system) }
- let!(:metadata) { create(:system_note_metadata, note: note, action: type) }
+ context "with #{type}" do
+ let(:note) { build_stubbed(:note, :system) }
+ let!(:metadata) { build_stubbed(:system_note_metadata, note: note, action: type) }
- it 'delegates to the cross-reference regex' do
- expect(note).to receive(:matches_cross_reference_regex?).and_return(false)
+ it 'delegates to the cross-reference regex' do
+ expect(note).to receive(:matches_cross_reference_regex?).and_return(false)
- note.system_note_with_references?
+ note.system_note_with_references?
+ end
end
end
end
diff --git a/spec/requests/api/ci/jobs_spec.rb b/spec/requests/api/ci/jobs_spec.rb
index 8b3ec59b785..25871beeb4f 100644
--- a/spec/requests/api/ci/jobs_spec.rb
+++ b/spec/requests/api/ci/jobs_spec.rb
@@ -198,22 +198,22 @@ RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
let_it_be(:agent_authorizations_without_env) do
[
- create(:agent_group_authorization, agent: create(:cluster_agent, project: other_project), group: group),
- create(:agent_project_authorization, agent: create(:cluster_agent, project: project), project: project),
- Clusters::Agents::ImplicitAuthorization.new(agent: create(:cluster_agent, project: project))
+ create(:agent_ci_access_group_authorization, agent: create(:cluster_agent, project: other_project), group: group),
+ create(:agent_ci_access_project_authorization, agent: create(:cluster_agent, project: project), project: project),
+ Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: create(:cluster_agent, project: project))
]
end
let_it_be(:agent_authorizations_with_review_and_production_env) do
[
create(
- :agent_group_authorization,
+ :agent_ci_access_group_authorization,
agent: create(:cluster_agent, project: other_project),
group: group,
environments: ['production', 'review/*']
),
create(
- :agent_project_authorization,
+ :agent_ci_access_project_authorization,
agent: create(:cluster_agent, project: project),
project: project,
environments: ['production', 'review/*']
@@ -224,13 +224,13 @@ RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
let_it_be(:agent_authorizations_with_staging_env) do
[
create(
- :agent_group_authorization,
+ :agent_ci_access_group_authorization,
agent: create(:cluster_agent, project: other_project),
group: group,
environments: ['staging']
),
create(
- :agent_project_authorization,
+ :agent_ci_access_project_authorization,
agent: create(:cluster_agent, project: project),
project: project,
environments: ['staging']
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index 547b9071f94..56d6f538026 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -158,8 +158,8 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
send_request(params: { agent_id: agent.id, agent_config: config })
expect(response).to have_gitlab_http_status(:no_content)
- expect(agent.authorized_groups).to contain_exactly(group)
- expect(agent.authorized_projects).to contain_exactly(project)
+ expect(agent.ci_access_authorized_groups).to contain_exactly(group)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(project)
end
end
diff --git a/spec/scripts/review_apps/automated_cleanup_spec.rb b/spec/scripts/review_apps/automated_cleanup_spec.rb
index 40cf0a8bf75..a8b8353d2ef 100644
--- a/spec/scripts/review_apps/automated_cleanup_spec.rb
+++ b/spec/scripts/review_apps/automated_cleanup_spec.rb
@@ -30,7 +30,6 @@ RSpec.describe ReviewApps::AutomatedCleanup, feature_category: :tooling do
allow(Tooling::Helm3Client).to receive(:new).and_return(helm_client)
allow(Tooling::KubernetesClient).to receive(:new).and_return(kubernetes_client)
- allow(kubernetes_client).to receive(:cleanup_pvcs_by_created_at)
allow(kubernetes_client).to receive(:cleanup_namespaces_by_created_at)
end
@@ -124,28 +123,6 @@ RSpec.describe ReviewApps::AutomatedCleanup, feature_category: :tooling do
end
end
- describe '#perform_stale_pvc_cleanup!' do
- subject { instance.perform_stale_pvc_cleanup!(days: days) }
-
- let(:days) { 2 }
-
- it_behaves_like 'the days argument is an integer in the correct range'
-
- it 'performs Kubernetes cleanup by created at' do
- expect(kubernetes_client).to receive(:cleanup_pvcs_by_created_at).with(created_before: two_days_ago)
-
- subject
- end
-
- context 'when the dry-run flag is true' do
- let(:dry_run) { true }
-
- it 'does not delete anything' do
- expect(kubernetes_client).not_to receive(:cleanup_pvcs_by_created_at)
- end
- end
- end
-
describe '#perform_stale_namespace_cleanup!' do
subject { instance.perform_stale_namespace_cleanup!(days: days) }
diff --git a/spec/services/ci/generate_kubeconfig_service_spec.rb b/spec/services/ci/generate_kubeconfig_service_spec.rb
index da18dfe04c3..913aaf11d7d 100644
--- a/spec/services/ci/generate_kubeconfig_service_spec.rb
+++ b/spec/services/ci/generate_kubeconfig_service_spec.rb
@@ -13,12 +13,12 @@ RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_mana
let_it_be(:project_agent_authorization) do
agent = create(:cluster_agent, project: agent_project)
- create(:agent_project_authorization, agent: agent, project: project)
+ create(:agent_ci_access_project_authorization, agent: agent, project: project)
end
let_it_be(:group_agent_authorization) do
agent = create(:cluster_agent, project: agent_project)
- create(:agent_group_authorization, agent: agent, group: group)
+ create(:agent_ci_access_group_authorization, agent: agent, group: group)
end
let(:template) do
@@ -33,7 +33,7 @@ RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_mana
let(:agent_authorizations) { [project_agent_authorization, group_agent_authorization] }
let(:filter_service) do
instance_double(
- ::Clusters::Agents::FilterAuthorizationsService,
+ ::Clusters::Agents::Authorizations::CiAccess::FilterService,
execute: agent_authorizations
)
end
@@ -42,7 +42,7 @@ RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_mana
before do
allow(Gitlab::Kubernetes::Kubeconfig::Template).to receive(:new).and_return(template)
- allow(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).and_return(filter_service)
+ allow(::Clusters::Agents::Authorizations::CiAccess::FilterService).to receive(:new).and_return(filter_service)
end
it 'returns a Kubeconfig Template' do
@@ -59,7 +59,7 @@ RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_mana
end
it "filters the pipeline's agents by `nil` environment" do
- expect(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).with(
+ expect(::Clusters::Agents::Authorizations::CiAccess::FilterService).to receive(:new).with(
pipeline.cluster_agent_authorizations,
environment: nil
)
@@ -89,7 +89,7 @@ RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_mana
subject(:execute) { described_class.new(pipeline, token: build.token, environment: 'production').execute }
it "filters the pipeline's agents by the specified environment" do
- expect(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).with(
+ expect(::Clusters::Agents::Authorizations::CiAccess::FilterService).to receive(:new).with(
pipeline.cluster_agent_authorizations,
environment: 'production'
)
diff --git a/spec/services/clusters/agents/filter_authorizations_service_spec.rb b/spec/services/clusters/agents/authorizations/ci_access/filter_service_spec.rb
index 62cff405d0c..45443cfd887 100644
--- a/spec/services/clusters/agents/filter_authorizations_service_spec.rb
+++ b/spec/services/clusters/agents/authorizations/ci_access/filter_service_spec.rb
@@ -2,16 +2,16 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::FilterAuthorizationsService, feature_category: :continuous_integration do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::FilterService, feature_category: :continuous_integration do
describe '#execute' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let(:agent_authorizations_without_env) do
[
- build(:agent_project_authorization, project: project, agent: build(:cluster_agent, project: project)),
- build(:agent_group_authorization, group: group, agent: build(:cluster_agent, project: project)),
- ::Clusters::Agents::ImplicitAuthorization.new(agent: build(:cluster_agent, project: project))
+ build(:agent_ci_access_project_authorization, project: project, agent: build(:cluster_agent, project: project)),
+ build(:agent_ci_access_group_authorization, group: group, agent: build(:cluster_agent, project: project)),
+ ::Clusters::Agents::Authorizations::CiAccess::ImplicitAuthorization.new(agent: build(:cluster_agent, project: project))
]
end
@@ -31,13 +31,13 @@ RSpec.describe Clusters::Agents::FilterAuthorizationsService, feature_category:
let(:agent_authorizations_with_env) do
[
build(
- :agent_project_authorization,
+ :agent_ci_access_project_authorization,
project: project,
agent: build(:cluster_agent, project: project),
environments: ['staging', 'review/*', 'production']
),
build(
- :agent_group_authorization,
+ :agent_ci_access_group_authorization,
group: group,
agent: build(:cluster_agent, project: project),
environments: ['staging', 'review/*', 'production']
@@ -48,13 +48,13 @@ RSpec.describe Clusters::Agents::FilterAuthorizationsService, feature_category:
let(:agent_authorizations_with_different_env) do
[
build(
- :agent_project_authorization,
+ :agent_ci_access_project_authorization,
project: project,
agent: build(:cluster_agent, project: project),
environments: ['staging']
),
build(
- :agent_group_authorization,
+ :agent_ci_access_group_authorization,
group: group,
agent: build(:cluster_agent, project: project),
environments: ['staging']
diff --git a/spec/services/clusters/agents/refresh_authorization_service_spec.rb b/spec/services/clusters/agents/authorizations/ci_access/refresh_service_spec.rb
index 51c054ddc98..dc803c94ccb 100644
--- a/spec/services/clusters/agents/refresh_authorization_service_spec.rb
+++ b/spec/services/clusters/agents/authorizations/ci_access/refresh_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category: :kubernetes_management do
+RSpec.describe Clusters::Agents::Authorizations::CiAccess::RefreshService, feature_category: :kubernetes_management do
describe '#execute' do
let_it_be(:root_ancestor) { create(:group) }
@@ -39,11 +39,11 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
before do
default_config = { default_namespace: 'default' }
- agent.group_authorizations.create!(group: removed_group, config: default_config)
- agent.group_authorizations.create!(group: modified_group, config: default_config)
+ agent.ci_access_group_authorizations.create!(group: removed_group, config: default_config)
+ agent.ci_access_group_authorizations.create!(group: modified_group, config: default_config)
- agent.project_authorizations.create!(project: removed_project, config: default_config)
- agent.project_authorizations.create!(project: modified_project, config: default_config)
+ agent.ci_access_project_authorizations.create!(project: removed_project, config: default_config)
+ agent.ci_access_project_authorizations.create!(project: modified_project, config: default_config)
end
shared_examples 'removing authorization' do
@@ -78,12 +78,12 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
describe 'group authorization' do
it 'refreshes authorizations for the agent' do
expect(subject).to be_truthy
- expect(agent.authorized_groups).to contain_exactly(added_group, modified_group)
+ expect(agent.ci_access_authorized_groups).to contain_exactly(added_group, modified_group)
- added_authorization = agent.group_authorizations.find_by(group: added_group)
+ added_authorization = agent.ci_access_group_authorizations.find_by(group: added_group)
expect(added_authorization.config).to eq({ 'default_namespace' => 'default' })
- modified_authorization = agent.group_authorizations.find_by(group: modified_group)
+ modified_authorization = agent.ci_access_group_authorizations.find_by(group: modified_group)
expect(modified_authorization.config).to eq({ 'default_namespace' => 'new-namespace' })
end
@@ -94,24 +94,24 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
it 'authorizes groups up to the limit' do
expect(subject).to be_truthy
- expect(agent.authorized_groups).to contain_exactly(added_group)
+ expect(agent.ci_access_authorized_groups).to contain_exactly(added_group)
end
end
include_examples 'removing authorization' do
- let(:authorizations) { agent.authorized_groups }
+ let(:authorizations) { agent.ci_access_authorized_groups }
end
end
describe 'project authorization' do
it 'refreshes authorizations for the agent' do
expect(subject).to be_truthy
- expect(agent.authorized_projects).to contain_exactly(added_project, modified_project)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(added_project, modified_project)
- added_authorization = agent.project_authorizations.find_by(project: added_project)
+ added_authorization = agent.ci_access_project_authorizations.find_by(project: added_project)
expect(added_authorization.config).to eq({ 'default_namespace' => 'default' })
- modified_authorization = agent.project_authorizations.find_by(project: modified_project)
+ modified_authorization = agent.ci_access_project_authorizations.find_by(project: modified_project)
expect(modified_authorization.config).to eq({ 'default_namespace' => 'new-namespace' })
end
@@ -121,7 +121,7 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
it 'creates an authorization record for the project' do
expect(subject).to be_truthy
- expect(agent.authorized_projects).to contain_exactly(added_project)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(added_project)
end
end
@@ -131,7 +131,7 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
it 'creates an authorization record for the project' do
expect(subject).to be_truthy
- expect(agent.authorized_projects).to contain_exactly(added_project)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(added_project)
end
end
@@ -142,12 +142,12 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category:
it 'authorizes projects up to the limit' do
expect(subject).to be_truthy
- expect(agent.authorized_projects).to contain_exactly(added_project)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(added_project)
end
end
include_examples 'removing authorization' do
- let(:authorizations) { agent.authorized_projects }
+ let(:authorizations) { agent.ci_access_authorized_projects }
end
end
end
diff --git a/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb b/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
index 719a2cf24e9..7ac2249642a 100644
--- a/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
+++ b/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Security::CiConfiguration::DependencyScanningCreateService, :snowplow,
- feature_category: :dependency_scanning do
+ feature_category: :software_composition_analysis do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-dependency-scanning-config-1' }
diff --git a/spec/support/finder_collection_allowlist.yml b/spec/support/finder_collection_allowlist.yml
index 1b1c98af80d..25084ece58d 100644
--- a/spec/support/finder_collection_allowlist.yml
+++ b/spec/support/finder_collection_allowlist.yml
@@ -24,7 +24,7 @@
- Ci::CommitStatusesFinder
- Ci::DailyBuildGroupReportResultsFinder
- ClusterAncestorsFinder
-- Clusters::AgentAuthorizationsFinder
+- Clusters::Agents::Authorizations::CiAccess::Finder
- Clusters::KubernetesNamespaceFinder
- ComplianceManagement::MergeRequests::ComplianceViolationsFinder
- ContainerRepositoriesFinder
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index a767ae69653..1c26a34010c 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -7205,7 +7205,6 @@
- './spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb'
- './spec/lib/gitlab/slash_commands/presenters/run_spec.rb'
- './spec/lib/gitlab/slash_commands/run_spec.rb'
-- './spec/lib/gitlab/slug/environment_spec.rb'
- './spec/lib/gitlab/snippet_search_results_spec.rb'
- './spec/lib/gitlab/sourcegraph_spec.rb'
- './spec/lib/gitlab/spamcheck/client_spec.rb'
diff --git a/spec/tooling/lib/tooling/kubernetes_client_spec.rb b/spec/tooling/lib/tooling/kubernetes_client_spec.rb
index 20eb78c2f4f..8d127f1345b 100644
--- a/spec/tooling/lib/tooling/kubernetes_client_spec.rb
+++ b/spec/tooling/lib/tooling/kubernetes_client_spec.rb
@@ -14,88 +14,6 @@ RSpec.describe Tooling::KubernetesClient do
allow(instance).to receive(:run_command)
end
- describe '#cleanup_pvcs_by_created_at' do
- let(:pvc_1_created_at) { three_days_ago }
- let(:pvc_2_created_at) { three_days_ago }
- let(:pvc_1_namespace) { 'review-first-review-app' }
- let(:pvc_2_namespace) { 'review-second-review-app' }
- let(:kubectl_pvcs_json) do
- <<~JSON
- {
- "apiVersion": "v1",
- "items": [
- {
- "apiVersion": "v1",
- "kind": "PersistentVolumeClaim",
- "metadata": {
- "creationTimestamp": "#{pvc_1_created_at.utc.iso8601}",
- "name": "pvc1",
- "namespace": "#{pvc_1_namespace}"
- }
- },
- {
- "apiVersion": "v1",
- "kind": "PersistentVolumeClaim",
- "metadata": {
- "creationTimestamp": "#{pvc_2_created_at.utc.iso8601}",
- "name": "pvc2",
- "namespace": "#{pvc_2_namespace}"
- }
- }
- ]
- }
- JSON
- end
-
- subject { instance.cleanup_pvcs_by_created_at(created_before: two_days_ago) }
-
- before do
- allow(instance).to receive(:run_command).with(
- "kubectl get pvc --all-namespaces --sort-by='{.metadata.creationTimestamp}' -o json"
- ).and_return(kubectl_pvcs_json)
- end
-
- context 'when no pvcs are stale' do
- let(:pvc_1_created_at) { one_day_ago }
- let(:pvc_2_created_at) { one_day_ago }
-
- it 'does not delete any PVC' do
- expect(instance).not_to receive(:run_command).with(/kubectl delete pvc/)
-
- subject
- end
- end
-
- context 'when some pvcs are stale' do
- let(:pvc_1_created_at) { three_days_ago }
- let(:pvc_2_created_at) { three_days_ago }
-
- context 'when some pvcs are not in a review app namespaces' do
- let(:pvc_1_namespace) { 'review-my-review-app' }
- let(:pvc_2_namespace) { 'review-apps' } # This is not a review apps namespace, so we should not delete PVCs inside it
-
- it 'deletes the stale pvcs inside of review-apps namespaces only' do
- expect(instance).to receive(:run_command).with("kubectl delete pvc --namespace=#{pvc_1_namespace} --now --ignore-not-found pvc1")
- expect(instance).not_to receive(:run_command).with(/kubectl delete pvc --namespace=#{pvc_2_namespace}/)
-
- subject
- end
- end
-
- context 'when all pvcs are in review-apps namespaces' do
- let(:pvc_1_namespace) { 'review-my-review-app' }
- let(:pvc_2_namespace) { 'review-another-review-app' }
-
- it 'deletes all of the stale pvcs' do
- expect(instance).to receive(:run_command).with("kubectl delete pvc --namespace=#{pvc_1_namespace} --now --ignore-not-found pvc1")
- expect(instance).to receive(:run_command).with("kubectl delete pvc --namespace=#{pvc_2_namespace} --now --ignore-not-found pvc2")
-
- subject
- end
- end
- end
- end
-
describe '#cleanup_namespaces_by_created_at' do
let(:namespace_1_created_at) { three_days_ago }
let(:namespace_2_created_at) { three_days_ago }
@@ -174,32 +92,6 @@ RSpec.describe Tooling::KubernetesClient do
end
end
- describe '#delete_pvc' do
- let(:pvc_name) { 'my-pvc' }
-
- subject { instance.delete_pvc(pvc_name, pvc_namespace) }
-
- context 'when the namespace is not a review app namespace' do
- let(:pvc_namespace) { 'not-a-review-app-namespace' }
-
- it 'does not delete the pvc' do
- expect(instance).not_to receive(:run_command).with(/kubectl delete pvc/)
-
- subject
- end
- end
-
- context 'when the namespace is a review app namespace' do
- let(:pvc_namespace) { 'review-apple-test' }
-
- it 'deletes the pvc' do
- expect(instance).to receive(:run_command).with("kubectl delete pvc --namespace=#{pvc_namespace} --now --ignore-not-found #{pvc_name}")
-
- subject
- end
- end
- end
-
describe '#delete_namespaces' do
subject { instance.delete_namespaces(namespaces) }
@@ -224,70 +116,11 @@ RSpec.describe Tooling::KubernetesClient do
end
end
- describe '#pvcs_created_before' do
- subject { instance.pvcs_created_before(created_before: two_days_ago) }
-
- let(:pvc_1_created_at) { three_days_ago }
- let(:pvc_2_created_at) { three_days_ago }
- let(:pvc_1_namespace) { 'review-first-review-app' }
- let(:pvc_2_namespace) { 'review-second-review-app' }
- let(:kubectl_pvcs_json) do
- <<~JSON
- {
- "apiVersion": "v1",
- "items": [
- {
- "apiVersion": "v1",
- "kind": "PersistentVolumeClaim",
- "metadata": {
- "creationTimestamp": "#{pvc_1_created_at.utc.iso8601}",
- "name": "pvc1",
- "namespace": "#{pvc_1_namespace}"
- }
- },
- {
- "apiVersion": "v1",
- "kind": "PersistentVolumeClaim",
- "metadata": {
- "creationTimestamp": "#{pvc_2_created_at.utc.iso8601}",
- "name": "pvc2",
- "namespace": "#{pvc_2_namespace}"
- }
- }
- ]
- }
- JSON
- end
-
- it 'calls #resource_created_before with the correct parameters' do
- expect(instance).to receive(:resource_created_before).with(resource_type: 'pvc', created_before: two_days_ago)
-
- subject
- end
-
- it 'returns a hash with two keys' do
- allow(instance).to receive(:run_command).with(
- "kubectl get pvc --all-namespaces --sort-by='{.metadata.creationTimestamp}' -o json"
- ).and_return(kubectl_pvcs_json)
-
- expect(subject).to match_array([
- {
- resource_name: 'pvc1',
- namespace: 'review-first-review-app'
- },
- {
- resource_name: 'pvc2',
- namespace: 'review-second-review-app'
- }
- ])
- end
- end
-
describe '#namespaces_created_before' do
subject { instance.namespaces_created_before(created_before: two_days_ago) }
let(:namespace_1_created_at) { three_days_ago }
- let(:namespace_2_created_at) { three_days_ago }
+ let(:namespace_2_created_at) { one_day_ago }
let(:namespace_1_name) { 'review-first-review-app' }
let(:namespace_2_name) { 'review-second-review-app' }
let(:kubectl_namespaces_json) do
@@ -316,18 +149,12 @@ RSpec.describe Tooling::KubernetesClient do
JSON
end
- it 'calls #resource_created_before with the correct parameters' do
- expect(instance).to receive(:resource_created_before).with(resource_type: 'namespace', created_before: two_days_ago)
-
- subject
- end
-
it 'returns an array of namespaces' do
allow(instance).to receive(:run_command).with(
"kubectl get namespace --all-namespaces --sort-by='{.metadata.creationTimestamp}' -o json"
).and_return(kubectl_namespaces_json)
- expect(subject).to match_array(%w[review-first-review-app review-second-review-app])
+ expect(subject).to match_array(%w[review-first-review-app])
end
end
diff --git a/spec/views/search/_results.html.haml_spec.rb b/spec/views/search/_results.html.haml_spec.rb
index ed71a03c7e0..832cc5b7cf3 100644
--- a/spec/views/search/_results.html.haml_spec.rb
+++ b/spec/views/search/_results.html.haml_spec.rb
@@ -97,12 +97,6 @@ RSpec.describe 'search/_results', feature_category: :global_search do
expect(rendered).not_to have_selector('[data-track-property=search_result]')
end
end
-
- it 'does render the sidebar' do
- render
-
- expect(rendered).to have_selector('#js-search-sidebar')
- end
end
end
diff --git a/spec/views/search/show.html.haml_spec.rb b/spec/views/search/show.html.haml_spec.rb
index db06adfeb6b..0158a9049b9 100644
--- a/spec/views/search/show.html.haml_spec.rb
+++ b/spec/views/search/show.html.haml_spec.rb
@@ -41,6 +41,12 @@ RSpec.describe 'search/show', feature_category: :global_search do
expect(rendered).not_to render_template('search/_results')
end
+
+ it 'does render the sidebar' do
+ render
+
+ expect(rendered).to have_selector('#js-search-sidebar')
+ end
end
context 'unfurling support' do
diff --git a/tooling/lib/tooling/kubernetes_client.rb b/tooling/lib/tooling/kubernetes_client.rb
index b373f5d6980..5579f130a84 100644
--- a/tooling/lib/tooling/kubernetes_client.rb
+++ b/tooling/lib/tooling/kubernetes_client.rb
@@ -9,20 +9,6 @@ module Tooling
K8S_ALLOWED_NAMESPACES_REGEX = /^review-(?!apps).+/.freeze
CommandFailedError = Class.new(StandardError)
- def cleanup_pvcs_by_created_at(created_before:)
- stale_pvcs = pvcs_created_before(created_before: created_before)
-
- # `kubectl` doesn't allow us to filter namespaces with a regexp. We therefore do the filtering in Ruby.
- review_apps_stale_pvcs = stale_pvcs.select do |stale_pvc_hash|
- K8S_ALLOWED_NAMESPACES_REGEX.match?(stale_pvc_hash[:namespace])
- end
- return if review_apps_stale_pvcs.empty?
-
- review_apps_stale_pvcs.each do |pvc_hash|
- delete_pvc(pvc_hash[:resource_name], pvc_hash[:namespace])
- end
- end
-
def cleanup_namespaces_by_created_at(created_before:)
stale_namespaces = namespaces_created_before(created_before: created_before)
@@ -33,12 +19,6 @@ module Tooling
delete_namespaces(review_apps_stale_namespaces)
end
- def delete_pvc(pvc, namespace)
- return unless K8S_ALLOWED_NAMESPACES_REGEX.match?(namespace)
-
- run_command("kubectl delete pvc --namespace=#{namespace} --now --ignore-not-found #{pvc}")
- end
-
def delete_namespaces(namespaces)
return if namespaces.any? { |ns| !K8S_ALLOWED_NAMESPACES_REGEX.match?(ns) }
@@ -58,29 +38,14 @@ module Tooling
run_command(command)
end
- def pvcs_created_before(created_before:)
- resource_created_before(resource_type: 'pvc', created_before: created_before) do |item|
- {
- resource_name: item.dig('metadata', 'name'),
- namespace: item.dig('metadata', 'namespace')
- }
- end
- end
-
def namespaces_created_before(created_before:)
- resource_created_before(resource_type: 'namespace', created_before: created_before) do |item|
- item.dig('metadata', 'name')
- end
- end
-
- def resource_created_before(resource_type:, created_before:)
- response = run_command("kubectl get #{resource_type} --all-namespaces --sort-by='{.metadata.creationTimestamp}' -o json")
+ response = run_command("kubectl get namespace --all-namespaces --sort-by='{.metadata.creationTimestamp}' -o json")
items = JSON.parse(response)['items'] # rubocop:disable Gitlab/Json
items.filter_map do |item|
item_created_at = Time.parse(item.dig('metadata', 'creationTimestamp'))
- yield item if item_created_at < created_before
+ item.dig('metadata', 'name') if item_created_at < created_before
end
rescue ::JSON::ParserError => ex
puts "Ignoring this JSON parsing error: #{ex}\n\nResponse was:\n#{response}"