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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-11 15:10:57 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-11 15:10:57 +0300
commit320d8adff14c100cd8a6798880b7eeff8e137f15 (patch)
tree38aade64f34de6d98b7c0ca8630b3d8f01a9b613
parent3fc19e14429002aa548f6bd2691cea3f9cde7773 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS5
-rw-r--r--.rubocop_todo/rspec/verified_doubles.yml1
-rw-r--r--.rubocop_todo/style/percent_literal_delimiters.yml59
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipelines_list/pipelines.vue1
-rw-r--r--app/assets/javascripts/google_cloud/service_accounts/list.vue1
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js8
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue80
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue135
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss1
-rw-r--r--app/assets/stylesheets/page_bundles/projects_usage_quotas.scss19
-rw-r--r--app/assets/stylesheets/themes/theme_helper.scss3
-rw-r--r--app/models/lfs_download_object.rb2
-rw-r--r--app/models/namespace.rb2
-rw-r--r--app/models/namespace/root_storage_statistics.rb6
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/notification_setting.rb2
-rw-r--r--app/models/performance_monitoring/prometheus_panel_group.rb36
-rw-r--r--app/models/project.rb10
-rw-r--r--app/models/project_feature.rb4
-rw-r--r--app/models/project_setting.rb2
-rw-r--r--app/models/releases/link.rb2
-rw-r--r--app/models/repository.rb22
-rw-r--r--app/models/resource_label_event.rb2
-rw-r--r--app/models/resource_state_event.rb2
-rw-r--r--app/models/resource_timebox_event.rb2
-rw-r--r--app/models/user.rb6
-rw-r--r--app/models/user_interacted_project.rb2
-rw-r--r--app/presenters/dev_ops_report/metric_presenter.rb20
-rw-r--r--app/presenters/search_service_presenter.rb2
-rw-r--r--app/serializers/pipeline_serializer.rb2
-rw-r--r--app/services/application_settings/update_service.rb2
-rw-r--r--app/services/auth/container_registry_authentication_service.rb4
-rw-r--r--app/services/boards/update_service.rb2
-rw-r--r--app/services/bulk_imports/file_download_service.rb4
-rw-r--r--app/services/ci/update_instance_variables_service.rb2
-rw-r--r--app/services/clusters/kubernetes/create_or_update_service_account_service.rb12
-rw-r--r--app/services/feature_flags/base_service.rb2
-rw-r--r--app/services/files/multi_service.rb2
-rw-r--r--app/services/import/bitbucket_server_service.rb2
-rw-r--r--app/services/import/fogbugz_service.rb2
-rw-r--r--app/services/import/github_service.rb2
-rw-r--r--app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb2
-rw-r--r--app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb2
-rw-r--r--app/services/import_export_clean_up_service.rb2
-rw-r--r--app/services/incident_management/pager_duty/process_webhook_service.rb2
-rw-r--r--app/services/issuable/bulk_update_service.rb2
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/packages/debian/generate_distribution_service.rb4
-rw-r--r--app/services/preview_markdown_service.rb2
-rw-r--r--app/services/projects/apple_target_platform_detector_service.rb2
-rw-r--r--app/services/projects/download_service.rb2
-rw-r--r--app/services/projects/hashed_storage/migrate_attachments_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_object_download_list_service.rb2
-rw-r--r--app/services/projects/update_service.rb4
-rw-r--r--app/services/repositories/base_service.rb2
-rw-r--r--app/services/repository_archive_clean_up_service.rb4
-rw-r--r--app/services/resource_access_tokens/create_service.rb2
-rw-r--r--app/services/resource_access_tokens/revoke_service.rb2
-rw-r--r--app/services/search/global_service.rb2
-rw-r--r--app/services/search/project_service.rb2
-rw-r--r--app/services/snippets/update_service.rb2
-rw-r--r--app/services/todos/destroy/destroyed_issuable_service.rb2
-rw-r--r--app/services/todos/destroy/entity_leave_service.rb2
-rw-r--r--app/uploaders/design_management/design_v432x230_uploader.rb2
-rw-r--r--app/uploaders/gitlab_uploader.rb2
-rw-r--r--app/validators/addressable_url_validator.rb2
-rw-r--r--app/validators/gitlab/zoom_url_validator.rb2
-rw-r--r--app/validators/json_schema_validator.rb2
-rw-r--r--app/views/projects/blame/show.html.haml1
-rw-r--r--app/views/projects/blob/_blob.html.haml1
-rw-r--r--app/views/projects/commits/show.html.haml1
-rw-r--r--app/views/projects/find_file/show.html.haml1
-rw-r--r--app/views/projects/usage_quotas/index.html.haml1
-rw-r--r--app/workers/members_destroyer/unassign_issuables_worker.rb2
-rw-r--r--app/workers/projects/record_target_platforms_worker.rb2
-rw-r--r--config/application.rb1
-rw-r--r--danger/clickhouse/Dangerfile (renamed from danger/database/clickhouse/Dangerfile)7
-rw-r--r--danger/plugins/clickhouse.rb10
-rw-r--r--doc/architecture/blueprints/organization/index.md16
-rw-r--r--doc/architecture/blueprints/organization/organization-faq.md44
-rw-r--r--doc/user/profile/service_accounts.md2
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/component/access_tokens.rb1
-rw-r--r--spec/features/invites_spec.rb18
-rw-r--r--spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb3
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js39
-rw-r--r--spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js29
-rw-r--r--spec/frontend/usage_quotas/storage/components/usage_graph_spec.js125
-rw-r--r--spec/models/performance_monitoring/prometheus_panel_group_spec.rb62
-rw-r--r--spec/models/performance_monitoring/prometheus_panel_spec.rb11
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/helpers/sign_up_helpers.rb27
-rw-r--r--spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb109
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb7
-rw-r--r--spec/workers/gitlab/github_import/advance_stage_worker_spec.rb123
-rw-r--r--spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb7
-rw-r--r--tooling/danger/project_helper.rb8
-rw-r--r--yarn.lock8
98 files changed, 473 insertions, 733 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 62224524065..24178879b3b 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -48,6 +48,11 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
/spec/frontend_integration/
/ee/spec/frontend_integration/
+[Clickhouse] @gitlab-org/maintainers/clickhouse
+/db/clickhouse/
+/ee/db/clickhouse/
+/**/click(_|-)?house/
+
[Database] @gitlab-org/maintainers/database
/db/
/ee/db/
diff --git a/.rubocop_todo/rspec/verified_doubles.yml b/.rubocop_todo/rspec/verified_doubles.yml
index 0408eb97119..42d1363358b 100644
--- a/.rubocop_todo/rspec/verified_doubles.yml
+++ b/.rubocop_todo/rspec/verified_doubles.yml
@@ -1001,7 +1001,6 @@ RSpec/VerifiedDoubles:
- 'spec/workers/create_commit_signature_worker_spec.rb'
- 'spec/workers/environments/auto_stop_worker_spec.rb'
- 'spec/workers/error_tracking_issue_link_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_issue_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_note_worker_spec.rb'
diff --git a/.rubocop_todo/style/percent_literal_delimiters.yml b/.rubocop_todo/style/percent_literal_delimiters.yml
index 4d7023d8a94..1aedbdb1704 100644
--- a/.rubocop_todo/style/percent_literal_delimiters.yml
+++ b/.rubocop_todo/style/percent_literal_delimiters.yml
@@ -2,64 +2,6 @@
# Cop supports --autocorrect.
Style/PercentLiteralDelimiters:
Exclude:
- - 'app/models/lfs_download_object.rb'
- - 'app/models/namespace.rb'
- - 'app/models/namespace/root_storage_statistics.rb'
- - 'app/models/note.rb'
- - 'app/models/notification_setting.rb'
- - 'app/models/project.rb'
- - 'app/models/project_feature.rb'
- - 'app/models/project_setting.rb'
- - 'app/models/releases/link.rb'
- - 'app/models/repository.rb'
- - 'app/models/resource_label_event.rb'
- - 'app/models/resource_state_event.rb'
- - 'app/models/resource_timebox_event.rb'
- - 'app/models/user.rb'
- - 'app/models/user_interacted_project.rb'
- - 'app/presenters/dev_ops_report/metric_presenter.rb'
- - 'app/presenters/search_service_presenter.rb'
- - 'app/serializers/pipeline_serializer.rb'
- - 'app/services/application_settings/update_service.rb'
- - 'app/services/auth/container_registry_authentication_service.rb'
- - 'app/services/boards/update_service.rb'
- - 'app/services/bulk_imports/file_download_service.rb'
- - 'app/services/ci/update_instance_variables_service.rb'
- - 'app/services/clusters/kubernetes/create_or_update_service_account_service.rb'
- - 'app/services/feature_flags/base_service.rb'
- - 'app/services/files/multi_service.rb'
- - 'app/services/import/bitbucket_server_service.rb'
- - 'app/services/import/fogbugz_service.rb'
- - 'app/services/import/github_service.rb'
- - 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb'
- - 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb'
- - 'app/services/import_export_clean_up_service.rb'
- - 'app/services/incident_management/pager_duty/process_webhook_service.rb'
- - 'app/services/issuable/bulk_update_service.rb'
- - 'app/services/merge_requests/update_service.rb'
- - 'app/services/packages/debian/generate_distribution_service.rb'
- - 'app/services/preview_markdown_service.rb'
- - 'app/services/projects/apple_target_platform_detector_service.rb'
- - 'app/services/projects/download_service.rb'
- - 'app/services/projects/hashed_storage/migrate_attachments_service.rb'
- - 'app/services/projects/lfs_pointers/lfs_object_download_list_service.rb'
- - 'app/services/projects/update_service.rb'
- - 'app/services/repositories/base_service.rb'
- - 'app/services/repository_archive_clean_up_service.rb'
- - 'app/services/resource_access_tokens/create_service.rb'
- - 'app/services/resource_access_tokens/revoke_service.rb'
- - 'app/services/search/global_service.rb'
- - 'app/services/search/project_service.rb'
- - 'app/services/snippets/update_service.rb'
- - 'app/services/todos/destroy/destroyed_issuable_service.rb'
- - 'app/services/todos/destroy/entity_leave_service.rb'
- - 'app/uploaders/design_management/design_v432x230_uploader.rb'
- - 'app/uploaders/gitlab_uploader.rb'
- - 'app/validators/addressable_url_validator.rb'
- - 'app/validators/gitlab/zoom_url_validator.rb'
- - 'app/validators/json_schema_validator.rb'
- - 'app/workers/members_destroyer/unassign_issuables_worker.rb'
- - 'app/workers/projects/record_target_platforms_worker.rb'
- 'config/application.rb'
- 'config/boot.rb'
- 'config/environments/production.rb'
@@ -970,7 +912,6 @@ Style/PercentLiteralDelimiters:
- 'spec/views/projects/commit/branches.html.haml_spec.rb'
- 'spec/workers/concerns/worker_context_spec.rb'
- 'spec/workers/container_registry/migration/enqueuer_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
- 'spec/workers/groups/update_statistics_worker_spec.rb'
- 'spec/workers/jira_connect/sync_branch_worker_spec.rb'
- 'spec/workers/post_receive_spec.rb'
diff --git a/app/assets/javascripts/ci/pipeline_details/pipelines_list/pipelines.vue b/app/assets/javascripts/ci/pipeline_details/pipelines_list/pipelines.vue
index 26db10505ef..bc169236e35 100644
--- a/app/assets/javascripts/ci/pipeline_details/pipelines_list/pipelines.vue
+++ b/app/assets/javascripts/ci/pipeline_details/pipelines_list/pipelines.vue
@@ -426,6 +426,7 @@ export default {
<gl-empty-state
v-else-if="stateToRender === $options.stateMap.emptyTab"
:svg-path="noPipelinesSvgPath"
+ :svg-height="150"
:title="emptyTabMessage"
/>
diff --git a/app/assets/javascripts/google_cloud/service_accounts/list.vue b/app/assets/javascripts/google_cloud/service_accounts/list.vue
index 635b185d207..ebba9332c53 100644
--- a/app/assets/javascripts/google_cloud/service_accounts/list.vue
+++ b/app/assets/javascripts/google_cloud/service_accounts/list.vue
@@ -63,6 +63,7 @@ export default {
:primary-button-link="createUrl"
:primary-button-text="$options.i18n.createServiceAccount"
:svg-path="emptyIllustrationUrl"
+ :svg-height="150"
/>
<div v-else>
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 95646324078..7d16af003e4 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -729,3 +729,11 @@ export const isCurrentUser = (userId) => {
return Number(userId) === currentUserId;
};
+
+/**
+ * Clones an object via JSON stringifying and re-parsing.
+ * This ensures object references are not persisted (e.g. unlike lodash cloneDeep)
+ */
+export const cloneWithoutReferences = (obj) => {
+ return JSON.parse(JSON.stringify(obj));
+};
diff --git a/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
index f271b284d78..a5e1cc398e3 100644
--- a/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
+++ b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
@@ -3,6 +3,7 @@ import { GlAlert, GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { updateRepositorySize } from '~/api/projects_api';
import { numberToHumanSize } from '~/lib/utils/number_utils';
+import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
import {
ERROR_MESSAGE,
LEARN_MORE_LABEL,
@@ -19,7 +20,6 @@ import {
} from '../constants';
import getProjectStorageStatistics from '../queries/project_storage.query.graphql';
import { getStorageTypesFromProjectStatistics, descendingStorageUsageSort } from '../utils';
-import UsageGraph from './usage_graph.vue';
import ProjectStorageDetail from './project_storage_detail.vue';
export default {
@@ -29,8 +29,8 @@ export default {
GlButton,
GlLink,
GlLoadingIcon,
- UsageGraph,
ProjectStorageDetail,
+ SectionedPercentageBar,
},
inject: ['projectPath'],
apollo: {
@@ -88,6 +88,67 @@ export default {
storageTypeHelpPaths,
);
},
+
+ sections() {
+ if (!this.project?.statistics) {
+ return null;
+ }
+
+ const {
+ buildArtifactsSize,
+ lfsObjectsSize,
+ packagesSize,
+ repositorySize,
+ storageSize,
+ wikiSize,
+ snippetsSize,
+ } = this.project.statistics;
+
+ if (storageSize === 0) {
+ return null;
+ }
+
+ return [
+ {
+ id: 'repository',
+ value: repositorySize,
+ },
+ {
+ id: 'lfsObjects',
+ value: lfsObjectsSize,
+ },
+ {
+ id: 'packages',
+ value: packagesSize,
+ },
+ {
+ id: 'buildArtifacts',
+ value: buildArtifactsSize,
+ },
+ {
+ id: 'wiki',
+ value: wikiSize,
+ },
+ {
+ id: 'snippets',
+ value: snippetsSize,
+ },
+ ]
+ .filter((data) => data.value !== 0)
+ .sort(descendingStorageUsageSort('value'))
+ .map((storageType) => {
+ const storageTypeExtraData = PROJECT_STORAGE_TYPES.find(
+ (type) => storageType.id === type.id,
+ );
+ const label = storageTypeExtraData?.name;
+
+ return {
+ label,
+ formattedValue: numberToHumanSize(storageType.value),
+ ...storageType,
+ };
+ });
+ },
},
methods: {
clearError() {
@@ -123,11 +184,11 @@ export default {
{{ error }}
</gl-alert>
<div v-else>
- <div class="gl-pt-5 gl-px-3">
- <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+ <div class="gl-pt-5">
+ <div class="gl-display-flex gl-justify-content-space-between">
<div>
- <h2 class="gl-m-0 gl-font-lg gl-font-weight-bold">{{ $options.TOTAL_USAGE_TITLE }}</h2>
- <p class="gl-m-0 gl-text-gray-400">
+ <h4 class="gl-font-lg gl-mb-3 gl-mt-0">{{ $options.TOTAL_USAGE_TITLE }}</h4>
+ <p>
{{ $options.TOTAL_USAGE_SUBTITLE }}
<gl-link
:href="$options.usageQuotasHelpPaths.usageQuotas"
@@ -137,13 +198,16 @@ export default {
>
</p>
</div>
- <p class="gl-m-0 gl-font-size-h-display gl-font-weight-bold" data-testid="total-usage">
+ <p
+ class="gl-m-0 gl-font-size-h-display gl-font-weight-bold gl-white-space-nowrap"
+ data-testid="total-usage"
+ >
{{ totalUsage }}
</p>
</div>
</div>
<div v-if="!isStatisticsEmpty" class="gl-w-full">
- <usage-graph :root-storage-statistics="project.statistics" :limit="0" />
+ <sectioned-percentage-bar class="gl-mt-5" :sections="sections" />
</div>
<div class="gl-w-full gl-my-5">
<gl-button
diff --git a/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue b/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue
deleted file mode 100644
index d5e7b7e2063..00000000000
--- a/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue
+++ /dev/null
@@ -1,135 +0,0 @@
-<script>
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { PROJECT_STORAGE_TYPES } from '../constants';
-import { descendingStorageUsageSort } from '../utils';
-
-export default {
- name: 'UsageGraph',
- props: {
- rootStorageStatistics: {
- required: true,
- type: Object,
- },
- limit: {
- required: true,
- type: Number,
- },
- },
- computed: {
- storageTypes() {
- const {
- buildArtifactsSize,
- lfsObjectsSize,
- packagesSize,
- repositorySize,
- storageSize,
- wikiSize,
- snippetsSize,
- } = this.rootStorageStatistics;
-
- if (storageSize === 0) {
- return null;
- }
-
- return [
- {
- id: 'repository',
- style: this.usageStyle(this.barRatio(repositorySize)),
- class: 'gl-bg-data-viz-blue-500',
- size: repositorySize,
- },
- {
- id: 'lfsObjects',
- style: this.usageStyle(this.barRatio(lfsObjectsSize)),
- class: 'gl-bg-data-viz-orange-600',
- size: lfsObjectsSize,
- },
- {
- id: 'packages',
- style: this.usageStyle(this.barRatio(packagesSize)),
- class: 'gl-bg-data-viz-aqua-500',
- size: packagesSize,
- },
- {
- id: 'buildArtifacts',
- style: this.usageStyle(this.barRatio(buildArtifactsSize)),
- class: 'gl-bg-data-viz-green-500',
- size: buildArtifactsSize,
- },
- {
- id: 'wiki',
- style: this.usageStyle(this.barRatio(wikiSize)),
- class: 'gl-bg-data-viz-magenta-500',
- size: wikiSize,
- },
- {
- id: 'snippets',
- style: this.usageStyle(this.barRatio(snippetsSize)),
- class: 'gl-bg-data-viz-orange-800',
- size: snippetsSize,
- },
- ]
- .filter((data) => data.size !== 0)
- .sort(descendingStorageUsageSort('size'))
- .map((storageType) => {
- const storageTypeExtraData = PROJECT_STORAGE_TYPES.find(
- (type) => storageType.id === type.id,
- );
- const name = storageTypeExtraData?.name;
-
- return {
- name,
- ...storageType,
- };
- });
- },
- },
- methods: {
- formatSize(size) {
- return numberToHumanSize(size);
- },
- usageStyle(ratio) {
- return { flex: ratio };
- },
- barRatio(size) {
- let max = this.rootStorageStatistics.storageSize;
-
- if (this.limit !== 0 && max <= this.limit) {
- max = this.limit;
- }
-
- return size / max;
- },
- },
-};
-</script>
-<template>
- <div v-if="storageTypes" class="gl-display-flex gl-flex-direction-column w-100">
- <div class="gl-h-6 gl-my-5 gl-bg-gray-50 gl-rounded-base gl-display-flex">
- <div
- v-for="storageType in storageTypes"
- :key="storageType.name"
- class="storage-type-usage gl-h-full gl-display-inline-block"
- :class="storageType.class"
- :style="storageType.style"
- data-testid="storage-type-usage"
- ></div>
- </div>
- <div class="row gl-mb-4">
- <div
- v-for="storageType in storageTypes"
- :key="storageType.name"
- class="col-md-auto gl-display-flex gl-align-items-center"
- data-testid="storage-type-legend"
- >
- <div class="gl-h-2 gl-w-5 gl-mr-2 gl-display-inline-block" :class="storageType.class"></div>
- <span class="gl-mr-2 gl-font-weight-bold gl-font-sm">
- {{ storageType.name }}
- </span>
- <span class="gl-text-gray-500 gl-font-sm">
- {{ formatSize(storageType.size) }}
- </span>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index 0ab56e35e2d..b00e1813696 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -547,6 +547,7 @@ $tabs-holder-z-index: 250;
}
.mr-widget-section:not(:first-child) > div,
+ .mr-widget-section:not(:first-child) > section,
.mr-widget-section .mr-widget-section > div {
border-top: solid 1px var(--border-color, $border-color);
}
diff --git a/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss b/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss
deleted file mode 100644
index 8f2cbc402c9..00000000000
--- a/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-@import 'mixins_and_variables_and_functions';
-
-.storage-type-usage {
- &:first-child {
- @include gl-rounded-top-left-base;
- @include gl-rounded-bottom-left-base;
- }
-
- &:last-child {
- @include gl-rounded-top-right-base;
- @include gl-rounded-bottom-right-base;
- }
-
- &:not(:last-child) {
- @include gl-border-r-2;
- @include gl-border-r-solid;
- border-right-color: var(--white, $white);
- }
-}
diff --git a/app/assets/stylesheets/themes/theme_helper.scss b/app/assets/stylesheets/themes/theme_helper.scss
index 95f57f7e406..cab3e630851 100644
--- a/app/assets/stylesheets/themes/theme_helper.scss
+++ b/app/assets/stylesheets/themes/theme_helper.scss
@@ -283,11 +283,12 @@
$theme-color,
$theme-color-darkest,
) {
+ --sidebar-background: #{mix(white, $theme-color-lightest, 50%)};
--transparent-white-16: rgba(255, 255, 255, 0.16);
--transparent-white-24: rgba(255, 255, 255, 0.24);
.super-sidebar {
- background-color: $theme-color-lightest;
+ background-color: var(--sidebar-background);
}
.super-sidebar .user-bar {
diff --git a/app/models/lfs_download_object.rb b/app/models/lfs_download_object.rb
index 3df6742fbc9..046e47262dd 100644
--- a/app/models/lfs_download_object.rb
+++ b/app/models/lfs_download_object.rb
@@ -9,7 +9,7 @@ class LfsDownloadObject
validates :oid, format: { with: /\A\h{64}\z/ }
validates :size, numericality: { greater_than_or_equal_to: 0 }
- validates :link, public_url: { protocols: %w(http https) }
+ validates :link, public_url: { protocols: %w[http https] }
validate :headers_must_be_hash
def initialize(oid:, size:, link:, headers: {})
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 6ba2bf39bb6..ced855c7287 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -753,7 +753,7 @@ class Namespace < ApplicationRecord
end
def reload_namespace_details
- return unless !project_namespace? && (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && namespace_details.present?
+ return unless !project_namespace? && (previous_changes.keys & %w[description description_html cached_markdown_version]).any? && namespace_details.present?
namespace_details.reset
end
diff --git a/app/models/namespace/root_storage_statistics.rb b/app/models/namespace/root_storage_statistics.rb
index 8af0cf2767c..1d11bcb574c 100644
--- a/app/models/namespace/root_storage_statistics.rb
+++ b/app/models/namespace/root_storage_statistics.rb
@@ -2,7 +2,7 @@
class Namespace::RootStorageStatistics < ApplicationRecord
SNIPPETS_SIZE_STAT_NAME = 'snippets_size'
- STATISTICS_ATTRIBUTES = %W(
+ STATISTICS_ATTRIBUTES = %W[
storage_size
repository_size
wiki_size
@@ -12,7 +12,7 @@ class Namespace::RootStorageStatistics < ApplicationRecord
#{SNIPPETS_SIZE_STAT_NAME}
pipeline_artifacts_size
uploads_size
- ).freeze
+ ].freeze
self.primary_key = :namespace_id
@@ -36,7 +36,7 @@ class Namespace::RootStorageStatistics < ApplicationRecord
end
def self.namespace_statistics_attributes
- %w(storage_size dependency_proxy_size)
+ %w[storage_size dependency_proxy_size]
end
private
diff --git a/app/models/note.rb b/app/models/note.rb
index 1615394b291..34e718feb42 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -169,7 +169,7 @@ class Note < ApplicationRecord
end
end
- scope :diff_notes, -> { where(type: %w(LegacyDiffNote DiffNote)) }
+ scope :diff_notes, -> { where(type: %w[LegacyDiffNote DiffNote]) }
scope :new_diff_notes, -> { where(type: 'DiffNote') }
scope :non_diff_notes, -> { where(type: NON_DIFF_NOTE_TYPES) }
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index cde7b92e74a..eb4fa9ac474 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -60,7 +60,7 @@ class NotificationSetting < ApplicationRecord
end
def self.allowed_fields(source = nil)
- NotificationSetting.email_events(source).dup + %i(level notification_email)
+ NotificationSetting.email_events(source).dup + %i[level notification_email]
end
def email_events
diff --git a/app/models/performance_monitoring/prometheus_panel_group.rb b/app/models/performance_monitoring/prometheus_panel_group.rb
deleted file mode 100644
index 7f3d2a1b8f4..00000000000
--- a/app/models/performance_monitoring/prometheus_panel_group.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module PerformanceMonitoring
- class PrometheusPanelGroup
- include ActiveModel::Model
-
- attr_accessor :group, :priority, :panels
-
- validates :group, presence: true
- validates :panels, array_members: { member_class: PerformanceMonitoring::PrometheusPanel }
-
- class << self
- def from_json(json_content)
- build_from_hash(json_content).tap(&:validate!)
- end
-
- private
-
- def build_from_hash(attributes)
- return new unless attributes.is_a?(Hash)
-
- new(
- group: attributes['group'],
- priority: attributes['priority'],
- panels: initialize_children_collection(attributes['panels'])
- )
- end
-
- def initialize_children_collection(children)
- return unless children.is_a?(Array)
-
- children.map { |panels| PerformanceMonitoring::PrometheusPanel.from_json(panels) }
- end
- end
- end
-end
diff --git a/app/models/project.rb b/app/models/project.rb
index dd197e4a43d..25991108801 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -68,10 +68,10 @@ class Project < ApplicationRecord
}.freeze
VALID_IMPORT_PORTS = [80, 443].freeze
- VALID_IMPORT_PROTOCOLS = %w(http https git).freeze
+ VALID_IMPORT_PROTOCOLS = %w[http https git].freeze
VALID_MIRROR_PORTS = [22, 80, 443].freeze
- VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze
+ VALID_MIRROR_PROTOCOLS = %w[http https ssh git].freeze
SORTING_PREFERENCE_FIELD = :projects_sort
MAX_BUILD_TIMEOUT = 1.month
@@ -1667,7 +1667,7 @@ class Project < ApplicationRecord
return unless Gitlab::Email::IncomingEmail.supports_issue_creation? && author
# check since this can come from a request parameter
- return unless %w(issue merge_request).include?(address_type)
+ return unless %w[issue merge_request].include?(address_type)
author.ensure_incoming_email_token!
@@ -3495,11 +3495,11 @@ class Project < ApplicationRecord
end
def sync_project_namespace?
- (changes.keys & %w(name path namespace_id namespace visibility_level shared_runners_enabled)).any? && project_namespace.present?
+ (changes.keys & %w[name path namespace_id namespace visibility_level shared_runners_enabled]).any? && project_namespace.present?
end
def reload_project_namespace_details
- return unless (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && project_namespace.namespace_details.present?
+ return unless (previous_changes.keys & %w[description description_html cached_markdown_version]).any? && project_namespace.namespace_details.present?
project_namespace.namespace_details.reset
end
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 92ba02ec777..246ab5a1abc 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -201,11 +201,11 @@ class ProjectFeature < ApplicationRecord
self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed
end
- %i(merge_requests_access_level builds_access_level).each(&validator)
+ %i[merge_requests_access_level builds_access_level].each(&validator)
end
def feature_validation_exclusion
- %i(pages package_registry)
+ %i[pages package_registry]
end
override :resource_member?
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index 29fb0450525..69d1a9f4aeb 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -5,7 +5,7 @@ class ProjectSetting < ApplicationRecord
include EachBatch
include IgnorableColumns
- ALLOWED_TARGET_PLATFORMS = %w(ios osx tvos watchos android).freeze
+ ALLOWED_TARGET_PLATFORMS = %w[ios osx tvos watchos android].freeze
belongs_to :project, inverse_of: :project_setting
diff --git a/app/models/releases/link.rb b/app/models/releases/link.rb
index 67d765a15c0..84a794f9a4f 100644
--- a/app/models/releases/link.rb
+++ b/app/models/releases/link.rb
@@ -11,7 +11,7 @@ module Releases
FILEPATH_REGEX = %r{\A\/[^\/](?!.*\/\/.*)[\-\.\w\/]+[\da-zA-Z]+\z}.freeze
FILEPATH_MAX_LENGTH = 128
- validates :url, presence: true, addressable_url: { schemes: %w(http https ftp) }, uniqueness: { scope: :release }
+ validates :url, presence: true, addressable_url: { schemes: %w[http https ftp] }, uniqueness: { scope: :release }
validates :name, presence: true, uniqueness: { scope: :release }
validates :filepath, uniqueness: { scope: :release }, allow_blank: true
validate :filepath_format_valid?
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 1e69ff4d1fc..3efdaee38f0 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -47,20 +47,20 @@ class Repository
#
# For example, for entry `:commit_count` there's a method called `commit_count` which
# stores its data in the `commit_count` cache key.
- CACHED_METHODS = %i(size recent_objects_size commit_count readme_path contribution_guide
+ CACHED_METHODS = %i[size recent_objects_size commit_count readme_path contribution_guide
changelog license_blob license_gitaly gitignore
gitlab_ci_yml branch_names tag_names branch_count
tag_count avatar exists? root_ref merged_branch_names
has_visible_content? issue_template_names_hash merge_request_template_names_hash
- xcode_project? has_ambiguous_refs?).freeze
+ xcode_project? has_ambiguous_refs?].freeze
# Certain method caches should be refreshed when certain types of files are
# changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
# the corresponding methods to call for refreshing caches.
METHOD_CACHES_FOR_FILE_TYPES = {
- readme: %i(readme_path),
+ readme: %i[readme_path],
changelog: :changelog,
- license: %i(license_blob license_gitaly),
+ license: %i[license_blob license_gitaly],
contributing: :contribution_guide,
gitignore: :gitignore,
gitlab_ci: :gitlab_ci_yml,
@@ -343,13 +343,13 @@ class Repository
end
def expire_tags_cache
- expire_method_caches(%i(tag_names tag_count has_ambiguous_refs?))
+ expire_method_caches(%i[tag_names tag_count has_ambiguous_refs?])
@tags = nil
@tag_names_include = nil
end
def expire_branches_cache
- expire_method_caches(%i(branch_names merged_branch_names branch_count has_visible_content? has_ambiguous_refs?))
+ expire_method_caches(%i[branch_names merged_branch_names branch_count has_visible_content? has_ambiguous_refs?])
expire_protected_branches_cache
@local_branches = nil
@@ -362,7 +362,7 @@ class Repository
end
def expire_statistics_caches
- expire_method_caches(%i(size recent_objects_size commit_count))
+ expire_method_caches(%i[size recent_objects_size commit_count])
end
def expire_all_method_caches
@@ -370,7 +370,7 @@ class Repository
end
def expire_avatar_cache
- expire_method_caches(%i(avatar))
+ expire_method_caches(%i[avatar])
end
# Refreshes the method caches of this repository.
@@ -411,19 +411,19 @@ class Repository
end
def expire_root_ref_cache
- expire_method_caches(%i(root_ref))
+ expire_method_caches(%i[root_ref])
end
# Expires the cache(s) used to determine if a repository is empty or not.
def expire_emptiness_caches
return unless empty?
- expire_method_caches(%i(has_visible_content?))
+ expire_method_caches(%i[has_visible_content?])
raw_repository.expire_has_local_branches_cache
end
def expire_exists_cache
- expire_method_caches(%i(exists?))
+ expire_method_caches(%i[exists?])
end
# expire cache that doesn't depend on repository data (when expiring)
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index 8fb7a9beb37..d5c839724d4 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -21,7 +21,7 @@ class ResourceLabelEvent < ResourceEvent
}
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def self.preload_label_subjects(events)
diff --git a/app/models/resource_state_event.rb b/app/models/resource_state_event.rb
index 134f71e35ad..88a86258b0a 100644
--- a/app/models/resource_state_event.rb
+++ b/app/models/resource_state_event.rb
@@ -14,7 +14,7 @@ class ResourceStateEvent < ResourceEvent
after_create :issue_usage_metrics
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def issuable
diff --git a/app/models/resource_timebox_event.rb b/app/models/resource_timebox_event.rb
index 1cc77501d8d..644ffae5749 100644
--- a/app/models/resource_timebox_event.rb
+++ b/app/models/resource_timebox_event.rb
@@ -16,7 +16,7 @@ class ResourceTimeboxEvent < ResourceEvent
after_create :issue_usage_metrics
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def issuable
diff --git a/app/models/user.rb b/app/models/user.rb
index 0651a38428e..05ec27416c2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -61,7 +61,7 @@ class User < MainClusterwide::ApplicationRecord
:public_email
].freeze
- FORBIDDEN_SEARCH_STATES = %w(blocked banned ldap_blocked).freeze
+ FORBIDDEN_SEARCH_STATES = %w[blocked banned ldap_blocked].freeze
INCOMING_MAIL_TOKEN_PREFIX = 'glimt-'
FEED_TOKEN_PREFIX = 'glft-'
@@ -1925,7 +1925,7 @@ class User < MainClusterwide::ApplicationRecord
def access_level=(new_level)
new_level = new_level.to_s
- return unless %w(admin regular).include?(new_level)
+ return unless %w[admin regular].include?(new_level)
self.admin = (new_level == 'admin')
end
@@ -2425,7 +2425,7 @@ class User < MainClusterwide::ApplicationRecord
def update_highest_role?
return false unless persisted?
- (previous_changes.keys & %w(state user_type)).any?
+ (previous_changes.keys & %w[state user_type]).any?
end
def update_highest_role_attribute
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
index 1c7515894fe..73bca362960 100644
--- a/app/models/user_interacted_project.rb
+++ b/app/models/user_interacted_project.rb
@@ -24,7 +24,7 @@ class UserInteractedProject < ApplicationRecord
}
cached_exists?(**attributes) do
- where(attributes).exists? || UserInteractedProject.insert_all([attributes], unique_by: %w(project_id user_id))
+ where(attributes).exists? || UserInteractedProject.insert_all([attributes], unique_by: %w[project_id user_id])
true
end
end
diff --git a/app/presenters/dev_ops_report/metric_presenter.rb b/app/presenters/dev_ops_report/metric_presenter.rb
index 1a5b12fa408..75dbbb63f76 100644
--- a/app/presenters/dev_ops_report/metric_presenter.rb
+++ b/app/presenters/dev_ops_report/metric_presenter.rb
@@ -93,52 +93,52 @@ module DevOpsReport
IdeaToProductionStep.new(
metric: metric,
title: 'Idea',
- features: %w(issues)
+ features: %w[issues]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Issue',
- features: %w(issues notes)
+ features: %w[issues notes]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Plan',
- features: %w(milestones boards)
+ features: %w[milestones boards]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Code',
- features: %w(merge_requests)
+ features: %w[merge_requests]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Commit',
- features: %w(merge_requests)
+ features: %w[merge_requests]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Test',
- features: %w(ci_pipelines)
+ features: %w[ci_pipelines]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Review',
- features: %w(ci_pipelines environments)
+ features: %w[ci_pipelines environments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Staging',
- features: %w(environments deployments)
+ features: %w[environments deployments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Production',
- features: %w(deployments)
+ features: %w[deployments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Feedback',
- features: %w(projects_prometheus_active service_desk_issues)
+ features: %w[projects_prometheus_active service_desk_issues]
)
]
end
diff --git a/app/presenters/search_service_presenter.rb b/app/presenters/search_service_presenter.rb
index 91e67c379c4..d79736a6e52 100644
--- a/app/presenters/search_service_presenter.rb
+++ b/app/presenters/search_service_presenter.rb
@@ -17,7 +17,7 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated
blobs: :with_web_entity_associations
}.freeze
- SORT_ENABLED_SCOPES = %w(issues merge_requests epics).freeze
+ SORT_ENABLED_SCOPES = %w[issues merge_requests epics].freeze
delegator_override :search_objects
def search_objects
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index b738438a78f..a3e842d348e 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -50,7 +50,7 @@ class PipelineSerializer < BaseSerializer
{
manual_actions: :metadata,
scheduled_actions: :metadata,
- failed_builds: %i(project metadata),
+ failed_builds: %i[project metadata],
merge_request: {
source_project: [:route, { namespace: :route }],
target_project: [:route, { namespace: :route }]
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index 6d484c4fa22..a46ecc3eee6 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -6,7 +6,7 @@ module ApplicationSettings
attr_reader :params, :application_setting
- MARKDOWN_CACHE_INVALIDATING_PARAMS = %w(asset_proxy_enabled asset_proxy_url asset_proxy_secret_key asset_proxy_whitelist).freeze
+ MARKDOWN_CACHE_INVALIDATING_PARAMS = %w[asset_proxy_enabled asset_proxy_url asset_proxy_secret_key asset_proxy_whitelist].freeze
def execute
result = update_settings
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index eaee5ce70fc..9b010272995 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -39,11 +39,11 @@ module Auth
end
def self.full_access_token(*names)
- access_token(%w(*), names)
+ access_token(%w[*], names)
end
def self.import_access_token
- access_token(%w(*), ['import'], 'registry')
+ access_token(%w[*], ['import'], 'registry')
end
def self.pull_access_token(*names)
diff --git a/app/services/boards/update_service.rb b/app/services/boards/update_service.rb
index 6ba8f68a4cb..c702398e89e 100644
--- a/app/services/boards/update_service.rb
+++ b/app/services/boards/update_service.rb
@@ -2,7 +2,7 @@
module Boards
class UpdateService < Boards::BaseService
- PERMITTED_PARAMS = %i(name hide_backlog_list hide_closed_list).freeze
+ PERMITTED_PARAMS = %i[name hide_backlog_list hide_closed_list].freeze
def execute(board)
filter_params
diff --git a/app/services/bulk_imports/file_download_service.rb b/app/services/bulk_imports/file_download_service.rb
index b7e84508e98..1f2437d783d 100644
--- a/app/services/bulk_imports/file_download_service.rb
+++ b/app/services/bulk_imports/file_download_service.rb
@@ -15,7 +15,7 @@ module BulkImports
ServiceError = Class.new(StandardError)
- DEFAULT_ALLOWED_CONTENT_TYPES = %w(application/gzip application/octet-stream).freeze
+ DEFAULT_ALLOWED_CONTENT_TYPES = %w[application/gzip application/octet-stream].freeze
def initialize(
configuration:,
@@ -120,7 +120,7 @@ module BulkImports
http_client.resource_url(relative_url),
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/ci/update_instance_variables_service.rb b/app/services/ci/update_instance_variables_service.rb
index ee513647d08..2f941118a1c 100644
--- a/app/services/ci/update_instance_variables_service.rb
+++ b/app/services/ci/update_instance_variables_service.rb
@@ -5,7 +5,7 @@
module Ci
class UpdateInstanceVariablesService
- UNASSIGNABLE_KEYS = %w(id _destroy).freeze
+ UNASSIGNABLE_KEYS = %w[id _destroy].freeze
def initialize(params)
@params = params[:variables_attributes]
diff --git a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
index e87640f4c76..94781422686 100644
--- a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
+++ b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
@@ -137,9 +137,9 @@ module Clusters
name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
namespace: service_account_namespace,
rules: [{
- apiGroups: %w(serving.knative.dev),
- resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services),
- verbs: %w(get list create update delete patch watch)
+ apiGroups: %w[serving.knative.dev],
+ resources: %w[configurations configurationgenerations routes revisions revisionuids autoscalers services],
+ verbs: %w[get list create update delete patch watch]
}]
).generate
end
@@ -159,9 +159,9 @@ module Clusters
name: Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME,
namespace: service_account_namespace,
rules: [{
- apiGroups: %w(database.crossplane.io),
- resources: %w(postgresqlinstances),
- verbs: %w(get list create watch)
+ apiGroups: %w[database.crossplane.io],
+ resources: %w[postgresqlinstances],
+ verbs: %w[get list create watch]
}]
).generate
end
diff --git a/app/services/feature_flags/base_service.rb b/app/services/feature_flags/base_service.rb
index 834409bf3c4..961e8d54efa 100644
--- a/app/services/feature_flags/base_service.rb
+++ b/app/services/feature_flags/base_service.rb
@@ -4,7 +4,7 @@ module FeatureFlags
class BaseService < ::BaseService
include Gitlab::Utils::StrongMemoize
- AUDITABLE_ATTRIBUTES = %w(name description active).freeze
+ AUDITABLE_ATTRIBUTES = %w[name description active].freeze
def success(**args)
sync_to_jira(args[:feature_flag])
diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb
index dd09ecafb4f..a7be73aa04c 100644
--- a/app/services/files/multi_service.rb
+++ b/app/services/files/multi_service.rb
@@ -2,7 +2,7 @@
module Files
class MultiService < Files::BaseService
- UPDATE_FILE_ACTIONS = %w(update move delete chmod).freeze
+ UPDATE_FILE_ACTIONS = %w[update move delete chmod].freeze
def create_commit!
transformer = Lfs::FileTransformer.new(project, repository, @branch_name)
diff --git a/app/services/import/bitbucket_server_service.rb b/app/services/import/bitbucket_server_service.rb
index 5d496dc7cc3..3d961780889 100644
--- a/app/services/import/bitbucket_server_service.rb
+++ b/app/services/import/bitbucket_server_service.rb
@@ -83,7 +83,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/fogbugz_service.rb b/app/services/import/fogbugz_service.rb
index 9a8def43312..2f63e4e6fb7 100644
--- a/app/services/import/fogbugz_service.rb
+++ b/app/services/import/fogbugz_service.rb
@@ -88,7 +88,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/github_service.rb b/app/services/import/github_service.rb
index df255a7ae24..73e0c229a9c 100644
--- a/app/services/import/github_service.rb
+++ b/app/services/import/github_service.rb
@@ -91,7 +91,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
index e30818cc5d2..ed99d20d67f 100644
--- a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
+++ b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
@@ -11,7 +11,7 @@ module Import
end
validates :file_url, addressable_url: {
- schemes: %w(https),
+ schemes: %w[https],
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
dns_rebind_protection: true
diff --git a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
index 7599343d4e1..57ed717b966 100644
--- a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
+++ b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
@@ -13,7 +13,7 @@ module Import
validates_presence_of :region, :bucket_name, :file_key, :access_key_id, :secret_access_key
validates :file_url, addressable_url: {
- schemes: %w(https),
+ schemes: %w[https],
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
dns_rebind_protection: true
diff --git a/app/services/import_export_clean_up_service.rb b/app/services/import_export_clean_up_service.rb
index 567ac065cf7..5ee2f70ec4c 100644
--- a/app/services/import_export_clean_up_service.rb
+++ b/app/services/import_export_clean_up_service.rb
@@ -60,7 +60,7 @@ class ImportExportCleanUpService
end
def directories_cmd
- %W(find #{path} -mindepth #{DIR_DEPTH} -maxdepth #{DIR_DEPTH} -type d -not -path #{path} -mmin +#{mmin})
+ %W[find #{path} -mindepth #{DIR_DEPTH} -maxdepth #{DIR_DEPTH} -type d -not -path #{path} -mmin +#{mmin}]
end
def logger
diff --git a/app/services/incident_management/pager_duty/process_webhook_service.rb b/app/services/incident_management/pager_duty/process_webhook_service.rb
index 3ce2674616e..6f779bfdb18 100644
--- a/app/services/incident_management/pager_duty/process_webhook_service.rb
+++ b/app/services/incident_management/pager_duty/process_webhook_service.rb
@@ -10,7 +10,7 @@ module IncidentManagement
PAGER_DUTY_PAYLOAD_SIZE_LIMIT = 55.kilobytes
# https://developer.pagerduty.com/docs/db0fa8c8984fc-overview#event-types
- PAGER_DUTY_PROCESSABLE_EVENT_TYPES = %w(incident.triggered).freeze
+ PAGER_DUTY_PROCESSABLE_EVENT_TYPES = %w[incident.triggered].freeze
def initialize(project, payload)
super(project: project)
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index 166452968f4..e996aecdf97 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -43,7 +43,7 @@ module Issuable
end
def permitted_attrs(type)
- attrs = %i(state_event milestone_id add_label_ids remove_label_ids subscription_event)
+ attrs = %i[state_event milestone_id add_label_ids remove_label_ids subscription_event]
if type == 'issue'
attrs.push(:assignee_ids, :confidential)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 598dbaf93a9..c435048e343 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -94,7 +94,7 @@ module MergeRequests
end
def track_title_and_desc_edits(changed_fields)
- tracked_fields = %w(title description)
+ tracked_fields = %w[title description]
return unless changed_fields.any? { |field| tracked_fields.include?(field) }
diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb
index 9feb860ae87..05f6d9af581 100644
--- a/app/services/packages/debian/generate_distribution_service.rb
+++ b/app/services/packages/debian/generate_distribution_service.rb
@@ -12,7 +12,7 @@ module Packages
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
# From https://salsa.debian.org/ftp-team/dak/-/blob/991aaa27a7f7aa773bb9c0cf2d516e383d9cffa0/setup/core-init.d/080_metadatakeys#L9
- METADATA_KEYS = %w(
+ METADATA_KEYS = %w[
Package
Source
Binary
@@ -60,7 +60,7 @@ module Packages
Tag
Package-Type
Installer-Menu-Item
- ).freeze
+ ].freeze
def initialize(distribution)
@distribution = distribution
diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb
index c8ccbe1465e..10aef87332a 100644
--- a/app/services/preview_markdown_service.rb
+++ b/app/services/preview_markdown_service.rb
@@ -17,7 +17,7 @@ class PreviewMarkdownService < BaseService
private
def quick_action_types
- %w(Issue MergeRequest Commit WorkItem)
+ %w[Issue MergeRequest Commit WorkItem]
end
def explain_quick_actions(text)
diff --git a/app/services/projects/apple_target_platform_detector_service.rb b/app/services/projects/apple_target_platform_detector_service.rb
index ec4c16a1416..087bb1f22e1 100644
--- a/app/services/projects/apple_target_platform_detector_service.rb
+++ b/app/services/projects/apple_target_platform_detector_service.rb
@@ -20,7 +20,7 @@ module Projects
# > AppleTargetPlatformDetectorService.new(multiplatform_project).execute
# => [:ios, :osx, :tvos, :watchos]
class AppleTargetPlatformDetectorService < BaseService
- BUILD_CONFIG_FILENAMES = %w(project.pbxproj *.xcconfig).freeze
+ BUILD_CONFIG_FILENAMES = %w[project.pbxproj *.xcconfig].freeze
# For the current iteration, we only want to detect when the project targets
# iOS. In the future, we can use the same logic to detect projects that
diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb
index 22104409199..d67b7832bf8 100644
--- a/app/services/projects/download_service.rb
+++ b/app/services/projects/download_service.rb
@@ -28,7 +28,7 @@ module Projects
end
def http?(url)
- url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/
+ url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
end
def valid_domain?(url)
diff --git a/app/services/projects/hashed_storage/migrate_attachments_service.rb b/app/services/projects/hashed_storage/migrate_attachments_service.rb
index 023f8494d99..40c4fd5376c 100644
--- a/app/services/projects/hashed_storage/migrate_attachments_service.rb
+++ b/app/services/projects/hashed_storage/migrate_attachments_service.rb
@@ -6,7 +6,7 @@ module Projects
extend ::Gitlab::Utils::Override
# List of paths that can be excluded while evaluation if a target can be discarded
- DISCARDABLE_PATHS = %w(tmp tmp/cache tmp/work).freeze
+ DISCARDABLE_PATHS = %w[tmp tmp/cache tmp/work].freeze
def initialize(project:, old_disk_path:, logger: nil)
super
diff --git a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
index 09fec9939b9..f52f8551834 100644
--- a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
@@ -101,7 +101,7 @@ module Projects
# The import url must end with '.git' here we ensure it is
def default_endpoint_uri
@default_endpoint_uri ||= import_uri.dup.tap do |uri|
- path = uri.path.gsub(%r(/$), '')
+ path = uri.path.gsub(%r{/$}, '')
path += '.git' unless path.ends_with?('.git')
uri.path = path + LFS_BATCH_API_ENDPOINT
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 40d3e2392c6..a6a2fa87e59 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -120,11 +120,11 @@ module Projects
end
def after_update
- todos_features_changes = %w(
+ todos_features_changes = %w[
issues_access_level
merge_requests_access_level
repository_access_level
- )
+ ]
project_changed_feature_keys = project.project_feature.previous_changes.keys
if project.visibility_level_previous_changes && project.private?
diff --git a/app/services/repositories/base_service.rb b/app/services/repositories/base_service.rb
index b262b4a1f7b..bf7ac2e5fd8 100644
--- a/app/services/repositories/base_service.rb
+++ b/app/services/repositories/base_service.rb
@@ -29,7 +29,7 @@ class Repositories::BaseService < BaseService
end
def move_error(path)
- error = %{Repository "#{path}" could not be moved}
+ error = %(Repository "#{path}" could not be moved)
log_error(error)
error(error)
diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb
index 0fb7dfdb85f..4258898c665 100644
--- a/app/services/repository_archive_clean_up_service.rb
+++ b/app/services/repository_archive_clean_up_service.rb
@@ -37,7 +37,7 @@ class RepositoryArchiveCleanUpService
private
def clean_up_old_archives
- run(%W(find #{path} -mindepth 1 -maxdepth #{MAX_ARCHIVE_DEPTH} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete))
+ run(%W[find #{path} -mindepth 1 -maxdepth #{MAX_ARCHIVE_DEPTH} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete])
end
def clean_up_empty_directories
@@ -45,7 +45,7 @@ class RepositoryArchiveCleanUpService
end
def clean_up_empty_directories_with_depth(depth)
- run(%W(find #{path} -mindepth #{depth} -maxdepth #{depth} -type d -empty -delete))
+ run(%W[find #{path} -mindepth #{depth} -maxdepth #{depth} -type d -empty -delete])
end
def run(cmd)
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index 1fea894a599..1c496aa5e77 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -60,7 +60,7 @@ module ResourceAccessTokens
strong_memoize_attr :username_and_email_generator
def has_permission_to_create?
- %w(project group).include?(resource_type) && can?(current_user, :create_resource_access_tokens, resource)
+ %w[project group].include?(resource_type) && can?(current_user, :create_resource_access_tokens, resource)
end
def create_user
diff --git a/app/services/resource_access_tokens/revoke_service.rb b/app/services/resource_access_tokens/revoke_service.rb
index 2aaf4cc31d2..46c71b04632 100644
--- a/app/services/resource_access_tokens/revoke_service.rb
+++ b/app/services/resource_access_tokens/revoke_service.rb
@@ -38,7 +38,7 @@ module ResourceAccessTokens
end
def can_destroy_token?
- %w(project group).include?(resource.class.name.downcase) && can?(current_user, :destroy_resource_access_tokens, resource)
+ %w[project group].include?(resource.class.name.downcase) && can?(current_user, :destroy_resource_access_tokens, resource)
end
def find_member
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index f4c0a743ef0..24549b1498b 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -6,7 +6,7 @@ module Search
include Gitlab::Utils::StrongMemoize
DEFAULT_SCOPE = 'projects'
- ALLOWED_SCOPES = %w(projects issues merge_requests milestones users).freeze
+ ALLOWED_SCOPES = %w[projects issues merge_requests milestones users].freeze
attr_accessor :current_user, :params
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index 73d46a9ba70..24613dc2564 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -5,7 +5,7 @@ module Search
include Search::Filter
include Gitlab::Utils::StrongMemoize
- ALLOWED_SCOPES = %w(blobs issues merge_requests wiki_blobs commits notes milestones users).freeze
+ ALLOWED_SCOPES = %w[blobs issues merge_requests wiki_blobs commits notes milestones users].freeze
attr_accessor :project, :current_user, :params
diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb
index 662e31a93aa..8cc6458227f 100644
--- a/app/services/snippets/update_service.rb
+++ b/app/services/snippets/update_service.rb
@@ -2,7 +2,7 @@
module Snippets
class UpdateService < Snippets::BaseService
- COMMITTABLE_ATTRIBUTES = %w(file_name content).freeze
+ COMMITTABLE_ATTRIBUTES = %w[file_name content].freeze
UpdateError = Class.new(StandardError)
diff --git a/app/services/todos/destroy/destroyed_issuable_service.rb b/app/services/todos/destroy/destroyed_issuable_service.rb
index 759c430ec7a..6ba286458df 100644
--- a/app/services/todos/destroy/destroyed_issuable_service.rb
+++ b/app/services/todos/destroy/destroyed_issuable_service.rb
@@ -8,7 +8,7 @@ module Todos
# Since we are moving towards work items, in some instances we create todos with
# `target_type: WorkItem` in other instances we still create todos with `target_type: Issue`
# So when an issue/work item is deleted, we just make sure to delete todos for both target types
- BOUND_TARGET_TYPES = %w(Issue WorkItem).freeze
+ BOUND_TARGET_TYPES = %w[Issue WorkItem].freeze
def initialize(target_id, target_type)
@target_id = target_id
diff --git a/app/services/todos/destroy/entity_leave_service.rb b/app/services/todos/destroy/entity_leave_service.rb
index 5b04d2fd3af..387c5ce063a 100644
--- a/app/services/todos/destroy/entity_leave_service.rb
+++ b/app/services/todos/destroy/entity_leave_service.rb
@@ -8,7 +8,7 @@ module Todos
attr_reader :user, :entity
def initialize(user_id, entity_id, entity_type)
- unless %w(Group Project).include?(entity_type)
+ unless %w[Group Project].include?(entity_type)
raise ArgumentError, "#{entity_type} is not an entity user can leave"
end
diff --git a/app/uploaders/design_management/design_v432x230_uploader.rb b/app/uploaders/design_management/design_v432x230_uploader.rb
index 975050c26e4..0f1ebfed4aa 100644
--- a/app/uploaders/design_management/design_v432x230_uploader.rb
+++ b/app/uploaders/design_management/design_v432x230_uploader.rb
@@ -20,7 +20,7 @@ module DesignManagement
#
# We currently choose not to resize `image/svg+xml` for security reasons.
# See https://gitlab.com/gitlab-org/gitlab/issues/207740#note_302766171
- MIME_TYPE_ALLOWLIST = %w(image/png image/jpeg image/bmp image/gif).freeze
+ MIME_TYPE_ALLOWLIST = %w[image/png image/jpeg image/bmp image/gif].freeze
process resize_to_fit: [432, 230]
diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb
index 06bf742a22d..c1ca535b336 100644
--- a/app/uploaders/gitlab_uploader.rb
+++ b/app/uploaders/gitlab_uploader.rb
@@ -5,7 +5,7 @@ class GitlabUploader < CarrierWave::Uploader::Base
class_attribute :storage_location_identifier
- PROTECTED_METHODS = %i(filename cache_dir work_dir store_dir).freeze
+ PROTECTED_METHODS = %i[filename cache_dir work_dir store_dir].freeze
ObjectNotReadyError = Class.new(StandardError)
diff --git a/app/validators/addressable_url_validator.rb b/app/validators/addressable_url_validator.rb
index 3e6ec0b6f29..6dcc089fa73 100644
--- a/app/validators/addressable_url_validator.rb
+++ b/app/validators/addressable_url_validator.rb
@@ -51,7 +51,7 @@ class AddressableUrlValidator < ActiveModel::EachValidator
# tasks that uses that url won't work.
# See https://gitlab.com/gitlab-org/gitlab-foss/issues/66723
BLOCKER_VALIDATE_OPTIONS = {
- schemes: %w(http https),
+ schemes: %w[http https],
ports: [],
allow_localhost: true,
allow_local_network: true,
diff --git a/app/validators/gitlab/zoom_url_validator.rb b/app/validators/gitlab/zoom_url_validator.rb
index c752cec07c2..d3da3977697 100644
--- a/app/validators/gitlab/zoom_url_validator.rb
+++ b/app/validators/gitlab/zoom_url_validator.rb
@@ -8,7 +8,7 @@ module Gitlab
# @example usage
# validates :url, 'gitlab/zoom_url': true
class ZoomUrlValidator < ActiveModel::EachValidator
- ALLOWED_SCHEMES = %w(https).freeze
+ ALLOWED_SCHEMES = %w[https].freeze
def validate_each(record, attribute, value)
links_count = Gitlab::ZoomLinkExtractor.new(value).links.size
diff --git a/app/validators/json_schema_validator.rb b/app/validators/json_schema_validator.rb
index 9c246a114f6..2b03571d43e 100644
--- a/app/validators/json_schema_validator.rb
+++ b/app/validators/json_schema_validator.rb
@@ -12,7 +12,7 @@
class JsonSchemaValidator < ActiveModel::EachValidator
FILENAME_ALLOWED = /\A[a-z0-9_-]*\Z/.freeze
FilenameError = Class.new(StandardError)
- BASE_DIRECTORY = %w(app validators json_schemas).freeze
+ BASE_DIRECTORY = %w[app validators json_schemas].freeze
def initialize(options)
raise ArgumentError, "Expected 'filename' as an argument" unless options[:filename]
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index e2cad2fb3d7..bd0f4577a32 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -1,5 +1,6 @@
- page_title _("Blame"), @blob.path, @ref
- add_page_specific_style 'page_bundles/tree'
+- add_page_specific_style 'page_bundles/projects'
- blame_streaming_url = blame_pages_streaming_url(@id, @project)
- if @blame_mode.streaming? && @blame_pagination.total_extra_pages > 0
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 543bdaf46df..2d9b7ada015 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -2,6 +2,7 @@
- project = @project.present(current_user: current_user)
- ref = local_assigns[:ref] || @ref
- expanded = params[:expanded].present?
+- add_page_specific_style 'page_bundles/projects'
-# If the blob has a RichViewer we preload the content except for GeoJSON since it is handled by Vue
- if blob.rich_viewer && blob.extension != 'geojson'
- add_page_startup_api_call local_assigns.fetch(:viewer_url) { url_for(safe_params.merge(viewer: blob.rich_viewer.type, format: :json)) }
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 1034f06f722..be2bf43cbb9 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -1,6 +1,7 @@
- breadcrumb_title _("Commits")
- add_page_specific_style 'page_bundles/tree'
- add_page_specific_style 'page_bundles/merge_request'
+- add_page_specific_style 'page_bundles/projects'
- page_title _("Commits"), @ref
= content_for :meta_tags do
diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml
index 541b8c1147d..2c53b060c11 100644
--- a/app/views/projects/find_file/show.html.haml
+++ b/app/views/projects/find_file/show.html.haml
@@ -1,5 +1,6 @@
- page_title _("Find File"), @ref
- add_page_specific_style 'page_bundles/tree'
+- add_page_specific_style 'page_bundles/projects'
.file-finder-holder.tree-holder.clearfix.js-file-finder.gl-pt-4{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, format: :json))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @ref)) }
.nav-block.gl-xs-mr-0
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index eb570f999db..6f2a2aacf66 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -1,5 +1,4 @@
- page_title s_("UsageQuota|Usage")
-- add_page_specific_style 'page_bundles/projects_usage_quotas'
- @force_desktop_expanded_sidebar = true
= render Pajamas::AlertComponent.new(title: _('Repository usage recalculation started'),
diff --git a/app/workers/members_destroyer/unassign_issuables_worker.rb b/app/workers/members_destroyer/unassign_issuables_worker.rb
index 2e6ce0005fc..677a1be25ca 100644
--- a/app/workers/members_destroyer/unassign_issuables_worker.rb
+++ b/app/workers/members_destroyer/unassign_issuables_worker.rb
@@ -8,7 +8,7 @@ module MembersDestroyer
sidekiq_options retry: 3
- ENTITY_TYPES = %w(Group Project).freeze
+ ENTITY_TYPES = %w[Group Project].freeze
queue_namespace :unassign_issuables
feature_category :user_management
diff --git a/app/workers/projects/record_target_platforms_worker.rb b/app/workers/projects/record_target_platforms_worker.rb
index bf7210b24a9..bbe0c63cfd1 100644
--- a/app/workers/projects/record_target_platforms_worker.rb
+++ b/app/workers/projects/record_target_platforms_worker.rb
@@ -6,7 +6,7 @@ module Projects
include ExclusiveLeaseGuard
LEASE_TIMEOUT = 1.hour.to_i
- APPLE_PLATFORM_LANGUAGES = %w(swift objective-c).freeze
+ APPLE_PLATFORM_LANGUAGES = %w[swift objective-c].freeze
feature_category :experimentation_activation
data_consistency :always
diff --git a/config/application.rb b/config/application.rb
index adf9f29db98..3f095ee0e10 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -341,7 +341,6 @@ module Gitlab
config.assets.precompile << "page_bundles/project.css"
config.assets.precompile << "page_bundles/projects.css"
config.assets.precompile << "page_bundles/projects_edit.css"
- config.assets.precompile << "page_bundles/projects_usage_quotas.css"
config.assets.precompile << "page_bundles/promotions.css"
config.assets.precompile << "page_bundles/releases.css"
config.assets.precompile << "page_bundles/remote_development.css"
diff --git a/danger/database/clickhouse/Dangerfile b/danger/clickhouse/Dangerfile
index 5a82779ce90..91fa45541e7 100644
--- a/danger/database/clickhouse/Dangerfile
+++ b/danger/clickhouse/Dangerfile
@@ -11,12 +11,17 @@ MSG
CH_UNREVIEWED_LABEL = 'clickhouse::review pending'
CH_APPROVED_LABEL = 'clickhouse::approved'
+CH_URL =
+ 'https://gitlab.com/groups/gitlab-org/maintainers/clickhouse/-/group_members?with_inherited_permissions=exclude'
+
return if stable_branch.valid_stable_branch?
return if helper.mr_labels.include?(CH_UNREVIEWED_LABEL)
+helper.labels_to_add << 'clickhouse' if clickhouse.changes.any?
+
if helper.mr_labels.include?('clickhouse') || clickhouse.changes.any?
message 'This merge request adds or changes files that require a ' \
- 'review from the [GitLab ClickHouse team](https://gitlab.com/groups/gl-clickhouse/-/group_members).'
+ 'review from the [GitLab ClickHouse team](CH_URL).'
markdown(CH_MESSAGE)
diff --git a/danger/plugins/clickhouse.rb b/danger/plugins/clickhouse.rb
new file mode 100644
index 00000000000..324a0e5c1a9
--- /dev/null
+++ b/danger/plugins/clickhouse.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/clickhouse'
+
+module Danger
+ class Clickhouse < ::Danger::Plugin
+ # Put the helper code somewhere it can be tested
+ include Tooling::Danger::Clickhouse
+ end
+end
diff --git a/doc/architecture/blueprints/organization/index.md b/doc/architecture/blueprints/organization/index.md
index 7315e754045..0955d53313d 100644
--- a/doc/architecture/blueprints/organization/index.md
+++ b/doc/architecture/blueprints/organization/index.md
@@ -381,21 +381,7 @@ An alternative approach to building Organizations is to convert top-level Groups
## Frequently Asked Questions
-### Do we expect large SaaS customers to be licensed at the Organization level, for example to have the ability to include multiple top-level Groups under on license?
-
-Yes, this has been discussed with Fulfillment and is part of the post MVC roadmap for Organizations.
-See also [Alignment between Organization and Fulfillment](#alignment-between-organization-and-fulfillment).
-
-### Do we expect to be able to configure alternate GitLab domain names for Organizations (such as `customer.gitlab.com`)?
-
-There is no plan at this point to allow configuration of alternate GitLab domain names.
-We have previously heard that sub-domains bring administrative challenges.
-GitLab Dedicated will be a much better fit for that at this moment.
-
-### Do we expect Organizations to have visibility settings (public/private) of their own? Will visibility remain a property of top-level Groups?
-
-Organizations are public for now but will have their own independent visibility settings.
-See also [When can Users see an Organization?](#when-can-users-see-an-organization).
+See [Organization: Frequently Asked Questions](organization-faq.md).
## Decision Log
diff --git a/doc/architecture/blueprints/organization/organization-faq.md b/doc/architecture/blueprints/organization/organization-faq.md
new file mode 100644
index 00000000000..97bd8f057cc
--- /dev/null
+++ b/doc/architecture/blueprints/organization/organization-faq.md
@@ -0,0 +1,44 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Organization: FAQ'
+---
+
+# Organization: Frequently Asked Questions
+
+## Do we expect large SaaS customers to be licensed at the Organization level, for example to have the ability to include multiple top-level Groups under on license?
+
+Yes, this has been discussed with Fulfillment and is part of the post MVC roadmap for Organizations.
+See also [Alignment between Organization and Fulfillment](index.md#alignment-between-organization-and-fulfillment).
+
+## Do we expect to be able to configure alternate GitLab domain names for Organizations (such as `customer.gitlab.com`)?
+
+There is no plan at this point to allow configuration of alternate GitLab domain names.
+We have previously heard that sub-domains bring administrative challenges.
+GitLab Dedicated will be a much better fit for that at this moment.
+
+## Do we expect Organizations to have visibility settings (public/private) of their own? Will visibility remain a property of top-level Groups?
+
+Organizations are public for now but will have their own independent visibility settings.
+See also [When can Users see an Organization?](index.md#when-can-users-see-an-organization).
+
+## What would the migration of a feature from the top-level Group to the Organization look like?
+
+One of our requirements is that everything needs to be mapped to an Organization.
+Only that way will we achieve the isolation we are striving for.
+For SaaS, all existing Groups and Projects are already mapped to `Org_ID = 1` in the backend.
+`Org_ID = 1` corresponds to the `Default Organization`, meaning that upon Organization rollout, all existing Groups and Projects will be part of the default Organization and will be seen in that context.
+Because we want to achieve as much parity as possible between SaaS and self-managed, self-managed customers would also get everything mapped to the default Organization.
+The difference between SaaS and self-managed is that for SaaS we expect users to create many Organizations, and for self-managed we do not.
+We will control this via a `can_create_organization` application setting that will be enabled by default on SaaS and disabled by default for self-managed users.
+
+Consider whether your feature can support cascading, or in other words, whether the functionality is capable of existing on multiple nested levels without causing conflicts.
+If your feature can support cascading:
+
+- Today, you should add your feature to the top-level Group for both SaaS and self-managed, and to the instance for self-managed.
+- Once the Organization is ready, you would migrate your instance level feature over the Organization object at which point it would be available at both the Organization and top-level Group for all customers.
+
+If your feature cannot support cascading:
+
+- Today, you should add your feature to the top-level Group for SaaS only, and to the instance for self-managed. The top-level Group functionality would be hidden for self-managed users.
+- Once the Organization is ready, you would migrate instance functionality to the Organization for self-managed customers, but hide it at the Organization level for SaaS. On SaaS, users would continue to manage their functionality at the top-level Group, and not at the Organization level. At some point in the future when 99% of paying customers have moved to their own Organization, you could clean things up by introducing a breaking change and unhiding it from the Organization level for all customers (SaaS and self-managed) and removing the functionality from the top-level Group.
diff --git a/doc/user/profile/service_accounts.md b/doc/user/profile/service_accounts.md
index 20fa0325b85..8bb9902d93a 100644
--- a/doc/user/profile/service_accounts.md
+++ b/doc/user/profile/service_accounts.md
@@ -66,7 +66,7 @@ Prerequisite:
This service account is associated with the entire instance, not a specific group
or project in the instance.
-1. [Create a personal access token](../../api/groups.md#create-personal-access-token-for-service-account-user)
+1. [Create a personal access token](../../api/users.md#create-a-personal-access-token)
for the service account user.
You define the scopes for the service account by [setting the scopes for the personal access token](personal_access_tokens.md#personal-access-token-scopes).
diff --git a/package.json b/package.json
index a8719375f5c..8ce6aed9bd7 100644
--- a/package.json
+++ b/package.json
@@ -148,7 +148,7 @@
"gettext-parser": "^6.0.0",
"graphql": "^15.7.2",
"graphql-tag": "^2.11.0",
- "gridstack": "^9.1.1",
+ "gridstack": "^9.2.0",
"highlight.js": "^11.8.0",
"immer": "^9.0.15",
"ipaddr.js": "^1.9.1",
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index 6d7c36065ef..0732e0b8a89 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -75,7 +75,6 @@ module QA
def created_access_token
within_element(:access_token_section) do
- click_element(:toggle_visibility_button, wait: 30)
find_element(:created_access_token_field).value
end
end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 847b2fd2d81..c29da757c3a 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -23,24 +23,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
visit user_confirmation_path(confirmation_token: new_user_token)
end
- def fill_in_sign_up_form(new_user, submit_button_text = 'Register')
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
- fill_in 'new_user_password', with: new_user.password
-
- wait_for_all_requests
-
- expect_username_to_be_validated
-
- click_button submit_button_text
- end
-
- def expect_username_to_be_validated
- expect(page).to have_selector('[data-testid="new_user_username_field"].gl-field-success-outline')
- end
-
def fill_in_welcome_form
select 'Software Developer', from: 'user_role'
click_button 'Get started!'
diff --git a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
index a96ec1f68aa..df39fe492c1 100644
--- a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
+++ b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
@@ -48,7 +48,8 @@ RSpec.describe 'Batch diffs', :js, feature_category: :code_review_workflow do
context 'when user visits a URL with a link directly to to a discussion' do
context 'which is in the first batched page of diffs' do
- it 'scrolls to the correct discussion' do
+ it 'scrolls to the correct discussion',
+ quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410029' } do
page.within get_first_diff do
click_link('just now')
end
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index 444d4a96f9c..8697249ebf5 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -1174,4 +1174,43 @@ describe('common_utils', () => {
});
});
});
+
+ describe('cloneWithoutReferences', () => {
+ it('clones the provided object', () => {
+ const obj = {
+ foo: 'bar',
+ cool: 1337,
+ nested: {
+ peanut: 'butter',
+ },
+ arrays: [0, 1, 2],
+ };
+
+ const cloned = commonUtils.cloneWithoutReferences(obj);
+
+ expect(cloned).toMatchObject({
+ foo: 'bar',
+ cool: 1337,
+ nested: {
+ peanut: 'butter',
+ },
+ arrays: [0, 1, 2],
+ });
+ });
+
+ it('does not persist object references after cloning', () => {
+ const ref = {
+ foo: 'bar',
+ };
+
+ const obj = {
+ ref,
+ };
+
+ const cloned = commonUtils.cloneWithoutReferences(obj);
+
+ expect(cloned.ref).toMatchObject({ foo: 'bar' });
+ expect(cloned.ref === ref).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js b/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
index 88ab51cf135..0ae01083a09 100644
--- a/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
+++ b/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
@@ -5,7 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import ProjectStorageApp from '~/usage_quotas/storage/components/project_storage_app.vue';
-import UsageGraph from '~/usage_quotas/storage/components/usage_graph.vue';
+import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
import {
descendingStorageUsageSort,
getStorageTypesFromProjectStatistics,
@@ -56,7 +56,7 @@ describe('ProjectStorageApp', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findUsagePercentage = () => wrapper.findByTestId('total-usage');
- const findUsageGraph = () => wrapper.findComponent(UsageGraph);
+ const findSectionedPercentageBar = () => wrapper.findComponent(SectionedPercentageBar);
const findProjectDetailsTable = () => wrapper.findByTestId('usage-quotas-project-usage-details');
const findNamespaceDetailsTable = () =>
wrapper.findByTestId('usage-quotas-namespace-usage-details');
@@ -157,7 +157,7 @@ describe('ProjectStorageApp', () => {
});
});
- describe('rendering <usage-graph />', () => {
+ describe('rendering <sectioned-percentage-bar />', () => {
let mockApollo;
beforeEach(async () => {
@@ -168,16 +168,23 @@ describe('ProjectStorageApp', () => {
await waitForPromises();
});
- it('renders usage-graph component if project.statistics exists', () => {
- expect(findUsageGraph().exists()).toBe(true);
+ it('renders sectioned-percentage-bar component if project.statistics exists', () => {
+ expect(findSectionedPercentageBar().exists()).toBe(true);
});
- it('passes project.statistics to usage-graph component', () => {
- const {
- __typename,
- ...statistics
- } = mockGetProjectStorageStatisticsGraphQLResponse.data.project.statistics;
- expect(findUsageGraph().props('rootStorageStatistics')).toMatchObject(statistics);
+ it('passes processed project statistics to sectioned-percentage-bar component', () => {
+ expect(findSectionedPercentageBar().props('sections')).toMatchObject([
+ { formattedValue: '4.58 MiB', id: 'lfsObjects', label: 'LFS', value: 4800000 },
+ { formattedValue: '3.72 MiB', id: 'repository', label: 'Repository', value: 3900000 },
+ { formattedValue: '3.62 MiB', id: 'packages', label: 'Packages', value: 3800000 },
+ {
+ formattedValue: '390.63 KiB',
+ id: 'buildArtifacts',
+ label: 'Job artifacts',
+ value: 400000,
+ },
+ { formattedValue: '292.97 KiB', id: 'wiki', label: 'Wiki', value: 300000 },
+ ]);
});
});
});
diff --git a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js b/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
deleted file mode 100644
index fc116211bf0..00000000000
--- a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import UsageGraph from '~/usage_quotas/storage/components/usage_graph.vue';
-
-let data;
-let wrapper;
-
-function mountComponent({ rootStorageStatistics, limit }) {
- wrapper = shallowMount(UsageGraph, {
- propsData: {
- rootStorageStatistics,
- limit,
- },
- });
-}
-function findStorageTypeUsagesSerialized() {
- return wrapper
- .findAll('[data-testid="storage-type-usage"]')
- .wrappers.map((wp) => wp.element.style.flex);
-}
-
-describe('UsageGraph', () => {
- beforeEach(() => {
- data = {
- rootStorageStatistics: {
- wikiSize: 5000,
- repositorySize: 4000,
- packagesSize: 3000,
- containerRegistrySize: 2500,
- lfsObjectsSize: 2000,
- buildArtifactsSize: 700,
- snippetsSize: 2000,
- storageSize: 17000,
- },
- limit: 2000,
- };
- mountComponent(data);
- });
-
- it('renders the legend in order', () => {
- const types = wrapper.findAll('[data-testid="storage-type-legend"]');
-
- const {
- buildArtifactsSize,
- lfsObjectsSize,
- packagesSize,
- repositorySize,
- wikiSize,
- snippetsSize,
- } = data.rootStorageStatistics;
-
- expect(types.at(0).text()).toMatchInterpolatedText(`Wiki ${numberToHumanSize(wikiSize)}`);
- expect(types.at(1).text()).toMatchInterpolatedText(
- `Repository ${numberToHumanSize(repositorySize)}`,
- );
- expect(types.at(2).text()).toMatchInterpolatedText(
- `Packages ${numberToHumanSize(packagesSize)}`,
- );
- expect(types.at(3).text()).toMatchInterpolatedText(`LFS ${numberToHumanSize(lfsObjectsSize)}`);
- expect(types.at(4).text()).toMatchInterpolatedText(
- `Snippets ${numberToHumanSize(snippetsSize)}`,
- );
- expect(types.at(5).text()).toMatchInterpolatedText(
- `Job artifacts ${numberToHumanSize(buildArtifactsSize)}`,
- );
- });
-
- describe('when storage type is not used', () => {
- beforeEach(() => {
- data.rootStorageStatistics.wikiSize = 0;
- mountComponent(data);
- });
-
- it('filters the storage type', () => {
- expect(wrapper.text()).not.toContain('Wikis');
- });
- });
-
- describe('when there is no storage usage', () => {
- beforeEach(() => {
- data.rootStorageStatistics.storageSize = 0;
- mountComponent(data);
- });
-
- it('does not render', () => {
- expect(wrapper.html()).toEqual('');
- });
- });
-
- describe('when limit is 0', () => {
- beforeEach(() => {
- data.limit = 0;
- mountComponent(data);
- });
-
- it('sets correct flex values', () => {
- expect(findStorageTypeUsagesSerialized()).toStrictEqual([
- '0.29411764705882354',
- '0.23529411764705882',
- '0.17647058823529413',
- '0.11764705882352941',
- '0.11764705882352941',
- '0.041176470588235294',
- ]);
- });
- });
-
- describe('when storage exceeds limit', () => {
- beforeEach(() => {
- data.limit = data.rootStorageStatistics.storageSize - 1;
- mountComponent(data);
- });
-
- it('does render correclty', () => {
- expect(findStorageTypeUsagesSerialized()).toStrictEqual([
- '0.29411764705882354',
- '0.23529411764705882',
- '0.17647058823529413',
- '0.11764705882352941',
- '0.11764705882352941',
- '0.041176470588235294',
- ]);
- });
- });
-});
diff --git a/spec/models/performance_monitoring/prometheus_panel_group_spec.rb b/spec/models/performance_monitoring/prometheus_panel_group_spec.rb
deleted file mode 100644
index 497f80483eb..00000000000
--- a/spec/models/performance_monitoring/prometheus_panel_group_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PerformanceMonitoring::PrometheusPanelGroup do
- let(:json_content) do
- {
- "group" => "Group Title",
- "panels" => [{
- "type" => "area-chart",
- "title" => "Chart Title",
- "y_label" => "Y-Axis",
- "metrics" => [{
- "id" => "metric_of_ages",
- "unit" => "count",
- "label" => "Metric of Ages",
- "query_range" => "http_requests_total"
- }]
- }]
- }
- end
-
- describe '.from_json' do
- subject { described_class.from_json(json_content) }
-
- it 'creates a PrometheusPanelGroup object' do
- expect(subject).to be_a described_class
- expect(subject.group).to eq(json_content['group'])
- expect(subject.panels).to all(be_a PerformanceMonitoring::PrometheusPanel)
- end
-
- describe 'validations' do
- context 'json_content is not a hash' do
- let(:json_content) { nil }
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when group is missing' do
- before do
- json_content.delete('group')
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when panels are missing' do
- before do
- json_content['panels'] = []
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
- end
- end
-end
diff --git a/spec/models/performance_monitoring/prometheus_panel_spec.rb b/spec/models/performance_monitoring/prometheus_panel_spec.rb
index 42dcbbdb8e0..3dc05576826 100644
--- a/spec/models/performance_monitoring/prometheus_panel_spec.rb
+++ b/spec/models/performance_monitoring/prometheus_panel_spec.rb
@@ -30,17 +30,6 @@ RSpec.describe PerformanceMonitoring::PrometheusPanel do
end
describe '.from_json' do
- subject { described_class.from_json(json_content) }
-
- it 'creates a PrometheusPanelGroup object' do
- expect(subject).to be_a described_class
- expect(subject.type).to eq(json_content['type'])
- expect(subject.title).to eq(json_content['title'])
- expect(subject.y_label).to eq(json_content['y_label'])
- expect(subject.weight).to eq(json_content['weight'])
- expect(subject.metrics).to all(be_a PerformanceMonitoring::PrometheusMetric)
- end
-
describe 'validations' do
context 'json_content is not a hash' do
let(:json_content) { nil }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e7afa3dedd5..40384e067aa 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -178,6 +178,7 @@ RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :feature
config.include Devise::Test::IntegrationHelpers, type: :request
config.include LoginHelpers, type: :feature
+ config.include SignUpHelpers, type: :feature
config.include SearchHelpers, type: :feature
config.include WaitHelpers, type: :feature
config.include WaitForRequests, type: :feature
diff --git a/spec/support/helpers/sign_up_helpers.rb b/spec/support/helpers/sign_up_helpers.rb
new file mode 100644
index 00000000000..258a1e5456f
--- /dev/null
+++ b/spec/support/helpers/sign_up_helpers.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module SignUpHelpers
+ def fill_in_sign_up_form(new_user, submit_button_text = 'Register')
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ fill_in 'new_user_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+ fill_in 'new_user_password', with: new_user.password
+
+ wait_for_all_requests
+
+ expect_username_to_be_validated
+
+ yield if block_given?
+
+ click_button submit_button_text
+ end
+
+ private
+
+ def expect_username_to_be_validated
+ expect(page).to have_selector('[data-testid="new_user_username_field"].gl-field-success-outline')
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb
new file mode 100644
index 00000000000..0fef5269ab6
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::Import::AdvanceStage do |factory:|
+ let_it_be(:project) { create(:project) }
+ let_it_be_with_reload(:import_state) { create(factory, :started, project: project, jid: '123') }
+ let(:worker) { described_class.new }
+ let(:next_stage) { :finish }
+
+ describe '#perform', :clean_gitlab_redis_shared_state do
+ context 'when the project no longer exists' do
+ it 'does not perform any work' do
+ expect(worker).not_to receive(:wait_for_jobs)
+
+ worker.perform(non_existing_record_id, { '123' => 2 }, next_stage)
+ end
+ end
+
+ context 'when there are remaining jobs' do
+ it 'reschedules itself' do
+ expect(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({ '123' => 1 })
+
+ expect(described_class)
+ .to receive(:perform_in)
+ .with(described_class::INTERVAL, project.id, { '123' => 1 }, next_stage)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ context 'when the project import is not running' do
+ before do
+ import_state.update_column(:status, :failed)
+ end
+
+ it 'does not perform any work' do
+ expect(worker).not_to receive(:wait_for_jobs)
+ expect(described_class).not_to receive(:perform_in)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ it 'clears the JobWaiter cache' do
+ expect(Gitlab::JobWaiter).to receive(:delete_key).with('123')
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+ end
+ end
+
+ context 'when there are no remaining jobs' do
+ before do
+ allow(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({})
+ end
+
+ it 'schedules the next stage' do
+ next_worker = described_class::STAGES[next_stage]
+
+ expect_next_found_instance_of(import_state.class) do |state|
+ expect(state).to receive(:refresh_jid_expiration)
+ end
+
+ expect(next_worker).to receive(:perform_async).with(project.id)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ it 'raises KeyError when the stage name is invalid' do
+ expect { worker.perform(project.id, { '123' => 2 }, :kittens) }
+ .to raise_error(KeyError)
+ end
+ end
+ end
+
+ describe '#wait_for_jobs' do
+ it 'waits for jobs to complete and returns a new pair of keys to wait for' do
+ waiter1 = instance_double("Gitlab::JobWaiter", jobs_remaining: 1, key: '123')
+ waiter2 = instance_double("Gitlab::JobWaiter", jobs_remaining: 0, key: '456')
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(2, '123')
+ .and_return(waiter1)
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(1, '456')
+ .and_return(waiter2)
+
+ expect(waiter1)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ expect(waiter2)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ new_waiters = worker.wait_for_jobs({ '123' => 2, '456' => 1 })
+
+ expect(new_waiters).to eq({ '123' => 1 })
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb
new file mode 100644
index 00000000000..14e93440422
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :import_state
+end
diff --git a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
index 2faa28a365e..60c117a2a90 100644
--- a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
@@ -2,125 +2,6 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::AdvanceStageWorker, :clean_gitlab_redis_shared_state, feature_category: :importers do
- let(:project) { create(:project) }
- let(:import_state) { create(:import_state, project: project, jid: '123') }
- let(:worker) { described_class.new }
-
- describe '#perform' do
- context 'when the project no longer exists' do
- it 'does not perform any work' do
- expect(worker).not_to receive(:wait_for_jobs)
-
- worker.perform(-1, { '123' => 2 }, :finish)
- end
- end
-
- context 'when there are remaining jobs' do
- before do
- allow(worker)
- .to receive(:find_import_state)
- .and_return(import_state)
- end
-
- it 'reschedules itself' do
- expect(worker)
- .to receive(:wait_for_jobs)
- .with({ '123' => 2 })
- .and_return({ '123' => 1 })
-
- expect(described_class)
- .to receive(:perform_in)
- .with(described_class::INTERVAL, project.id, { '123' => 1 }, :finish)
-
- worker.perform(project.id, { '123' => 2 }, :finish)
- end
-
- context 'when import state is nil' do
- let(:import_state) { nil }
-
- it 'clears the JobWaiter cache and does not perform any work' do
- expect(Gitlab::JobWaiter).to receive(:delete_key).with('123')
- expect(worker).not_to receive(:wait_for_jobs)
-
- worker.perform(project.id, { '123' => 2 }, :finish)
- end
- end
- end
-
- context 'when there are no remaining jobs' do
- before do
- allow(worker)
- .to receive(:find_import_state)
- .and_return(import_state)
-
- allow(worker)
- .to receive(:wait_for_jobs)
- .with({ '123' => 2 })
- .and_return({})
- end
-
- it 'schedules the next stage' do
- expect(import_state)
- .to receive(:refresh_jid_expiration)
-
- expect(Gitlab::GithubImport::Stage::FinishImportWorker)
- .to receive(:perform_async)
- .with(project.id)
-
- worker.perform(project.id, { '123' => 2 }, :finish)
- end
-
- it 'raises KeyError when the stage name is invalid' do
- expect { worker.perform(project.id, { '123' => 2 }, :kittens) }
- .to raise_error(KeyError)
- end
- end
- end
-
- describe '#wait_for_jobs' do
- it 'waits for jobs to complete and returns a new pair of keys to wait for' do
- waiter1 = double(:waiter1, jobs_remaining: 1, key: '123')
- waiter2 = double(:waiter2, jobs_remaining: 0, key: '456')
-
- expect(Gitlab::JobWaiter)
- .to receive(:new)
- .ordered
- .with(2, '123')
- .and_return(waiter1)
-
- expect(Gitlab::JobWaiter)
- .to receive(:new)
- .ordered
- .with(1, '456')
- .and_return(waiter2)
-
- expect(waiter1)
- .to receive(:wait)
- .with(described_class::BLOCKING_WAIT_TIME)
-
- expect(waiter2)
- .to receive(:wait)
- .with(described_class::BLOCKING_WAIT_TIME)
-
- new_waiters = worker.wait_for_jobs({ '123' => 2, '456' => 1 })
-
- expect(new_waiters).to eq({ '123' => 1 })
- end
- end
-
- describe '#find_import_state' do
- it 'returns a ProjectImportState' do
- import_state.update_column(:status, 'started')
-
- found = worker.find_import_state(project.id)
-
- expect(found).to be_an_instance_of(ProjectImportState)
- expect(found.attributes.keys).to match_array(%w(id jid))
- end
-
- it 'returns nil if the project import is not running' do
- expect(worker.find_import_state(project.id)).to be_nil
- end
- end
+RSpec.describe Gitlab::GithubImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :import_state
end
diff --git a/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb
new file mode 100644
index 00000000000..d7c5d8aba4d
--- /dev/null
+++ b/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::JiraImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :jira_import_state
+end
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index 90166438ca0..62563da8151 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -98,6 +98,10 @@ module Tooling
\.gitlab/ci/frontend\.gitlab-ci\.yml
)\z}x => %i[frontend tooling],
+ %r{\A(ee/)?db/click_house/} => :clickhouse,
+ %r{\Agems/click_house-client/} => :clickhouse,
+ %r{click((-)?|(_)?)house} => :clickhouse,
+
%r{\A((ee|jh)/)?db/(geo/)?(migrate|post_migrate)/} => [:database],
%r{\A((ee|jh)/)?db/(?!fixtures)[^/]+} => [:database],
%r{\A((ee|jh)/)?lib/gitlab/(database|background_migration|sql)(/|\.rb)} => [:database, :backend],
@@ -106,10 +110,6 @@ module Tooling
%r{\A((ee|jh)/)?app/finders/} => [:database, :backend],
%r{\Arubocop/cop/migration(/|\.rb)} => :database,
- %r{\A(ee/)?db/click_house/} => :clickhouse,
- %r{\Agems/click_house-client/} => :clickhouse,
- %r{click(-)?house} => :clickhouse,
-
%r{\Alib/gitlab/ci/templates} => :ci_template,
%r{\A((ee|jh)/)?spec/features/} => :test,
diff --git a/yarn.lock b/yarn.lock
index aa10a04accf..45197c6feba 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7171,10 +7171,10 @@ graphql@^15.7.2:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.7.2.tgz#85ab0eeb83722977151b3feb4d631b5f2ab287ef"
integrity sha512-AnnKk7hFQFmU/2I9YSQf3xw44ctnSFCfp3zE0N6W174gqe9fWG/2rKaKxROK7CcI3XtERpjEKFqts8o319Kf7A==
-gridstack@^9.1.1:
- version "9.1.1"
- resolved "https://registry.yarnpkg.com/gridstack/-/gridstack-9.1.1.tgz#76695d6eec4ed693e4c53ed410e043c12e19af24"
- integrity sha512-DgRLROhJ2JPOOzfn+irsLpnkwgUuY3w0fX7HinEjAk5SbvNYBKKEuN89Di22CM2IX2ehNY85OzxxletnBuAnlQ==
+gridstack@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/gridstack/-/gridstack-9.2.0.tgz#1a415185649a8ebe8a92f9aebea14183f2996d25"
+ integrity sha512-+uWb4p1Za3j6OfvumXzuWQ4EcDh3kZZFLr0vONLPdrtGPJuxb73TjqttEu4igW7iP2Y80kewfYnNT6kQ0blJQQ==
gzip-size@^6.0.0:
version "6.0.0"