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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml3
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.checksum4
-rw-r--r--Gemfile.lock8
-rw-r--r--app/assets/javascripts/import_entities/components/import_status.vue8
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue8
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue79
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/mutations.js40
-rw-r--r--app/assets/javascripts/import_entities/import_projects/utils.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue6
-rw-r--r--app/assets/stylesheets/utilities.scss5
-rw-r--r--app/controllers/projects/issues_controller.rb6
-rw-r--r--app/finders/ci/pipeline_schedules_finder.rb47
-rw-r--r--app/graphql/mutations/concerns/mutations/assignable.rb2
-rw-r--r--app/graphql/mutations/issues/set_confidential.rb2
-rw-r--r--app/graphql/mutations/issues/set_due_date.rb2
-rw-r--r--app/graphql/mutations/issues/set_escalation_status.rb2
-rw-r--r--app/graphql/mutations/issues/set_locked.rb2
-rw-r--r--app/graphql/mutations/issues/set_severity.rb2
-rw-r--r--app/graphql/mutations/issues/update.rb2
-rw-r--r--app/graphql/mutations/work_items/update.rb2
-rw-r--r--app/graphql/mutations/work_items/update_task.rb2
-rw-r--r--app/graphql/resolvers/data_transfer_resolver.rb57
-rw-r--r--app/graphql/resolvers/project_pipeline_schedules_resolver.rb9
-rw-r--r--app/graphql/types/data_transfer/base_type.rb13
-rw-r--r--app/graphql/types/data_transfer/egress_node_type.rb37
-rw-r--r--app/graphql/types/data_transfer/group_data_transfer_type.rb10
-rw-r--r--app/graphql/types/data_transfer/project_data_transfer_type.rb20
-rw-r--r--app/graphql/types/group_type.rb5
-rw-r--r--app/graphql/types/issue_type.rb2
-rw-r--r--app/graphql/types/project_type.rb5
-rw-r--r--app/helpers/application_settings_helper.rb7
-rw-r--r--app/models/ci/group_variable.rb7
-rw-r--r--app/models/ci/job_artifact.rb3
-rw-r--r--app/models/ci/variable.rb7
-rw-r--r--app/services/boards/issues/move_service.rb2
-rw-r--r--app/services/error_tracking/issue_update_service.rb2
-rw-r--r--app/services/issuable/clone/base_service.rb2
-rw-r--r--app/services/issues/after_create_service.rb5
-rw-r--r--app/services/issues/close_service.rb10
-rw-r--r--app/services/issues/duplicate_service.rb7
-rw-r--r--app/services/issues/referenced_merge_requests_service.rb5
-rw-r--r--app/services/issues/related_branches_service.rb7
-rw-r--r--app/services/issues/reopen_service.rb13
-rw-r--r--app/services/issues/reorder_service.rb7
-rw-r--r--app/services/issues/update_service.rb15
-rw-r--r--app/services/issues/zoom_link_service.rb4
-rw-r--r--app/services/merge_requests/assign_issues_service.rb2
-rw-r--r--app/services/merge_requests/post_merge_service.rb2
-rw-r--r--app/services/milestones/destroy_service.rb2
-rw-r--r--app/services/tasks_to_be_done/base_service.rb2
-rw-r--r--app/services/work_items/task_list_reference_removal_service.rb2
-rw-r--r--app/services/work_items/task_list_reference_replacement_service.rb2
-rw-r--r--app/services/work_items/update_service.rb4
-rw-r--r--app/views/admin/application_settings/_external_authorization_service_form.html.haml3
-rw-r--r--app/workers/incident_management/close_incident_worker.rb2
-rw-r--r--app/workers/issues/close_worker.rb2
-rw-r--r--app/workers/merge_requests/close_issue_worker.rb2
-rw-r--r--app/workers/new_issue_worker.rb2
-rw-r--r--config/feature_flags/development/data_transfer_monitoring.yml8
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/9_fast_gettext.rb4
-rw-r--r--config/initializers_before_autoloader/001_fast_gettext.rb30
-rw-r--r--config/object_store_settings.rb8
-rw-r--r--db/migrate/20230210181214_add_allow_deploy_tokens_and_keys_with_external_authn_to_application_settings.rb8
-rw-r--r--db/migrate/20230214142447_remove_text_limit_from_ci_job_artifacts_original_filename.rb17
-rw-r--r--db/migrate/20230214142813_remove_ci_job_artifacts_original_filename.rb16
-rw-r--r--db/schema_migrations/202302101812141
-rw-r--r--db/schema_migrations/202302141424471
-rw-r--r--db/schema_migrations/202302141428131
-rw-r--r--db/structure.sql5
-rw-r--r--doc/administration/geo/index.md2
-rw-r--r--doc/api/graphql/reference/index.md80
-rw-r--r--doc/update/index.md8
-rw-r--r--doc/user/project/import/bitbucket.md6
-rw-r--r--doc/user/project/import/bitbucket_server.md5
-rw-r--r--doc/user/project/import/fogbugz.md6
-rw-r--r--doc/user/project/import/gitea.md4
-rw-r--r--doc/user/project/import/github.md5
-rw-r--r--doc/user/project/import/manifest.md9
-rw-r--r--lib/api/draft_notes.rb31
-rw-r--r--lib/api/issues.rb11
-rw-r--r--lib/api/time_tracking_endpoints.rb4
-rw-r--r--lib/gitlab/api_authentication/token_resolver.rb4
-rw-r--r--lib/gitlab/auth/auth_finders.rb2
-rw-r--r--lib/gitlab/ci/config/external/mapper/verifier.rb2
-rw-r--r--lib/gitlab/external_authorization/config.rb6
-rw-r--r--lib/gitlab/git_access.rb4
-rw-r--r--lib/gitlab/i18n.rb38
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb2
-rw-r--r--lib/gitlab/quick_actions/issue_actions.rb2
-rw-r--r--lib/gitlab/redis/multi_store.rb16
-rw-r--r--lib/gitlab/slash_commands/issue_close.rb2
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/page/project/import/github.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb4
-rwxr-xr-xscripts/ingest-reports-to-siem-devo45
-rw-r--r--spec/config/settings_spec.rb8
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb2
-rw-r--r--spec/finders/ci/pipeline_schedules_finder_spec.rb43
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js1
-rw-r--r--spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js67
-rw-r--r--spec/frontend/import_entities/import_projects/store/mutations_spec.js26
-rw-r--r--spec/frontend/import_entities/import_projects/utils_spec.js2
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js1
-rw-r--r--spec/graphql/resolvers/data_transfer_resolver_spec.rb31
-rw-r--r--spec/lib/gitlab/api_authentication/token_resolver_spec.rb6
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb6
-rw-r--r--spec/lib/gitlab/external_authorization/config_spec.rb23
-rw-r--r--spec/lib/gitlab/git_access_spec.rb8
-rw-r--r--spec/lib/gitlab/github_import/logger_spec.rb12
-rw-r--r--spec/lib/gitlab/import/logger_spec.rb12
-rw-r--r--spec/lib/gitlab/import_export/import_export_equivalence_spec.rb5
-rw-r--r--spec/lib/gitlab/json_logger_spec.rb8
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb18
-rw-r--r--spec/models/ci/group_variable_spec.rb7
-rw-r--r--spec/models/ci/variable_spec.rb7
-rw-r--r--spec/requests/api/ci/variables_spec.rb129
-rw-r--r--spec/requests/api/draft_notes_spec.rb58
-rw-r--r--spec/requests/api/group_variables_spec.rb105
-rw-r--r--spec/serializers/issue_entity_spec.rb2
-rw-r--r--spec/services/issues/after_create_service_spec.rb2
-rw-r--r--spec/services/issues/close_service_spec.rb22
-rw-r--r--spec/services/issues/duplicate_service_spec.rb2
-rw-r--r--spec/services/issues/referenced_merge_requests_service_spec.rb2
-rw-r--r--spec/services/issues/related_branches_service_spec.rb4
-rw-r--r--spec/services/issues/reopen_service_spec.rb6
-rw-r--r--spec/services/issues/reorder_service_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb24
-rw-r--r--spec/services/issues/zoom_link_service_spec.rb2
-rw-r--r--spec/services/tasks_to_be_done/base_service_spec.rb2
-rw-r--r--spec/services/work_items/update_service_spec.rb6
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb2
-rw-r--r--spec/support/import_export/common_util.rb14
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/issuable_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/services/updating_mentions_shared_examples.rb3
-rw-r--r--spec/workers/incident_management/close_incident_worker_spec.rb2
-rw-r--r--spec/workers/issues/close_worker_spec.rb2
-rw-r--r--spec/workers/merge_requests/close_issue_worker_spec.rb2
144 files changed, 1215 insertions, 428 deletions
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index b87e5ad9bba..3242ca29d75 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -104,7 +104,8 @@ yarn-audit-dependency_scanning:
- mkdir ~/.aws
- '[[ -z "${AWS_SIEM_REPORT_INGESTION_CREDENTIALS_FILE}" ]] || mv "${AWS_SIEM_REPORT_INGESTION_CREDENTIALS_FILE}" ~/.aws/credentials'
- npm install --no-save --ignore-scripts @aws-sdk/client-s3@3.49.0
- - scripts/ingest-reports-to-siem
+ - scripts/ingest-reports-to-siem || true # Allow legacy report to fail as we'll remove it in the future anyway
+ - scripts/ingest-reports-to-siem-devo
artifacts:
paths:
- gl-dependency-scanning-report.json
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 9541010d62b..4a3cf30f37d 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-f223d8cbcb6319356cb9f746252b15e541695d2f
+7910fc0e132402d3ab22cef73924aef360598f35
diff --git a/Gemfile b/Gemfile
index a2b82ba0b61..92fec94f8c7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -348,7 +348,7 @@ gem 'pg_query', '~> 2.2', '>= 2.2.1'
gem 'premailer-rails', '~> 1.10.3'
-gem 'gitlab-labkit', '~> 0.30.1'
+gem 'gitlab-labkit', '~> 0.31.0'
gem 'thrift', '>= 0.16.0'
# I18n
@@ -373,7 +373,7 @@ gem 'prometheus-client-mmap', '~> 0.17', require: 'prometheus/client'
gem 'warning', '~> 1.3.0'
group :development do
- gem 'lefthook', '~> 1.2.8', require: false
+ gem 'lefthook', '~> 1.2.9', require: false
gem 'rubocop'
gem 'solargraph', '~> 0.47.2', require: false
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 12d317089fb..0351e8d258a 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -203,7 +203,7 @@
{"name":"gitlab-dangerfiles","version":"3.7.0","platform":"ruby","checksum":"35c5bc42e60c575ab5701192ca2384ab414b14c2963602b39e143b1aaeb7e54d"},
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
{"name":"gitlab-fog-azure-rm","version":"1.4.0","platform":"ruby","checksum":"af4163c32b028aa5208814a3f4765a5817d50527e6c61931f766bf18a2e0eb7e"},
-{"name":"gitlab-labkit","version":"0.30.1","platform":"ruby","checksum":"bdedbd86014c83dfd6a50d20dbc1709697bba2bb9e3666383e5f28cbd312b113"},
+{"name":"gitlab-labkit","version":"0.31.0","platform":"ruby","checksum":"5b044c4ededd7005e6d1ca5a53ac5f9d7a4d12a7363673fbc898e1844246ed1f"},
{"name":"gitlab-license","version":"2.2.1","platform":"ruby","checksum":"39fcf6be8b2887df8afe01b5dcbae8d08b7c5d937ff56b0fb40484a8c4f02d30"},
{"name":"gitlab-mail_room","version":"0.0.9","platform":"ruby","checksum":"6700374b5c0aa9d9ad4e711aeb677f0b7d415a6d01d3baa699efab25349d851c"},
{"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"},
@@ -314,7 +314,7 @@
{"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"},
{"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"},
{"name":"launchy","version":"2.5.0","platform":"ruby","checksum":"954243c4255920982ce682f89a42e76372dba94770bf09c23a523e204bdebef5"},
-{"name":"lefthook","version":"1.2.8","platform":"ruby","checksum":"3776de22e0a3de8fc8c4c58d8b42cd5eeb1cd291232a09a8dc5335f0ad505a7c"},
+{"name":"lefthook","version":"1.2.9","platform":"ruby","checksum":"1fd4a768e08fc624e756597fc628b3c7991267325974a7a5cc169595b425701d"},
{"name":"letter_opener","version":"1.7.0","platform":"ruby","checksum":"095bc0d58e006e5b43ea7d219e64ecf2de8d1f7d9dafc432040a845cf59b4725"},
{"name":"letter_opener_web","version":"2.0.0","platform":"ruby","checksum":"33860ad41e1785d75456500e8ca8bba8ed71ee6eaf08a98d06bbab67c5577b6f"},
{"name":"libyajl2","version":"1.2.0","platform":"ruby","checksum":"1117cd1e48db013b626e36269bbf1cef210538ca6d2e62d3fa3db9ded005b258"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 5d070d45736..c55cc5d2f45 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -584,7 +584,7 @@ GEM
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.30.1)
+ gitlab-labkit (0.31.0)
actionpack (>= 5.0.0, < 8.0.0)
activesupport (>= 5.0.0, < 8.0.0)
grpc (>= 1.37)
@@ -845,7 +845,7 @@ GEM
kramdown (~> 2.0)
launchy (2.5.0)
addressable (~> 2.7)
- lefthook (1.2.8)
+ lefthook (1.2.9)
letter_opener (1.7.0)
launchy (~> 2.2)
letter_opener_web (2.0.0)
@@ -1679,7 +1679,7 @@ DEPENDENCIES
gitlab-dangerfiles (~> 3.7.0)
gitlab-experiment (~> 0.7.1)
gitlab-fog-azure-rm (~> 1.4.0)
- gitlab-labkit (~> 0.30.1)
+ gitlab-labkit (~> 0.31.0)
gitlab-license (~> 2.2.1)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.9.0)
@@ -1738,7 +1738,7 @@ DEPENDENCIES
knapsack (~> 1.21.1)
kramdown (~> 2.3.1)
kubeclient (~> 4.9.3)!
- lefthook (~> 1.2.8)
+ lefthook (~> 1.2.9)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
licensee (~> 9.15)
diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue
index e2a4cca289d..6dc0b2cec24 100644
--- a/app/assets/javascripts/import_entities/components/import_status.vue
+++ b/app/assets/javascripts/import_entities/components/import_status.vue
@@ -65,7 +65,9 @@ const STATUS_MAP = {
};
function isIncompleteImport(stats) {
- return Object.keys(stats.fetched).some((key) => stats.fetched[key] !== stats.imported[key]);
+ return Object.keys(stats?.fetched ?? []).some(
+ (key) => stats.fetched[key] !== stats.imported[key],
+ );
}
export default {
@@ -91,7 +93,9 @@ export default {
computed: {
knownStats() {
const knownStatisticKeys = Object.keys(STATISTIC_ITEMS);
- return Object.keys(this.stats.fetched).filter((key) => knownStatisticKeys.includes(key));
+ return Object.keys(this.stats?.fetched ?? []).filter((key) =>
+ knownStatisticKeys.includes(key),
+ );
},
hasStats() {
diff --git a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
index 63a36f1a79f..aaa37f145aa 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
@@ -182,16 +182,16 @@ export default {
<div v-if="repositories.length" class="gl-w-full">
<table>
<thead class="gl-border-0 gl-border-solid gl-border-t-1 gl-border-gray-100">
- <th class="import-jobs-from-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ <th class="gl-w-half gl-p-4 gl-vertical-align-top gl-border-b-1">
{{ fromHeaderText }}
</th>
- <th class="import-jobs-to-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ <th class="gl-w-half gl-p-4 gl-vertical-align-top gl-border-b-1">
{{ __('To GitLab') }}
</th>
- <th class="import-jobs-status-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ <th class="gl-p-4 gl-vertical-align-top gl-border-b-1">
{{ __('Status') }}
</th>
- <th class="import-jobs-cta-col gl-p-4 gl-vertical-align-top gl-border-b-1"></th>
+ <th class="gl-p-4 gl-vertical-align-top gl-border-b-1"></th>
</thead>
<tbody>
<template v-for="repo in repositories">
diff --git a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
index da5dcfa71e3..265cca9070e 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
@@ -9,6 +9,8 @@ import {
GlDropdownDivider,
GlDropdownSectionHeader,
GlTooltip,
+ GlSprintf,
+ GlTooltipDirective,
} from '@gitlab/ui';
import { mapState, mapGetters, mapActions } from 'vuex';
import { __ } from '~/locale';
@@ -32,6 +34,10 @@ export default {
GlBadge,
GlLink,
GlTooltip,
+ GlSprintf,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
},
props: {
repo: {
@@ -53,6 +59,12 @@ export default {
},
},
+ data() {
+ return {
+ isSelectedForReimport: false,
+ };
+ },
+
computed: {
...mapState(['ciCdOnly']),
...mapGetters(['getImportTarget']),
@@ -94,7 +106,11 @@ export default {
},
importButtonText() {
- return this.ciCdOnly ? __('Connect') : __('Import');
+ if (this.ciCdOnly) {
+ return __('Connect');
+ }
+
+ return this.isFinished ? __('Re-import') : __('Import');
},
newNameInput: {
@@ -115,6 +131,22 @@ export default {
importTarget: { ...this.importTarget, ...changedValues },
});
},
+
+ handleImportRepo() {
+ if (this.isFinished && !this.isSelectedForReimport) {
+ this.isSelectedForReimport = true;
+ this.$nextTick(() => {
+ this.$refs.newNameInput.$el.focus();
+ });
+ } else {
+ this.isSelectedForReimport = false;
+
+ this.fetchImport({
+ repoId: this.repo.importSource.id,
+ optionalStages: this.optionalStages,
+ });
+ }
+ },
},
helpUrl: helpPagePath('/user/project/import/github.md'),
@@ -132,6 +164,20 @@ export default {
>{{ repo.importSource.fullName }}
<gl-icon v-if="repo.importSource.providerLink" name="external-link" />
</gl-link>
+ <div v-if="isFinished" class="gl-font-sm">
+ <gl-sprintf :message="s__('BulkImport|Last imported to %{link}')">
+ <template #link>
+ <gl-link
+ :href="repo.importedProject.fullPath"
+ class="gl-font-sm"
+ target="_blank"
+ data-qa-selector="go_to_project_link"
+ >
+ {{ displayFullPath }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
</td>
<td
class="gl-display-flex gl-sm-flex-wrap gl-p-4 gl-pt-5 gl-vertical-align-top"
@@ -139,7 +185,7 @@ export default {
data-qa-selector="project_path_content"
>
<template v-if="repo.importSource.target">{{ repo.importSource.target }}</template>
- <template v-else-if="isImportNotStarted">
+ <template v-else-if="isImportNotStarted || isSelectedForReimport">
<div class="gl-display-flex gl-align-items-stretch gl-w-full">
<import-group-dropdown #default="{ namespaces }" :text="importTarget.targetNamespace">
<template v-if="namespaces.length">
@@ -166,6 +212,7 @@ export default {
/
</div>
<gl-form-input
+ ref="newNameInput"
v-model="newNameInput"
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
data-qa-selector="project_path_field"
@@ -177,7 +224,7 @@ export default {
<td class="gl-p-4 gl-vertical-align-top" data-qa-selector="import_status_indicator">
<import-status :status="importStatus" :stats="stats" />
</td>
- <td data-testid="actions" class="gl-vertical-align-top gl-pt-4">
+ <td data-testid="actions" class="gl-vertical-align-top gl-pt-4 gl-white-space-nowrap">
<gl-tooltip :target="() => $refs.cancelButton.$el">
<div class="gl-text-left">
<p class="gl-mb-5 gl-font-weight-bold">{{ s__('ImportProjects|Cancel import') }}</p>
@@ -199,22 +246,26 @@ export default {
@click="cancelImport({ repoId: repo.importSource.id })"
/>
<gl-button
- v-if="isFinished"
- class="btn btn-default"
- :href="repo.importedProject.fullPath"
- rel="noreferrer noopener"
- target="_blank"
- data-qa-selector="go_to_project_button"
- >{{ __('Go to project') }}
- </gl-button>
- <gl-button
- v-if="isImportNotStarted"
+ v-if="isImportNotStarted || isFinished"
type="button"
data-qa-selector="import_button"
- @click="fetchImport({ repoId: repo.importSource.id, optionalStages })"
+ @click="handleImportRepo()"
>
{{ importButtonText }}
</gl-button>
+ <gl-icon
+ v-if="isFinished"
+ v-gl-tooltip
+ :size="16"
+ name="information-o"
+ :title="
+ s__(
+ 'ImportProjects|Re-import creates a new project. It does not sync with the existing project.',
+ )
+ "
+ class="gl-ml-3"
+ />
+
<gl-badge v-else-if="isIncompatible" variant="danger">{{
__('Incompatible project')
}}</gl-badge>
diff --git a/app/assets/javascripts/import_entities/import_projects/store/mutations.js b/app/assets/javascripts/import_entities/import_projects/store/mutations.js
index 8b2e0364d7a..734e7b10a77 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/mutations.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/mutations.js
@@ -2,16 +2,6 @@ import Vue from 'vue';
import { STATUSES } from '../../constants';
import * as types from './mutation_types';
-const makeNewImportedProject = (importedProject) => ({
- importSource: {
- id: importedProject.id,
- fullName: importedProject.importSource,
- sanitizedName: importedProject.name,
- providerLink: importedProject.providerLink,
- },
- importedProject: { ...importedProject },
-});
-
const makeNewIncompatibleProject = (project) => ({
importSource: { ...project, incompatible: true },
importedProject: null,
@@ -55,14 +45,6 @@ export default {
// Legacy code path, will be removed when all importers will be switched to new pagination format
// https://gitlab.com/gitlab-org/gitlab/-/issues/27370#note_379034091
- const newImportedProjects = processLegacyEntries({
- newRepositories: repositories.importedProjects.filter(
- (p) => p.importStatus !== STATUSES.CANCELED,
- ),
- existingRepositories: state.repositories,
- factory: makeNewImportedProject,
- });
-
const incompatibleRepos = repositories.incompatibleRepos ?? [];
const newIncompatibleProjects = processLegacyEntries({
newRepositories: incompatibleRepos,
@@ -70,16 +52,22 @@ export default {
factory: makeNewIncompatibleProject,
});
- const existingProjects = [...newImportedProjects, ...state.repositories];
- const existingProjectNames = new Set(existingProjects.map((p) => p.importSource.fullName));
+ const existingProjectNames = new Set(state.repositories.map((p) => p.importSource.fullName));
+ const importedProjects = [...(repositories.importedProjects ?? [])].reverse();
const newProjects = repositories.providerRepos
.filter((project) => !existingProjectNames.has(project.fullName))
- .map((project) => ({
- importSource: project,
- importedProject: null,
- }));
+ .map((project) => {
+ const importedProject = importedProjects.find(
+ (p) => p.providerLink === project.providerLink,
+ );
+
+ return {
+ importSource: project,
+ importedProject,
+ };
+ });
- state.repositories = [...existingProjects, ...newProjects, ...newIncompatibleProjects];
+ state.repositories = [...state.repositories, ...newProjects, ...newIncompatibleProjects];
if (incompatibleRepos.length === 0 && repositories.providerRepos.length === 0) {
state.pageInfo.page -= 1;
@@ -113,7 +101,7 @@ export default {
[types.RECEIVE_IMPORT_ERROR](state, repoId) {
const existingRepo = state.repositories.find((r) => r.importSource.id === repoId);
- existingRepo.importedProject = null;
+ existingRepo.importedProject.importStatus = STATUSES.FAILED;
},
[types.RECEIVE_JOBS_SUCCESS](state, updatedProjects) {
diff --git a/app/assets/javascripts/import_entities/import_projects/utils.js b/app/assets/javascripts/import_entities/import_projects/utils.js
index c4c9e544c1e..08a96160ee3 100644
--- a/app/assets/javascripts/import_entities/import_projects/utils.js
+++ b/app/assets/javascripts/import_entities/import_projects/utils.js
@@ -11,7 +11,7 @@ export function getImportStatus(project) {
export function isProjectImportable(project) {
return (
!isIncompatible(project) &&
- [STATUSES.NONE, STATUSES.CANCELED].includes(getImportStatus(project))
+ [STATUSES.NONE, STATUSES.CANCELED, STATUSES.FAILED].includes(getImportStatus(project))
);
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index 19701125978..83d718f5a54 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -86,10 +86,8 @@ export default {
</span>
<template v-else>
<span class="gl-ml-0! gl-text-body! gl-flex-grow-1 gl-w-full gl-md-w-auto gl-mr-2">
- <bold-text :message="$options.i18n.shouldBeResolved" />
- <span v-if="!userPermissions.canMerge">
- {{ $options.i18n.usersWriteBranches }}
- </span>
+ <bold-text v-if="userPermissions.canMerge" :message="$options.i18n.shouldBeResolved" />
+ <bold-text v-else :message="$options.i18n.usersWriteBranches" />
</span>
</template>
</template>
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 34f8a1622f4..af98d59251f 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -277,11 +277,6 @@ to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1709
flex-flow: row wrap;
}
-// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2098
-.gl-max-w-0 {
- max-width: 0;
-}
-
.gl-isolate {
isolation: isolate;
}
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 1f578763c0c..21227d62023 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -205,7 +205,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def reorder
- service = ::Issues::ReorderService.new(project: project, current_user: current_user, params: reorder_params)
+ service = ::Issues::ReorderService.new(container: project, current_user: current_user, params: reorder_params)
if service.execute(issue)
head :ok
@@ -216,7 +216,7 @@ class Projects::IssuesController < Projects::ApplicationController
def related_branches
@related_branches = ::Issues::RelatedBranchesService
- .new(project: project, current_user: current_user)
+ .new(container: project, current_user: current_user)
.execute(issue)
.map { |branch| branch.merge(link: branch_link(branch)) }
@@ -371,7 +371,7 @@ class Projects::IssuesController < Projects::ApplicationController
def update_service
spam_params = ::Spam::SpamParams.new_from_request(request: request)
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: issue_params, spam_params: spam_params)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: issue_params, spam_params: spam_params)
end
def finder_type
diff --git a/app/finders/ci/pipeline_schedules_finder.rb b/app/finders/ci/pipeline_schedules_finder.rb
index 2544c8c3254..e5ee65a02c8 100644
--- a/app/finders/ci/pipeline_schedules_finder.rb
+++ b/app/finders/ci/pipeline_schedules_finder.rb
@@ -9,20 +9,39 @@ module Ci
@pipeline_schedules = project.pipeline_schedules
end
- # rubocop: disable CodeReuse/ActiveRecord
- def execute(scope: nil)
- scoped_schedules =
- case scope
- when 'active'
- pipeline_schedules.active
- when 'inactive'
- pipeline_schedules.inactive
- else
- pipeline_schedules
- end
-
- scoped_schedules.order(id: :desc)
+ def execute(scope: nil, ids: nil)
+ items = pipeline_schedules
+ items = by_ids(items, ids)
+ items = by_scope(items, scope)
+
+ sort_items(items)
+ end
+
+ private
+
+ def by_ids(items, ids)
+ if ids.present?
+ items.id_in(ids)
+ else
+ items
+ end
+ end
+
+ def by_scope(items, scope)
+ case scope
+ when 'active'
+ items.active
+ when 'inactive'
+ items.inactive
+ else
+ items
+ end
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ def sort_items(items)
+ items.order(id: :desc)
end
- # rubocop: enable CodeReuse/ActiveRecord
+ # rubocop:enable CodeReuse/ActiveRecord
end
end
diff --git a/app/graphql/mutations/concerns/mutations/assignable.rb b/app/graphql/mutations/concerns/mutations/assignable.rb
index 86f37207a2d..189c926fcc4 100644
--- a/app/graphql/mutations/concerns/mutations/assignable.rb
+++ b/app/graphql/mutations/concerns/mutations/assignable.rb
@@ -33,7 +33,7 @@ module Mutations
def assign!(resource, users, operation_mode)
update_service_class.new(
- project: resource.project,
+ **update_service_class.constructor_container_arg(resource.project),
current_user: current_user,
params: { assignee_ids: assignee_ids(resource, users, operation_mode) }
).execute(resource)
diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb
index b795d66c16f..08578881a13 100644
--- a/app/graphql/mutations/issues/set_confidential.rb
+++ b/app/graphql/mutations/issues/set_confidential.rb
@@ -19,7 +19,7 @@ module Mutations
# spam_params so a check can be performed.
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params)
.execute(issue)
check_spam_action_response!(issue)
diff --git a/app/graphql/mutations/issues/set_due_date.rb b/app/graphql/mutations/issues/set_due_date.rb
index 70b76da4fcb..e361d241083 100644
--- a/app/graphql/mutations/issues/set_due_date.rb
+++ b/app/graphql/mutations/issues/set_due_date.rb
@@ -14,7 +14,7 @@ module Mutations
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { due_date: due_date })
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { due_date: due_date })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/set_escalation_status.rb b/app/graphql/mutations/issues/set_escalation_status.rb
index 4f3fcb4886d..13286034ada 100644
--- a/app/graphql/mutations/issues/set_escalation_status.rb
+++ b/app/graphql/mutations/issues/set_escalation_status.rb
@@ -17,7 +17,7 @@ module Mutations
check_feature_availability!(issue)
::Issues::UpdateService.new(
- project: project,
+ container: project,
current_user: current_user,
params: { escalation_status: { status: status } }
).execute(issue)
diff --git a/app/graphql/mutations/issues/set_locked.rb b/app/graphql/mutations/issues/set_locked.rb
index 93b31350bbf..86ad129f4cb 100644
--- a/app/graphql/mutations/issues/set_locked.rb
+++ b/app/graphql/mutations/issues/set_locked.rb
@@ -13,7 +13,7 @@ module Mutations
def resolve(project_path:, iid:, locked:)
issue = authorized_find!(project_path: project_path, iid: iid)
- ::Issues::UpdateService.new(project: issue.project, current_user: current_user, params: { discussion_locked: locked })
+ ::Issues::UpdateService.new(container: issue.project, current_user: current_user, params: { discussion_locked: locked })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/set_severity.rb b/app/graphql/mutations/issues/set_severity.rb
index 4a24bfd18ef..68d7fb7d0c0 100644
--- a/app/graphql/mutations/issues/set_severity.rb
+++ b/app/graphql/mutations/issues/set_severity.rb
@@ -15,7 +15,7 @@ module Mutations
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { severity: severity })
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { severity: severity })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index f55e42b994c..b5af048dc07 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -42,7 +42,7 @@ module Mutations
args = parse_arguments(args)
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue)
{
issue: issue,
diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb
index 741a0ca771f..db6af38d82e 100644
--- a/app/graphql/mutations/work_items/update.rb
+++ b/app/graphql/mutations/work_items/update.rb
@@ -25,7 +25,7 @@ module Mutations
interpret_quick_actions!(work_item, current_user, widget_params, attributes)
update_result = ::WorkItems::UpdateService.new(
- project: work_item.project,
+ container: work_item.project,
current_user: current_user,
params: attributes,
widget_params: widget_params,
diff --git a/app/graphql/mutations/work_items/update_task.rb b/app/graphql/mutations/work_items/update_task.rb
index aeb4f1d0f06..8dcc4c325ea 100644
--- a/app/graphql/mutations/work_items/update_task.rb
+++ b/app/graphql/mutations/work_items/update_task.rb
@@ -32,7 +32,7 @@ module Mutations
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
::WorkItems::UpdateService.new(
- project: task.project,
+ container: task.project,
current_user: current_user,
params: task_data_hash.except(:id),
spam_params: spam_params
diff --git a/app/graphql/resolvers/data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer_resolver.rb
new file mode 100644
index 00000000000..1a240d2811f
--- /dev/null
+++ b/app/graphql/resolvers/data_transfer_resolver.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class DataTransferResolver < BaseResolver
+ argument :from, Types::DateType,
+ description: 'Retain egress data for 1 year. Current month will increase dynamically as egress occurs.',
+ required: false
+ argument :to, Types::DateType,
+ description: 'End date for the data.',
+ required: false
+
+ type ::Types::DataTransfer::BaseType, null: false
+
+ def self.source
+ raise NotImplementedError
+ end
+
+ def self.project
+ Class.new(self) do
+ type Types::DataTransfer::ProjectDataTransferType, null: false
+
+ def self.source
+ "Project"
+ end
+ end
+ end
+
+ def self.group
+ Class.new(self) do
+ type Types::DataTransfer::GroupDataTransferType, null: false
+
+ def self.source
+ "Group"
+ end
+ end
+ end
+
+ def resolve(**_args)
+ return unless Feature.enabled?(:data_transfer_monitoring)
+
+ start_date = Date.new(2023, 0o1, 0o1)
+ date_for_index = ->(i) { (start_date + i.months).strftime('%Y-%m-%d') }
+
+ nodes = 0.upto(3).map do |i|
+ {
+ date: date_for_index.call(i),
+ repository_egress: 250_000,
+ artifacts_egress: 250_000,
+ packages_egress: 250_000,
+ registry_egress: 250_000
+ }
+ end
+
+ { egress_nodes: nodes }
+ end
+ end
+end
diff --git a/app/graphql/resolvers/project_pipeline_schedules_resolver.rb b/app/graphql/resolvers/project_pipeline_schedules_resolver.rb
index eb980f72717..32887385d26 100644
--- a/app/graphql/resolvers/project_pipeline_schedules_resolver.rb
+++ b/app/graphql/resolvers/project_pipeline_schedules_resolver.rb
@@ -10,8 +10,13 @@ module Resolvers
required: false,
description: 'Filter pipeline schedules by active status.'
- def resolve(status: nil)
- ::Ci::PipelineSchedulesFinder.new(project).execute(scope: status)
+ argument :ids, [GraphQL::Types::ID],
+ required: false,
+ default_value: nil,
+ description: 'Filter pipeline schedules by IDs.'
+
+ def resolve(status: nil, ids: nil)
+ ::Ci::PipelineSchedulesFinder.new(project).execute(scope: status, ids: ids)
end
end
end
diff --git a/app/graphql/types/data_transfer/base_type.rb b/app/graphql/types/data_transfer/base_type.rb
new file mode 100644
index 00000000000..e077612bfd5
--- /dev/null
+++ b/app/graphql/types/data_transfer/base_type.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module DataTransfer
+ class BaseType < BaseObject
+ authorize
+
+ field :egress_nodes, type: Types::DataTransfer::EgressNodeType.connection_type,
+ description: 'Data nodes.',
+ null: true # disallow null once data_transfer_monitoring feature flag is rolled-out!
+ end
+ end
+end
diff --git a/app/graphql/types/data_transfer/egress_node_type.rb b/app/graphql/types/data_transfer/egress_node_type.rb
new file mode 100644
index 00000000000..a050540999f
--- /dev/null
+++ b/app/graphql/types/data_transfer/egress_node_type.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Types
+ module DataTransfer
+ class EgressNodeType < BaseObject
+ authorize
+
+ field :date, GraphQL::Types::String,
+ description: 'First day of the node range. There is one node per month.',
+ null: false
+
+ field :total_egress, GraphQL::Types::BigInt,
+ description: 'Total egress for that project in that period of time.',
+ null: false
+
+ field :repository_egress, GraphQL::Types::BigInt,
+ description: 'Repository egress for that project in that period of time.',
+ null: false
+
+ field :artifacts_egress, GraphQL::Types::BigInt,
+ description: 'Artifacts egress for that project in that period of time.',
+ null: false
+
+ field :packages_egress, GraphQL::Types::BigInt,
+ description: 'Packages egress for that project in that period of time.',
+ null: false
+
+ field :registry_egress, GraphQL::Types::BigInt,
+ description: 'Registery egress for that project in that period of time.',
+ null: false
+
+ def total_egress
+ object.values.select { |x| x.is_a?(Integer) }.sum
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/data_transfer/group_data_transfer_type.rb b/app/graphql/types/data_transfer/group_data_transfer_type.rb
new file mode 100644
index 00000000000..a9a353e10e8
--- /dev/null
+++ b/app/graphql/types/data_transfer/group_data_transfer_type.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Types
+ module DataTransfer
+ class GroupDataTransferType < BaseType
+ graphql_name 'GroupDataTransfer'
+ authorize
+ end
+ end
+end
diff --git a/app/graphql/types/data_transfer/project_data_transfer_type.rb b/app/graphql/types/data_transfer/project_data_transfer_type.rb
new file mode 100644
index 00000000000..f385aa20a7e
--- /dev/null
+++ b/app/graphql/types/data_transfer/project_data_transfer_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module DataTransfer
+ class ProjectDataTransferType < BaseType
+ graphql_name 'ProjectDataTransfer'
+ authorize
+
+ field :total_egress, GraphQL::Types::BigInt,
+ description: 'Total egress for that project in that period of time.',
+ null: true # disallow null once data_transfer_monitoring feature flag is rolled-out!
+
+ def total_egress(**_)
+ return unless Feature.enabled?(:data_transfer_monitoring)
+
+ 40_000_000
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index ad149d039fa..05783161bf5 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -239,6 +239,11 @@ module Types
description: 'Releases belonging to projects in the group.',
resolver: Resolvers::GroupReleasesResolver
+ field :data_transfer, Types::DataTransfer::GroupDataTransferType,
+ null: true,
+ resolver: Resolvers::DataTransferResolver.group,
+ description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.'
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
LabelsFinder
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index de0d5cc417d..1e5833a5cf0 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -190,7 +190,7 @@ module Types
def related_merge_requests
# rubocop: disable CodeReuse/ActiveRecord
MergeRequest.where(
- id: ::Issues::ReferencedMergeRequestsService.new(project: object.project, current_user: current_user)
+ id: ::Issues::ReferencedMergeRequestsService.new(container: object.project, current_user: current_user)
.execute(object)
.first
.map(&:id)
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 2fe9ac7e155..6fc76699590 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -566,6 +566,11 @@ module Types
resolver: ::Resolvers::Ci::ProjectRunnersResolver,
description: "Find runners visible to the current user."
+ field :data_transfer, Types::DataTransfer::ProjectDataTransferType,
+ null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out!
+ resolver: Resolvers::DataTransferResolver.project,
+ description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.'
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 084e44e1e2e..3abaae98c29 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -167,6 +167,10 @@ module ApplicationSettingsHelper
" using their classification label.")
end
+ def external_authorization_allow_token_help_text
+ s_("ExternalAuthorization|Does not apply if service URL is specified.")
+ end
+
def external_authorization_timeout_help_text
s_("ExternalAuthorization|Period GitLab waits for a response from the external "\
"service. If there is no response, access is denied. Default: 0.5 seconds.")
@@ -499,7 +503,8 @@ module ApplicationSettingsHelper
:external_authorization_service_default_label,
:external_authorization_service_enabled,
:external_authorization_service_timeout,
- :external_authorization_service_url
+ :external_authorization_service_url,
+ :allow_deploy_tokens_and_keys_with_external_authn
]
end
diff --git a/app/models/ci/group_variable.rb b/app/models/ci/group_variable.rb
index 508aaa5a63c..b03c46a164f 100644
--- a/app/models/ci/group_variable.rb
+++ b/app/models/ci/group_variable.rb
@@ -3,9 +3,11 @@
module Ci
class GroupVariable < Ci::ApplicationRecord
include Ci::HasVariable
- include Presentable
include Ci::Maskable
include Ci::RawVariable
+ include Limitable
+ include Presentable
+
prepend HasEnvironmentScope
belongs_to :group, class_name: "::Group"
@@ -21,6 +23,9 @@ module Ci
scope :by_environment_scope, -> (environment_scope) { where(environment_scope: environment_scope) }
scope :for_groups, ->(group_ids) { where(group_id: group_ids) }
+ self.limit_name = 'group_ci_variables'
+ self.limit_scope = :group
+
def audit_details
key
end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index d5be9ffdcc9..89a3d269a43 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -134,9 +134,6 @@ module Ci
belongs_to :project
belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
- # We will start using this column once we complete https://gitlab.com/gitlab-org/gitlab/-/issues/285597
- ignore_column :original_filename, remove_with: '14.7', remove_after: '2022-11-22'
-
mount_file_store_uploader JobArtifactUploader, skip_store_file: true
before_save :set_size, if: :file_changed?
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index f4e17b5d812..23fe89c38df 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -3,9 +3,11 @@
module Ci
class Variable < Ci::ApplicationRecord
include Ci::HasVariable
- include Presentable
include Ci::Maskable
include Ci::RawVariable
+ include Limitable
+ include Presentable
+
prepend HasEnvironmentScope
belongs_to :project
@@ -20,6 +22,9 @@ module Ci
scope :unprotected, -> { where(protected: false) }
scope :by_environment_scope, -> (environment_scope) { where(environment_scope: environment_scope) }
+ self.limit_name = 'project_ci_variables'
+ self.limit_scope = :project
+
def audit_details
key
end
diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb
index 4de4d7c8f69..e80ff9cf857 100644
--- a/app/services/boards/issues/move_service.rb
+++ b/app/services/boards/issues/move_service.rb
@@ -52,7 +52,7 @@ module Boards
end
def update(issue, issue_modification_params)
- ::Issues::UpdateService.new(project: issue.project, current_user: current_user, params: issue_modification_params).execute(issue)
+ ::Issues::UpdateService.new(container: issue.project, current_user: current_user, params: issue_modification_params).execute(issue)
end
def moving_to_list_items_relation
diff --git a/app/services/error_tracking/issue_update_service.rb b/app/services/error_tracking/issue_update_service.rb
index ca5e8d656a6..f5ce7da0de7 100644
--- a/app/services/error_tracking/issue_update_service.rb
+++ b/app/services/error_tracking/issue_update_service.rb
@@ -37,7 +37,7 @@ module ErrorTracking
def close_issue(issue)
Issues::CloseService
- .new(project: project, current_user: current_user)
+ .new(container: project, current_user: current_user)
.execute(issue, system_note: false)
end
diff --git a/app/services/issuable/clone/base_service.rb b/app/services/issuable/clone/base_service.rb
index 3d0abece1a2..02beaaf5d83 100644
--- a/app/services/issuable/clone/base_service.rb
+++ b/app/services/issuable/clone/base_service.rb
@@ -82,7 +82,7 @@ module Issuable
end
def close_issue
- close_service = Issues::CloseService.new(project: old_project, current_user: current_user)
+ close_service = Issues::CloseService.new(container: old_project, current_user: current_user)
close_service.execute(original_entity, notifications: false, system_note: true)
end
diff --git a/app/services/issues/after_create_service.rb b/app/services/issues/after_create_service.rb
index 5d10eca2979..011a78029c8 100644
--- a/app/services/issues/after_create_service.rb
+++ b/app/services/issues/after_create_service.rb
@@ -2,6 +2,11 @@
module Issues
class AfterCreateService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
def execute(issue)
todo_service.new_issue(issue, current_user)
delete_milestone_total_issue_counter_cache(issue.milestone)
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 4f6a859e20e..9fde1cc2ac2 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -2,6 +2,11 @@
module Issues
class CloseService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
# Closes the supplied issue if the current user is able to do so.
def execute(issue, commit: nil, notifications: true, system_note: true, skip_authorization: false)
return issue unless can_close?(issue, skip_authorization: skip_authorization)
@@ -51,6 +56,11 @@ module Issues
private
+ # TODO: remove once MergeRequests::CloseService or IssuableBaseService method is changed.
+ def self.constructor_container_arg(value)
+ { container: value }
+ end
+
def can_close?(issue, skip_authorization: false)
skip_authorization || can?(current_user, :update_issue, issue) || issue.is_a?(ExternalIssue)
end
diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb
index 9547698d916..a3213c50f86 100644
--- a/app/services/issues/duplicate_service.rb
+++ b/app/services/issues/duplicate_service.rb
@@ -2,6 +2,11 @@
module Issues
class DuplicateService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
def execute(duplicate_issue, canonical_issue)
return if canonical_issue == duplicate_issue
return unless can?(current_user, :update_issue, duplicate_issue)
@@ -10,7 +15,7 @@ module Issues
create_issue_duplicate_note(duplicate_issue, canonical_issue)
create_issue_canonical_note(canonical_issue, duplicate_issue)
- close_service.new(project: project, current_user: current_user).execute(duplicate_issue)
+ close_service.new(container: project, current_user: current_user).execute(duplicate_issue)
duplicate_issue.update(duplicated_to: canonical_issue)
relate_two_issues(duplicate_issue, canonical_issue)
diff --git a/app/services/issues/referenced_merge_requests_service.rb b/app/services/issues/referenced_merge_requests_service.rb
index a69cd324b1e..ba03927136a 100644
--- a/app/services/issues/referenced_merge_requests_service.rb
+++ b/app/services/issues/referenced_merge_requests_service.rb
@@ -2,6 +2,11 @@
module Issues
class ReferencedMergeRequestsService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def execute(issue)
referenced = referenced_merge_requests(issue)
diff --git a/app/services/issues/related_branches_service.rb b/app/services/issues/related_branches_service.rb
index 2ecd3e561c9..3f4413fdfd7 100644
--- a/app/services/issues/related_branches_service.rb
+++ b/app/services/issues/related_branches_service.rb
@@ -4,6 +4,11 @@
# those with a merge request open referencing the current issue.
module Issues
class RelatedBranchesService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
def execute(issue)
branch_names_with_mrs = branches_with_merge_request_for(issue)
branches = branches_with_iid_of(issue).reject { |b| branch_names_with_mrs.include?(b[:name]) }
@@ -27,7 +32,7 @@ module Issues
def branches_with_merge_request_for(issue)
Issues::ReferencedMergeRequestsService
- .new(project: project, current_user: current_user)
+ .new(container: project, current_user: current_user)
.referenced_merge_requests(issue)
.map(&:source_branch)
end
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index f4f81e9455a..ebcf2fb5c83 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -2,6 +2,11 @@
module Issues
class ReopenService < Issues::BaseService
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
def execute(issue, skip_authorization: false)
return issue unless can_reopen?(issue, skip_authorization: skip_authorization)
@@ -22,6 +27,14 @@ module Issues
private
+ # overriding this because IssuableBaseService#constructor_container_arg returns { project: value }
+ # Issues::ReopenService constructor signature is different now, it takes container instead of project also
+ # IssuableBaseService#change_state dynamically picks one of the `Issues::ReopenService`, `Epics::ReopenService` or
+ # MergeRequests::ReopenService, so we need this method to return { }container: value } for Issues::ReopenService
+ def self.constructor_container_arg(value)
+ { container: value }
+ end
+
def can_reopen?(issue, skip_authorization: false)
skip_authorization || can?(current_user, :reopen_issue, issue)
end
diff --git a/app/services/issues/reorder_service.rb b/app/services/issues/reorder_service.rb
index 5443d41ac30..059b4196b23 100644
--- a/app/services/issues/reorder_service.rb
+++ b/app/services/issues/reorder_service.rb
@@ -4,6 +4,11 @@ module Issues
class ReorderService < Issues::BaseService
include Gitlab::Utils::StrongMemoize
+ # TODO: this is to be removed once we get to rename the IssuableBaseService project param to container
+ def initialize(container:, current_user: nil, params: {})
+ super(project: container, current_user: current_user, params: params)
+ end
+
def execute(issue)
return false unless can?(current_user, :update_issue, issue)
return false unless move_between_ids
@@ -14,7 +19,7 @@ module Issues
private
def update(issue, attrs)
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: attrs).execute(issue)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: attrs).execute(issue)
rescue ActiveRecord::RecordNotFound
false
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index a185ff374ed..71324b3f044 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -5,8 +5,8 @@ module Issues
# NOTE: For Issues::UpdateService, we default the spam_params to nil, because spam_checking is not
# necessary in many cases, and we don't want to require every caller to explicitly pass it as nil
# to disable spam checking.
- def initialize(project:, current_user: nil, params: {}, spam_params: nil)
- super(project: project, current_user: current_user, params: params)
+ def initialize(container:, current_user: nil, params: {}, spam_params: nil)
+ super(project: container, current_user: current_user, params: params)
@spam_params = spam_params
end
@@ -96,7 +96,7 @@ module Issues
canonical_issue = IssuesFinder.new(current_user).find_by(id: canonical_issue_id)
if canonical_issue
- Issues::DuplicateService.new(project: project, current_user: current_user).execute(issue, canonical_issue)
+ Issues::DuplicateService.new(container: project, current_user: current_user).execute(issue, canonical_issue)
end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -116,6 +116,15 @@ module Issues
attr_reader :spam_params
+ # TODO: remove this once MergeRequests::UpdateService#initialize is changed to take container as named argument.
+ #
+ # Issues::UpdateService is used together with MergeRequests::UpdateService in Mutations::Assignable#assign! method
+ # however MergeRequests::UpdateService#initialize still takes `project` as param and Issues::UpdateService is being
+ # changed to take `container` as param. So we are adding this workaround in the meantime.
+ def self.constructor_container_arg(value)
+ { container: value }
+ end
+
def handle_quick_actions(issue)
# Do not handle quick actions unless the work item is the default Issue.
# The available quick actions for a work item depend on its type and widgets.
diff --git a/app/services/issues/zoom_link_service.rb b/app/services/issues/zoom_link_service.rb
index 1ce459aa7e6..4144c293990 100644
--- a/app/services/issues/zoom_link_service.rb
+++ b/app/services/issues/zoom_link_service.rb
@@ -2,8 +2,8 @@
module Issues
class ZoomLinkService < Issues::BaseService
- def initialize(project:, current_user:, params:)
- super
+ def initialize(container:, current_user:, params:)
+ super(project: container, current_user: current_user, params: params)
@issue = params.fetch(:issue)
@added_meeting = ZoomMeeting.canonical_meeting(@issue)
diff --git a/app/services/merge_requests/assign_issues_service.rb b/app/services/merge_requests/assign_issues_service.rb
index c107280efb1..54283ea0676 100644
--- a/app/services/merge_requests/assign_issues_service.rb
+++ b/app/services/merge_requests/assign_issues_service.rb
@@ -14,7 +14,7 @@ module MergeRequests
def execute
assignable_issues.each do |issue|
- Issues::UpdateService.new(project: issue.project, current_user: current_user, params: { assignee_ids: [current_user.id] }).execute(issue)
+ Issues::UpdateService.new(container: issue.project, current_user: current_user, params: { assignee_ids: [current_user.id] }).execute(issue)
end
{
diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb
index 9fca2b0d19e..e32895a3cb6 100644
--- a/app/services/merge_requests/post_merge_service.rb
+++ b/app/services/merge_requests/post_merge_service.rb
@@ -55,7 +55,7 @@ module MergeRequests
merge_request.id
)
else
- Issues::CloseService.new(project: project, current_user: current_user).execute(issue, commit: merge_request)
+ Issues::CloseService.new(container: project, current_user: current_user).execute(issue, commit: merge_request)
end
end
end
diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb
index c348e2a58a3..191a8711cbd 100644
--- a/app/services/milestones/destroy_service.rb
+++ b/app/services/milestones/destroy_service.rb
@@ -7,7 +7,7 @@ module Milestones
update_params = { milestone_id: nil, skip_milestone_email: true }
milestone.issues.each do |issue|
- Issues::UpdateService.new(project: parent, current_user: current_user, params: update_params).execute(issue)
+ Issues::UpdateService.new(container: parent, current_user: current_user, params: update_params).execute(issue)
end
milestone.merge_requests.each do |merge_request|
diff --git a/app/services/tasks_to_be_done/base_service.rb b/app/services/tasks_to_be_done/base_service.rb
index 3dd53a2f09c..5851a2cb9e5 100644
--- a/app/services/tasks_to_be_done/base_service.rb
+++ b/app/services/tasks_to_be_done/base_service.rb
@@ -16,7 +16,7 @@ module TasksToBeDone
def execute
if (issue = existing_task_issue)
- update_service = Issues::UpdateService.new(project: project, current_user: current_user, params: { add_assignee_ids: params[:assignee_ids] })
+ update_service = Issues::UpdateService.new(container: project, current_user: current_user, params: { add_assignee_ids: params[:assignee_ids] })
update_service.execute(issue)
else
build_service = Issues::BuildService.new(container: project, current_user: current_user, params: params)
diff --git a/app/services/work_items/task_list_reference_removal_service.rb b/app/services/work_items/task_list_reference_removal_service.rb
index 9152580bef0..843b03906ac 100644
--- a/app/services/work_items/task_list_reference_removal_service.rb
+++ b/app/services/work_items/task_list_reference_removal_service.rb
@@ -39,7 +39,7 @@ module WorkItems
end
::WorkItems::UpdateService.new(
- project: @work_item.project,
+ container: @work_item.project,
current_user: @current_user,
params: { description: source_lines.join("\n"), lock_version: @lock_version }
).execute(@work_item)
diff --git a/app/services/work_items/task_list_reference_replacement_service.rb b/app/services/work_items/task_list_reference_replacement_service.rb
index b098d67561b..d81576909d9 100644
--- a/app/services/work_items/task_list_reference_replacement_service.rb
+++ b/app/services/work_items/task_list_reference_replacement_service.rb
@@ -34,7 +34,7 @@ module WorkItems
remove_additional_lines!(source_lines)
::WorkItems::UpdateService.new(
- project: @work_item.project,
+ container: @work_item.project,
current_user: @current_user,
params: { description: source_lines.join("\n"), lock_version: @lock_version }
).execute(@work_item)
diff --git a/app/services/work_items/update_service.rb b/app/services/work_items/update_service.rb
index 1351445f6f3..d4acadbc851 100644
--- a/app/services/work_items/update_service.rb
+++ b/app/services/work_items/update_service.rb
@@ -4,10 +4,10 @@ module WorkItems
class UpdateService < ::Issues::UpdateService
include WidgetableService
- def initialize(project:, current_user: nil, params: {}, spam_params: nil, widget_params: {})
+ def initialize(container:, current_user: nil, params: {}, spam_params: nil, widget_params: {})
params[:widget_params] = true if widget_params.present?
- super(project: project, current_user: current_user, params: params, spam_params: nil)
+ super(container: container, current_user: current_user, params: params, spam_params: spam_params)
@widget_params = widget_params
end
diff --git a/app/views/admin/application_settings/_external_authorization_service_form.html.haml b/app/views/admin/application_settings/_external_authorization_service_form.html.haml
index a5e10846488..1b62083849b 100644
--- a/app/views/admin/application_settings/_external_authorization_service_form.html.haml
+++ b/app/views/admin/application_settings/_external_authorization_service_form.html.haml
@@ -17,6 +17,9 @@
= f.gitlab_ui_checkbox_component :external_authorization_service_enabled,
s_('ExternalAuthorization|Enable classification control using an external service'),
help_text: external_authorization_description
+ = f.gitlab_ui_checkbox_component :allow_deploy_tokens_and_keys_with_external_authn,
+ s_('ExternalAuthorization|Allow deploy tokens and deploy keys to be used with external authorization'),
+ help_text: external_authorization_allow_token_help_text
.form-group
= f.label :external_authorization_service_url, s_('ExternalAuthorization|Service URL'), class: 'label-bold'
= f.text_field :external_authorization_service_url, class: 'form-control gl-form-input'
diff --git a/app/workers/incident_management/close_incident_worker.rb b/app/workers/incident_management/close_incident_worker.rb
index 7d45a6785ea..6b3e1c5321b 100644
--- a/app/workers/incident_management/close_incident_worker.rb
+++ b/app/workers/incident_management/close_incident_worker.rb
@@ -30,7 +30,7 @@ module IncidentManagement
def close_incident(incident)
::Issues::CloseService
- .new(project: incident.project, current_user: user)
+ .new(container: incident.project, current_user: user)
.execute(incident, system_note: false)
end
diff --git a/app/workers/issues/close_worker.rb b/app/workers/issues/close_worker.rb
index 0d540ee8c4f..343f50cd7cf 100644
--- a/app/workers/issues/close_worker.rb
+++ b/app/workers/issues/close_worker.rb
@@ -42,7 +42,7 @@ module Issues
end
commit = Commit.build_from_sidekiq_hash(project, params["commit_hash"])
- service = Issues::CloseService.new(project: project, current_user: author)
+ service = Issues::CloseService.new(container: project, current_user: author)
service.execute(issue, commit: commit)
end
diff --git a/app/workers/merge_requests/close_issue_worker.rb b/app/workers/merge_requests/close_issue_worker.rb
index 8c3ba1bc5ab..5ac48423d41 100644
--- a/app/workers/merge_requests/close_issue_worker.rb
+++ b/app/workers/merge_requests/close_issue_worker.rb
@@ -45,7 +45,7 @@ module MergeRequests
end
Issues::CloseService
- .new(project: project, current_user: user)
+ .new(container: project, current_user: user)
.execute(issue, commit: merge_request)
end
end
diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb
index e14f0dc7dfe..07699a50e36 100644
--- a/app/workers/new_issue_worker.rb
+++ b/app/workers/new_issue_worker.rb
@@ -26,7 +26,7 @@ class NewIssueWorker # rubocop:disable Scalability/IdempotentWorker
issuable.create_cross_references!(user)
Issues::AfterCreateService
- .new(project: issuable.project, current_user: user)
+ .new(container: issuable.project, current_user: user)
.execute(issuable)
end
end
diff --git a/config/feature_flags/development/data_transfer_monitoring.yml b/config/feature_flags/development/data_transfer_monitoring.yml
new file mode 100644
index 00000000000..1675bf2de1d
--- /dev/null
+++ b/config/feature_flags/development/data_transfer_monitoring.yml
@@ -0,0 +1,8 @@
+---
+name: data_transfer_monitoring
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110211
+rollout_issue_url:
+milestone: '15.9'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 1927d15d72b..7f615370a90 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -903,6 +903,8 @@ Settings['repositories'] ||= Settingslogic.new({})
Settings.repositories['storages'] ||= {}
Settings.repositories.storages.each do |key, storage|
+ next if Settings.repositories.storages[key].is_a?(Gitlab::GitalyClient::StorageSettings)
+
Settings.repositories.storages[key] = Gitlab::GitalyClient::StorageSettings.new(storage)
end
diff --git a/config/initializers/9_fast_gettext.rb b/config/initializers/9_fast_gettext.rb
deleted file mode 100644
index 0c28a1b7ce8..00000000000
--- a/config/initializers/9_fast_gettext.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-FastGettext.default_available_locales = Gitlab::I18n.available_locales
-I18n.available_locales = Gitlab::I18n.available_locales
diff --git a/config/initializers_before_autoloader/001_fast_gettext.rb b/config/initializers_before_autoloader/001_fast_gettext.rb
index 76a1dafd2d8..4436eee2f90 100644
--- a/config/initializers_before_autoloader/001_fast_gettext.rb
+++ b/config/initializers_before_autoloader/001_fast_gettext.rb
@@ -1,31 +1,3 @@
# frozen_string_literal: true
-translation_repositories = [
- FastGettext::TranslationRepository.build(
- 'gitlab',
- path: File.join(Rails.root, 'locale'),
- type: :po,
- ignore_fuzzy: true
- )
-]
-
-Gitlab.jh do
- translation_repositories.unshift(
- FastGettext::TranslationRepository.build(
- 'gitlab',
- path: File.join(Rails.root, 'jh', 'locale'),
- type: :po,
- ignore_fuzzy: true
- )
- )
-end
-
-FastGettext.add_text_domain(
- 'gitlab',
- type: :chain,
- chain: translation_repositories,
- ignore_fuzzy: true
-)
-
-FastGettext.default_text_domain = 'gitlab'
-FastGettext.default_locale = :en
+Gitlab::I18n.setup(domain: 'gitlab', default_locale: :en)
diff --git a/config/object_store_settings.rb b/config/object_store_settings.rb
index 3fc24dab3d7..58d7ea22231 100644
--- a/config/object_store_settings.rb
+++ b/config/object_store_settings.rb
@@ -178,8 +178,12 @@ class ObjectStoreSettings
# 1. The common settings are defined
# 2. The legacy settings are not defined
def use_consolidated_settings?
- return false unless settings.dig('object_store', 'enabled')
- return false unless settings.dig('object_store', 'connection').present?
+ # to_h is needed because we define `default` as a Gitaly storage name
+ # in stub_storage_settings. This causes Settingslogic to redefine Hash#default,
+ # which causes Hash#dig to fail when the key doesn't exist: https://gitlab.com/gitlab-org/gitlab/-/issues/286873
+ settings_h = settings.to_h
+ return false unless settings_h.dig('object_store', 'enabled')
+ return false unless settings_h.dig('object_store', 'connection').present?
WORKHORSE_ACCELERATED_TYPES.each do |store|
# to_h is needed because we define `default` as a Gitaly storage name
diff --git a/db/migrate/20230210181214_add_allow_deploy_tokens_and_keys_with_external_authn_to_application_settings.rb b/db/migrate/20230210181214_add_allow_deploy_tokens_and_keys_with_external_authn_to_application_settings.rb
new file mode 100644
index 00000000000..d65fbca1975
--- /dev/null
+++ b/db/migrate/20230210181214_add_allow_deploy_tokens_and_keys_with_external_authn_to_application_settings.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class AddAllowDeployTokensAndKeysWithExternalAuthnToApplicationSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column(:application_settings, :allow_deploy_tokens_and_keys_with_external_authn, :boolean,
+ default: false, null: false)
+ end
+end
diff --git a/db/migrate/20230214142447_remove_text_limit_from_ci_job_artifacts_original_filename.rb b/db/migrate/20230214142447_remove_text_limit_from_ci_job_artifacts_original_filename.rb
new file mode 100644
index 00000000000..68552839a54
--- /dev/null
+++ b/db/migrate/20230214142447_remove_text_limit_from_ci_job_artifacts_original_filename.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class RemoveTextLimitFromCiJobArtifactsOriginalFilename < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ # In preparation for 20230214142813_remove_ci_job_artifacts_original_filename.rb
+ # We first remove the text limit before removing the column.
+ # This is to properly reverse the 2-step migration to add a text column with limit
+ # https://docs.gitlab.com/ee/development/database/strings_and_the_text_data_type.html#add-a-text-column-to-an-existing-table
+ remove_text_limit :ci_job_artifacts, :original_filename
+ end
+
+ def down
+ add_text_limit :ci_job_artifacts, :original_filename, 512
+ end
+end
diff --git a/db/migrate/20230214142813_remove_ci_job_artifacts_original_filename.rb b/db/migrate/20230214142813_remove_ci_job_artifacts_original_filename.rb
new file mode 100644
index 00000000000..fed09fb113d
--- /dev/null
+++ b/db/migrate/20230214142813_remove_ci_job_artifacts_original_filename.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class RemoveCiJobArtifactsOriginalFilename < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ # This column has never been used and has always been under ignore_column since it was added.
+ # We're doing the removal of the ignore_column in the same MR with this migration and this
+ # is why we are not doing this in post migrate.
+ remove_column :ci_job_artifacts, :original_filename, :text # rubocop:disable Migration/RemoveColumn
+ end
+
+ def down
+ add_column :ci_job_artifacts, :original_filename, :text
+ end
+end
diff --git a/db/schema_migrations/20230210181214 b/db/schema_migrations/20230210181214
new file mode 100644
index 00000000000..ab7b3b1ca21
--- /dev/null
+++ b/db/schema_migrations/20230210181214
@@ -0,0 +1 @@
+9e7245187ad1618304f2cdc901a6d8f63e63d007578da92f7ba049def9312923 \ No newline at end of file
diff --git a/db/schema_migrations/20230214142447 b/db/schema_migrations/20230214142447
new file mode 100644
index 00000000000..0f13b11d39e
--- /dev/null
+++ b/db/schema_migrations/20230214142447
@@ -0,0 +1 @@
+29006be848d8a5ba33c0e757ac4743cc19dc0274893e2e23c73615218975feef \ No newline at end of file
diff --git a/db/schema_migrations/20230214142813 b/db/schema_migrations/20230214142813
new file mode 100644
index 00000000000..4cfbe09f8a2
--- /dev/null
+++ b/db/schema_migrations/20230214142813
@@ -0,0 +1 @@
+c7f6778eb181c6c4e97b7d7698bb7df5a4589710426d0a6574d5230f9751ebed \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 2b7e397734d..8fadb91843f 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -11722,6 +11722,7 @@ CREATE TABLE application_settings (
deactivation_email_additional_text text,
jira_connect_public_key_storage_enabled boolean DEFAULT false NOT NULL,
git_rate_limit_users_alertlist integer[] DEFAULT '{}'::integer[] NOT NULL,
+ allow_deploy_tokens_and_keys_with_external_authn boolean DEFAULT false NOT NULL,
security_policy_global_group_approvers_enabled boolean DEFAULT true NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
@@ -13141,11 +13142,9 @@ CREATE TABLE ci_job_artifacts (
id bigint NOT NULL,
job_id bigint NOT NULL,
locked smallint DEFAULT 2,
- original_filename text,
partition_id bigint DEFAULT 100 NOT NULL,
accessibility smallint DEFAULT 0 NOT NULL,
- CONSTRAINT check_27f0f6dbab CHECK ((file_store IS NOT NULL)),
- CONSTRAINT check_85573000db CHECK ((char_length(original_filename) <= 512))
+ CONSTRAINT check_27f0f6dbab CHECK ((file_store IS NOT NULL))
);
CREATE SEQUENCE ci_job_artifacts_id_seq
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index d0e12fa7bdd..3f98f1e12fe 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -220,6 +220,8 @@ An [epic exists](https://gitlab.com/groups/gitlab-org/-/epics/4624) to fix this
Keep in mind that mentioned URLs don't work when [Admin Mode](../../user/admin_area/settings/sign_in_restrictions.md#admin-mode) is enabled.
+When using Unified URL, visiting the secondary site directly means you must route your requests to the secondary site. Exactly how this might be done depends on your networking configuration. If using DNS to route requests to the appropriate site, then you can, for example, edit your local machine's `/etc/hosts` file to route your requests to the desired secondary site. If the Geo sites are all behind a load balancer, then depending on the load balancer, you might be able to configure all requests from your IP to go to a particular secondary site.
+
## Setup instructions
For setup instructions, see [Setting up Geo](setup/index.md).
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 33c14436373..74e8035232b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -7843,6 +7843,29 @@ The edge type for [`Discussion`](#discussion).
| <a id="discussionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="discussionedgenode"></a>`node` | [`Discussion`](#discussion) | The item at the end of the edge. |
+#### `EgressNodeConnection`
+
+The connection type for [`EgressNode`](#egressnode).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="egressnodeconnectionedges"></a>`edges` | [`[EgressNodeEdge]`](#egressnodeedge) | A list of edges. |
+| <a id="egressnodeconnectionnodes"></a>`nodes` | [`[EgressNode]`](#egressnode) | A list of nodes. |
+| <a id="egressnodeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `EgressNodeEdge`
+
+The edge type for [`EgressNode`](#egressnode).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="egressnodeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="egressnodeedgenode"></a>`node` | [`EgressNode`](#egressnode) | The item at the end of the edge. |
+
#### `EmailConnection`
The connection type for [`Email`](#email).
@@ -12877,6 +12900,19 @@ Returns [`[DoraMetric!]`](#dorametric).
| <a id="dorametricdate"></a>`date` | [`String`](#string) | Date of the data point. |
| <a id="dorametricvalue"></a>`value` | [`Float`](#float) | Value of the data point. |
+### `EgressNode`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="egressnodeartifactsegress"></a>`artifactsEgress` | [`BigInt!`](#bigint) | Artifacts egress for that project in that period of time. |
+| <a id="egressnodedate"></a>`date` | [`String!`](#string) | First day of the node range. There is one node per month. |
+| <a id="egressnodepackagesegress"></a>`packagesEgress` | [`BigInt!`](#bigint) | Packages egress for that project in that period of time. |
+| <a id="egressnoderegistryegress"></a>`registryEgress` | [`BigInt!`](#bigint) | Registery egress for that project in that period of time. |
+| <a id="egressnoderepositoryegress"></a>`repositoryEgress` | [`BigInt!`](#bigint) | Repository egress for that project in that period of time. |
+| <a id="egressnodetotalegress"></a>`totalEgress` | [`BigInt!`](#bigint) | Total egress for that project in that period of time. |
+
### `Email`
#### Fields
@@ -14079,6 +14115,19 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupcontributionsfrom"></a>`from` | [`ISO8601Date!`](#iso8601date) | Start date of the reporting time range. |
| <a id="groupcontributionsto"></a>`to` | [`ISO8601Date!`](#iso8601date) | End date of the reporting time range. The end date must be within 31 days after the start date. |
+##### `Group.dataTransfer`
+
+Data transfer data point for a specific period. This is mocked data under a development feature flag.
+
+Returns [`GroupDataTransfer`](#groupdatatransfer).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for 1 year. Current month will increase dynamically as egress occurs. |
+| <a id="groupdatatransferto"></a>`to` | [`Date`](#date) | End date for the data. |
+
##### `Group.descendantGroups`
List of descendant groups of this group.
@@ -14688,6 +14737,14 @@ four standard [pagination arguments](#connection-pagination-arguments):
| ---- | ---- | ----------- |
| <a id="groupworkitemtypestaskable"></a>`taskable` | [`Boolean`](#boolean) | If `true`, only taskable work item types will be returned. Argument is experimental and can be removed in the future without notice. |
+### `GroupDataTransfer`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupdatatransferegressnodes"></a>`egressNodes` | [`EgressNodeConnection`](#egressnodeconnection) | Data nodes. (see [Connections](#connections)) |
+
### `GroupMember`
Represents a Group Membership.
@@ -17979,6 +18036,19 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectdastsitevalidationsnormalizedtargeturls"></a>`normalizedTargetUrls` | [`[String!]`](#string) | Normalized URL of the target to be scanned. |
| <a id="projectdastsitevalidationsstatus"></a>`status` | [`DastSiteValidationStatusEnum`](#dastsitevalidationstatusenum) | Status of the site validation. |
+##### `Project.dataTransfer`
+
+Data transfer data point for a specific period. This is mocked data under a development feature flag.
+
+Returns [`ProjectDataTransfer`](#projectdatatransfer).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for 1 year. Current month will increase dynamically as egress occurs. |
+| <a id="projectdatatransferto"></a>`to` | [`Date`](#date) | End date for the data. |
+
##### `Project.deployment`
Details of the deployment of the project.
@@ -18561,6 +18631,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="projectpipelineschedulesids"></a>`ids` | [`[ID!]`](#id) | Filter pipeline schedules by IDs. |
| <a id="projectpipelineschedulesstatus"></a>`status` | [`PipelineScheduleStatus`](#pipelineschedulestatus) | Filter pipeline schedules by active status. |
##### `Project.pipelines`
@@ -18986,6 +19057,15 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectcicdsettingoptinjwt"></a>`optInJwt` | [`Boolean`](#boolean) | When disabled, the JSON Web Token is always available in all jobs in the pipeline. |
| <a id="projectcicdsettingproject"></a>`project` | [`Project`](#project) | Project the CI/CD settings belong to. |
+### `ProjectDataTransfer`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectdatatransferegressnodes"></a>`egressNodes` | [`EgressNodeConnection`](#egressnodeconnection) | Data nodes. (see [Connections](#connections)) |
+| <a id="projectdatatransfertotalegress"></a>`totalEgress` | [`BigInt`](#bigint) | Total egress for that project in that period of time. |
+
### `ProjectMember`
Represents a Project Membership.
diff --git a/doc/update/index.md b/doc/update/index.md
index 86922a9a1e3..4c909395f54 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -373,6 +373,14 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
Sites that have configured `max_concurrency` will not be affected by this change.
[Read more about the Sidekiq concurrency setting](../administration/sidekiq/extra_sidekiq_processes.md#concurrency).
+- GitLab Runner 15.7.0 introduced a breaking change that impacts CI/CD jobs: [Correctly handle expansion of job file variables](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3613).
+ Previously, job-defined variables that referred to
+ [file type variables](../ci/variables/index.md#use-file-type-cicd-variables)
+ were expanded to the value of the file variable (its content). This behavior did not
+ respect the typical rules of shell variable expansion. There was also the potential
+ that secrets or sensitive information could leak if the file variable and its
+ contents printed. For example, if they were printed in an echo output. For more information,
+ see [Understanding the file type variable expansion change in GitLab 15.7](https://about.gitlab.com/blog/2023/02/13/impact-of-the-file-type-variable-change-15-7/).
- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This impacts versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md
index a3a4de844ad..7114974d8db 100644
--- a/doc/user/project/import/bitbucket.md
+++ b/doc/user/project/import/bitbucket.md
@@ -65,6 +65,8 @@ For user contributions to be mapped, each user must complete the following befor
## Import your Bitbucket repositories
+> Ability to re-import projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23905) in GitLab 15.9.
+
1. Sign in to GitLab.
1. On the top bar, select **New** (**{plus}**).
1. Select **New project/repository**.
@@ -78,7 +80,9 @@ For user contributions to be mapped, each user must complete the following befor
You can filter projects by name and select the namespace
each project is imported for.
- ![Import projects](img/bitbucket_import_select_project_v12_3.png)
+1. To import a project:
+ - For the first time: Select **Import**.
+ - Again: Select **Re-import**. Specify a new name and select **Re-import** again. Re-importing creates a new copy of the source project.
## Troubleshooting
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index db2a1d956ab..e6d2e3e00b6 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -24,6 +24,8 @@ created as private in GitLab as well.
## Import your Bitbucket repositories
+> Ability to re-import projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23905) in GitLab 15.9.
+
Prerequisites:
- An administrator must enable **Bitbucket Server** in **Admin > Settings > General > Visibility and access controls > Import sources**.
@@ -40,6 +42,9 @@ To import your Bitbucket repositories:
1. Log in to Bitbucket and grant GitLab access to your Bitbucket account.
1. Select the projects to import, or import all projects. You can filter projects by name and select
the namespace for which to import each project.
+1. To import a project:
+ - For the first time: Select **Import**.
+ - Again: Select **Re-import**. Specify a new name and select **Re-import** again. Re-importing creates a new copy of the source project.
### Items that are not imported
diff --git a/doc/user/project/import/fogbugz.md b/doc/user/project/import/fogbugz.md
index 08ee4c70dda..d9e03662434 100644
--- a/doc/user/project/import/fogbugz.md
+++ b/doc/user/project/import/fogbugz.md
@@ -7,6 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Import your project from FogBugz to GitLab **(FREE)**
+> Ability to re-import projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23905) in GitLab 15.9.
+
Using the importer, you can import your FogBugz project to GitLab.com
or to your self-managed GitLab instance.
@@ -33,4 +35,6 @@ To import your project from FogBugz:
![Import Project](img/fogbugz_import_select_project.png)
1. After the import finishes, select the link to go to the project
dashboard. Follow the directions to push your existing repository.
- ![Finished](img/fogbugz_import_finished.png)
+1. To import a project:
+ - For the first time: Select **Import**.
+ - Again: Select **Re-import**. Specify a new name and select **Re-import** again. Re-importing creates a new copy of the source project.
diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md
index fb64c902b38..404bb4c8600 100644
--- a/doc/user/project/import/gitea.md
+++ b/doc/user/project/import/gitea.md
@@ -70,8 +70,8 @@ From there, you can view the import statuses of your Gitea repositories:
- Those that are being imported show a _started_ status.
- Those already successfully imported are green with a _done_ status.
-- Those that aren't yet imported have an **Import** button on the
- right side of the table.
+- Those that aren't yet imported have **Import** on the right side of the table.
+- Those that are already imported have **Re-import** on the right side of the table.
You also can:
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 6234c9ef8de..177b6db99cf 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -146,7 +146,8 @@ You can choose to import these items, but this could significantly increase impo
### Select which repositories to import
-> Ability to cancel pending or active imports [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247325) in GitLab 15.7.
+> - Ability to cancel pending or active imports [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247325) in GitLab 15.7.
+> - Ability to re-import projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23905) in GitLab 15.9.
After you have authorized access to your GitHub repositories, you are redirected to the GitHub importer page and
your GitHub repositories are listed.
@@ -168,6 +169,8 @@ If the import has already started, the imported files are kept.
To open an repository in GitLab URL after it has been imported, select its GitLab path.
+Completed imports can be re-imported by selecting **Re-import** and specifying new name. This creates a new copy of the source project.
+
![GitHub importer page](img/import_projects_from_github_importer_v12_3.png)
## Mirror a repository and share pipeline status **(PREMIUM)**
diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md
index a7e1af9412d..514a6a0cb5a 100644
--- a/doc/user/project/import/manifest.md
+++ b/doc/user/project/import/manifest.md
@@ -7,7 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Import multiple repositories by uploading a manifest file **(FREE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/28811) in GitLab 11.2.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/28811) in GitLab 11.2.
+> - Ability to re-import projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23905) in GitLab 15.9.
GitLab allows you to import all the required Git repositories
based on a manifest file like the one used by the
@@ -59,6 +60,6 @@ To start the import:
1. Select a group you want to import to (you need to create a group first if you don't have one).
1. Select **List available repositories**. At this point, you are redirected
to the import status page with projects list based on the manifest file.
-1. Check the list and select **Import all repositories** to start the import.
-
- ![Manifest status](img/manifest_status_v13_3.png)
+1. To import:
+ - All projects for the first time: Select **Import all repositories**.
+ - Individual projects again: Select **Re-import**. Specify a new name and select **Re-import** again. Re-importing creates a new copy of the source project.
diff --git a/lib/api/draft_notes.rb b/lib/api/draft_notes.rb
index aef42fb125e..842180652c4 100644
--- a/lib/api/draft_notes.rb
+++ b/lib/api/draft_notes.rb
@@ -24,6 +24,12 @@ module API
def delete_draft_note(draft_note)
::DraftNotes::DestroyService.new(user_project, current_user).execute(draft_note)
end
+
+ def publish_draft_note(params:)
+ ::DraftNotes::PublishService
+ .new(merge_request(params: params), current_user)
+ .execute(get_draft_note(params: params))
+ end
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -90,6 +96,31 @@ module API
not_found!("Draft Note")
end
end
+
+ desc "Publish a pending draft note" do
+ success code: 204
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
+ params do
+ requires :id, type: String, desc: "The ID of a project"
+ requires :merge_request_iid, type: Integer, desc: "The ID of a merge request"
+ requires :draft_note_id, type: Integer, desc: "The ID of a draft note"
+ end
+ put(
+ ":id/merge_requests/:merge_request_iid/draft_notes/:draft_note_id/publish",
+ feature_category: :code_review_workflow) do
+ result = publish_draft_note(params: params)
+
+ if result[:status] == :success
+ status 204
+ body false
+ else
+ status 500
+ end
+ end
end
end
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 4f722c2cfaf..88e99b29587 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -319,7 +319,7 @@ module API
update_params = convert_parameters_from_legacy_format(update_params)
spam_params = ::Spam::SpamParams.new_from_request(request: request)
- issue = ::Issues::UpdateService.new(project: user_project,
+ issue = ::Issues::UpdateService.new(container: user_project,
current_user: current_user,
params: update_params,
spam_params: spam_params).execute(issue)
@@ -350,7 +350,7 @@ module API
authorize! :update_issue, issue
- if ::Issues::ReorderService.new(project: user_project, current_user: current_user, params: params).execute(issue)
+ if ::Issues::ReorderService.new(container: user_project, current_user: current_user, params: params).execute(issue)
present issue, with: Entities::Issue, current_user: current_user, project: user_project
else
render_api_error!({ error: 'Unprocessable Entity' }, 422)
@@ -438,9 +438,10 @@ module API
get ':id/issues/:issue_iid/related_merge_requests' do
issue = find_project_issue(params[:issue_iid])
- merge_requests = ::Issues::ReferencedMergeRequestsService.new(project: user_project, current_user: current_user)
- .execute(issue)
- .first
+ merge_requests = ::Issues::ReferencedMergeRequestsService
+ .new(container: user_project, current_user: current_user)
+ .execute(issue)
+ .first
present paginate(::Kaminari.paginate_array(merge_requests)),
with: Entities::MergeRequest,
diff --git a/lib/api/time_tracking_endpoints.rb b/lib/api/time_tracking_endpoints.rb
index dd8ad2cc144..3534edc3831 100644
--- a/lib/api/time_tracking_endpoints.rb
+++ b/lib/api/time_tracking_endpoints.rb
@@ -35,7 +35,9 @@ module API
custom_params = declared_params(include_missing: false)
custom_params.merge!(attrs)
- issuable = update_service.new(project: user_project, current_user: current_user, params: custom_params).execute(load_issuable)
+ issuable = update_service.new(**update_service.constructor_container_arg(user_project),
+ current_user: current_user, params: custom_params).execute(load_issuable)
+
if issuable.valid?
present issuable, with: Entities::IssuableTimeStats
else
diff --git a/lib/gitlab/api_authentication/token_resolver.rb b/lib/gitlab/api_authentication/token_resolver.rb
index afada055928..3f8025c408a 100644
--- a/lib/gitlab/api_authentication/token_resolver.rb
+++ b/lib/gitlab/api_authentication/token_resolver.rb
@@ -165,7 +165,9 @@ module Gitlab
end
def with_deploy_token(raw, &block)
- raise ::Gitlab::Auth::UnauthorizedError if Gitlab::ExternalAuthorization.enabled?
+ unless Gitlab::ExternalAuthorization.allow_deploy_tokens_and_deploy_keys?
+ raise ::Gitlab::Auth::UnauthorizedError
+ end
token = ::DeployToken.active.find_by_token(raw.password)
return unless token
diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb
index edcde55974c..c69462b12de 100644
--- a/lib/gitlab/auth/auth_finders.rb
+++ b/lib/gitlab/auth/auth_finders.rb
@@ -148,7 +148,7 @@ module Gitlab
# deploy tokens are accepted with deploy token headers and basic auth headers
def deploy_token_from_request
return unless route_authentication_setting[:deploy_token_allowed]
- return if Gitlab::ExternalAuthorization.enabled?
+ return unless Gitlab::ExternalAuthorization.allow_deploy_tokens_and_deploy_keys?
token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token
diff --git a/lib/gitlab/ci/config/external/mapper/verifier.rb b/lib/gitlab/ci/config/external/mapper/verifier.rb
index 83ef58bb46f..2982b0efb6c 100644
--- a/lib/gitlab/ci/config/external/mapper/verifier.rb
+++ b/lib/gitlab/ci/config/external/mapper/verifier.rb
@@ -28,7 +28,7 @@ module Gitlab
file.validate_content! if file.valid?
file.load_and_validate_expanded_hash! if file.valid?
- if ::Feature.enabled?(:ci_includes_count_duplicates, context.project)
+ if context.expandset.is_a?(Array) # To be removed when FF 'ci_includes_count_duplicates' is removed
context.expandset << file
else
context.expandset.add(file)
diff --git a/lib/gitlab/external_authorization/config.rb b/lib/gitlab/external_authorization/config.rb
index 8654a8c1e2e..e77318144ef 100644
--- a/lib/gitlab/external_authorization/config.rb
+++ b/lib/gitlab/external_authorization/config.rb
@@ -37,6 +37,12 @@ module Gitlab
client_cert.present? && client_key.present?
end
+ def allow_deploy_tokens_and_deploy_keys?
+ return true unless enabled?
+
+ service_url.blank? && application_settings.allow_deploy_tokens_and_keys_with_external_authn?
+ end
+
private
def application_settings
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 35b330fa089..9d19695363a 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -367,7 +367,7 @@ module Gitlab
end
def deploy_key?
- actor.is_a?(DeployKey) && !Gitlab::ExternalAuthorization.enabled?
+ actor.is_a?(DeployKey) && Gitlab::ExternalAuthorization.allow_deploy_tokens_and_deploy_keys?
end
def deploy_token
@@ -375,7 +375,7 @@ module Gitlab
end
def deploy_token?
- actor.is_a?(DeployToken) && !Gitlab::ExternalAuthorization.enabled?
+ actor.is_a?(DeployToken) && Gitlab::ExternalAuthorization.allow_deploy_tokens_and_deploy_keys?
end
def ci?
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index d8ef8b11bec..8fe5868ca57 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -116,5 +116,43 @@ module Gitlab
def with_default_locale(&block)
with_locale(::I18n.default_locale, &block)
end
+
+ def setup(domain:, default_locale:)
+ setup_repositories(domain)
+ setup_default_locale(default_locale)
+ end
+
+ private
+
+ def setup_repositories(domain)
+ translation_repositories = [
+ (po_repository(domain, 'jh/locale') if Gitlab.jh?),
+ po_repository(domain, 'locale')
+ ].compact
+
+ FastGettext.add_text_domain(
+ domain,
+ type: :chain,
+ chain: translation_repositories,
+ ignore_fuzzy: true
+ )
+
+ FastGettext.default_text_domain = domain
+ end
+
+ def po_repository(domain, path)
+ FastGettext::TranslationRepository.build(
+ domain,
+ path: Rails.root.join(path),
+ type: :po,
+ ignore_fuzzy: true
+ )
+ end
+
+ def setup_default_locale(locale)
+ FastGettext.default_locale = locale
+ FastGettext.default_available_locales = available_locales
+ ::I18n.available_locales = available_locales
+ end
end
end
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
index a12457d89c9..96e3112f32f 100644
--- a/lib/gitlab/quick_actions/issuable_actions.rb
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -248,7 +248,7 @@ module Gitlab
if severity
if quick_action_target.persisted?
- ::Issues::UpdateService.new(project: quick_action_target.project, current_user: current_user, params: { severity: severity }).execute(quick_action_target)
+ ::Issues::UpdateService.new(container: quick_action_target.project, current_user: current_user, params: { severity: severity }).execute(quick_action_target)
else
quick_action_target.build_issuable_severity(severity: severity)
end
diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb
index f782f2802b6..ae8bc102f57 100644
--- a/lib/gitlab/quick_actions/issue_actions.rb
+++ b/lib/gitlab/quick_actions/issue_actions.rb
@@ -320,7 +320,7 @@ module Gitlab
private
def zoom_link_service
- ::Issues::ZoomLinkService.new(project: quick_action_target.project, current_user: current_user, params: { issue: quick_action_target })
+ ::Issues::ZoomLinkService.new(container: quick_action_target.project, current_user: current_user, params: { issue: quick_action_target })
end
def zoom_link_params
diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb
index 2a5c606be43..a102267d52b 100644
--- a/lib/gitlab/redis/multi_store.rb
+++ b/lib/gitlab/redis/multi_store.rb
@@ -204,6 +204,14 @@ module Gitlab
extra.merge(command_name: command_name, instance_name: instance_name))
end
+ def default_store
+ use_primary_store_as_default? ? primary_store : secondary_store
+ end
+
+ def fallback_store
+ use_primary_store_as_default? ? secondary_store : primary_store
+ end
+
def ping(message = nil)
if use_primary_and_secondary_stores?
# Both stores have to response success for the ping to be considered success.
@@ -226,10 +234,6 @@ module Gitlab
false
end
- def default_store
- use_primary_store_as_default? ? primary_store : secondary_store
- end
-
def log_method_missing(command_name, *_args)
return if SKIP_LOG_METHOD_MISSING_FOR_COMMANDS.include?(command_name)
@@ -257,7 +261,7 @@ module Gitlab
def read_one_with_fallback(command_name, *args, **kwargs, &block)
begin
- value = send_command(primary_store, command_name, *args, **kwargs, &block)
+ value = send_command(default_store, command_name, *args, **kwargs, &block)
rescue StandardError => e
log_error(e, command_name,
multi_store_error_message: FAILED_TO_READ_ERROR_MESSAGE)
@@ -276,7 +280,7 @@ module Gitlab
end
def fallback_read(command_name, *args, **kwargs, &block)
- value = send_command(secondary_store, command_name, *args, **kwargs, &block)
+ value = send_command(fallback_store, command_name, *args, **kwargs, &block)
if value
log_error(ReadFromPrimaryError.new, command_name)
diff --git a/lib/gitlab/slash_commands/issue_close.rb b/lib/gitlab/slash_commands/issue_close.rb
index 5d33f2fe62d..885c08ce9d5 100644
--- a/lib/gitlab/slash_commands/issue_close.rb
+++ b/lib/gitlab/slash_commands/issue_close.rb
@@ -29,7 +29,7 @@ module Gitlab
private
def close_issue(issue:)
- ::Issues::CloseService.new(project: project, current_user: current_user).execute(issue)
+ ::Issues::CloseService.new(container: project, current_user: current_user).execute(issue)
end
def presenter(issue)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a9e933a0655..26fb9554d9c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -17010,6 +17010,9 @@ msgstr ""
msgid "ExternalAuthorization|Access to projects is validated on an external service using their classification label."
msgstr ""
+msgid "ExternalAuthorization|Allow deploy tokens and deploy keys to be used with external authorization"
+msgstr ""
+
msgid "ExternalAuthorization|Certificate used to authenticate with the external authorization service. If blank, the server certificate is validated when accessing over HTTPS."
msgstr ""
@@ -17028,6 +17031,9 @@ msgstr ""
msgid "ExternalAuthorization|Default classification label"
msgstr ""
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr ""
+
msgid "ExternalAuthorization|Enable classification control using an external service"
msgstr ""
@@ -21545,6 +21551,9 @@ msgstr ""
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
msgid "ImportProjects|Requesting namespaces failed"
msgstr ""
diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb
index 4ea0575b6e0..bb1095371a8 100644
--- a/qa/qa/page/project/import/github.rb
+++ b/qa/qa/page/project/import/github.rb
@@ -15,7 +15,7 @@ module QA
element :project_path_field
element :import_button
element :project_path_content
- element :go_to_project_button
+ element :go_to_project_link
element :import_status_indicator
end
@@ -60,9 +60,9 @@ module QA
#
# @param [String] gh_project_name
# @return [Boolean]
- def has_go_to_project_button?(gh_project_name)
+ def has_go_to_project_link?(gh_project_name)
within_element(:project_import_row, source_project: gh_project_name) do
- has_element?(:go_to_project_button)
+ has_element?(:go_to_project_link)
end
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
index c07bc8ac65b..461928cbf1f 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
@@ -52,9 +52,9 @@ module QA
aggregate_failures do
expect(import_page).to have_imported_project(github_repo, wait: 240)
- # validate button is present instead of navigating to avoid dealing with multiple tabs
+ # validate link is present instead of navigating to avoid dealing with multiple tabs
# which makes the test more complicated
- expect(import_page).to have_go_to_project_button(github_repo)
+ expect(import_page).to have_go_to_project_link(github_repo)
end
end
diff --git a/scripts/ingest-reports-to-siem-devo b/scripts/ingest-reports-to-siem-devo
new file mode 100755
index 00000000000..0645d778217
--- /dev/null
+++ b/scripts/ingest-reports-to-siem-devo
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+
+const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3')
+const { fromIni } = require('@aws-sdk/credential-provider-ini')
+const path = require('path')
+const fs = require('fs')
+const crypto = require('crypto')
+
+function getMD5HashFromFile(data) {
+ const hash = crypto.createHash('md5').update(data).digest('base64')
+ return hash
+}
+
+(async function () {
+ const s3Client = new S3Client({
+ region: 'us-east-2',
+ credentials: fromIni({ profile: 'gl-logs-for-panther' }),
+ })
+ try {
+ const file = 'gl-dependency-scanning-report.json'
+ const data = fs.readFileSync(file)
+
+ const [filename, fileext] = path.basename(file).split('.')
+ const uniqueId = process.env['CI_PIPELINE_ID'] && process.env['CI_JOB_ID'] ?
+ process.env['CI_PIPELINE_ID'] + '-' + process.env['CI_JOB_ID'] :
+ Date.now()
+ const key = path.join('package_hunter_logs', filename + '-' + uniqueId + '.' + fileext)
+
+ const responseData = await s3Client.send(
+ new PutObjectCommand({
+ Bucket: 'package-hunter-logs',
+ Key: key,
+ Body: data,
+ ContentMD5: getMD5HashFromFile(data),
+ }),
+ )
+ console.log('Successfully uploaded %s to %s', file, key)
+ } catch (err) {
+ if (err.name === 'CredentialsProviderError' || err.name === 'AuthorizationHeaderMalformed')
+ console.log('Could not upload the report. Are AWS credentials configured in ~/.aws/credentials?')
+ else
+ console.log('Unexpected error during upload: ', err.message)
+ process.exit(1)
+ }
+})()
diff --git a/spec/config/settings_spec.rb b/spec/config/settings_spec.rb
index 1aa1d885be3..0928f2b72ff 100644
--- a/spec/config/settings_spec.rb
+++ b/spec/config/settings_spec.rb
@@ -190,4 +190,12 @@ RSpec.describe Settings, feature_category: :authentication_and_authorization do
expect(described_class.microsoft_graph_mailer.graph_endpoint).to eq('https://graph.microsoft.com')
end
end
+
+ describe '.repositories' do
+ it 'sets up storage settings' do
+ described_class.repositories.storages.each do |_, storage|
+ expect(storage).to be_a Gitlab::GitalyClient::StorageSettings
+ end
+ end
+ end
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index a8a747e188e..bf2af918f39 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe "Issues > User edits issue", :js, feature_category: :team_plannin
visit edit_project_issue_path(project, issue)
end
- it "previews content" do
+ it "previews content", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391757' do
form = first(".gfm-form")
page.within(form) do
diff --git a/spec/finders/ci/pipeline_schedules_finder_spec.rb b/spec/finders/ci/pipeline_schedules_finder_spec.rb
index 535c684289e..4699592b6d4 100644
--- a/spec/finders/ci/pipeline_schedules_finder_spec.rb
+++ b/spec/finders/ci/pipeline_schedules_finder_spec.rb
@@ -15,8 +15,39 @@ RSpec.describe Ci::PipelineSchedulesFinder do
let(:params) { { scope: nil } }
it 'selects all pipeline schedules' do
- expect(subject.count).to be(2)
- expect(subject).to include(active_schedule, inactive_schedule)
+ expect(subject).to contain_exactly(active_schedule, inactive_schedule)
+ end
+ end
+
+ context 'when the id is nil' do
+ let(:params) { { ids: nil } }
+
+ it 'selects all pipeline schedules' do
+ expect(subject).to contain_exactly(active_schedule, inactive_schedule)
+ end
+ end
+
+ context 'when the id is a single pipeline schedule' do
+ let(:params) { { ids: active_schedule.id } }
+
+ it 'selects one pipeline schedule' do
+ expect(subject).to contain_exactly(active_schedule)
+ end
+ end
+
+ context 'when multiple ids are provided' do
+ let(:params) { { ids: [active_schedule.id, inactive_schedule.id] } }
+
+ it 'selects multiple pipeline schedules' do
+ expect(subject).to contain_exactly(active_schedule, inactive_schedule)
+ end
+ end
+
+ context 'when multiple ids are provided and a scope is set' do
+ let(:params) { { scope: 'active', ids: [active_schedule.id, inactive_schedule.id] } }
+
+ it 'selects one pipeline schedule' do
+ expect(subject).to contain_exactly(active_schedule)
end
end
@@ -24,9 +55,7 @@ RSpec.describe Ci::PipelineSchedulesFinder do
let(:params) { { scope: 'active' } }
it 'selects only active pipelines' do
- expect(subject.count).to be(1)
- expect(subject).to include(active_schedule)
- expect(subject).not_to include(inactive_schedule)
+ expect(subject).to contain_exactly(active_schedule)
end
end
@@ -34,9 +63,7 @@ RSpec.describe Ci::PipelineSchedulesFinder do
let(:params) { { scope: 'inactive' } }
it 'selects only inactive pipelines' do
- expect(subject.count).to be(1)
- expect(subject).not_to include(active_schedule)
- expect(subject).to include(inactive_schedule)
+ expect(subject).to contain_exactly(inactive_schedule)
end
end
end
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
index 00b69948bfb..c7bda5a60ec 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
@@ -40,6 +40,7 @@ describe('import table', () => {
generateFakeEntry({ id: 2, status: STATUSES.FINISHED }),
generateFakeEntry({ id: 3, status: STATUSES.NONE }),
];
+
const FAKE_PAGE_INFO = { page: 1, perPage: 20, total: 40, totalPages: 2 };
const FAKE_VERSION_VALIDATION = {
features: {
diff --git a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
index d686036781f..e613b9756af 100644
--- a/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
+++ b/spec/frontend/import_entities/import_projects/components/provider_repo_table_row_spec.js
@@ -1,4 +1,4 @@
-import { GlBadge, GlButton, GlDropdown } from '@gitlab/ui';
+import { GlBadge, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
@@ -31,12 +31,16 @@ describe('ProviderRepoTableRow', () => {
return store;
}
- const findImportButton = () => {
- const buttons = wrapper.findAllComponents(GlButton).filter((node) => node.text() === 'Import');
+ const findButton = (text) => {
+ const buttons = wrapper.findAllComponents(GlButton).filter((node) => node.text() === text);
return buttons.length ? buttons.at(0) : buttons;
};
+ const findImportButton = () => findButton('Import');
+ const findReimportButton = () => findButton('Re-import');
+ const findGroupDropdown = () => wrapper.findComponent(ImportGroupDropdown);
+
const findCancelButton = () => {
const buttons = wrapper
.findAllComponents(GlButton)
@@ -117,6 +121,10 @@ describe('ProviderRepoTableRow', () => {
optionalStages: OPTIONAL_STAGES,
});
});
+
+ it('does not render re-import button', () => {
+ expect(findReimportButton().exists()).toBe(false);
+ });
});
describe('when rendering importing project', () => {
@@ -200,19 +208,68 @@ describe('ProviderRepoTableRow', () => {
);
});
- it('does not renders a namespace select', () => {
- expect(wrapper.findComponent(GlDropdown).exists()).toBe(false);
+ it('does not render a namespace select', () => {
+ expect(findGroupDropdown().exists()).toBe(false);
});
it('does not render import button', () => {
expect(findImportButton().exists()).toBe(false);
});
+ it('renders re-import button', () => {
+ expect(findReimportButton().exists()).toBe(true);
+ });
+
+ it('renders namespace select after clicking re-import', async () => {
+ findReimportButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findGroupDropdown().exists()).toBe(true);
+ });
+
+ it('imports repo when clicking re-import button', async () => {
+ findReimportButton().vm.$emit('click');
+
+ await nextTick();
+
+ findReimportButton().vm.$emit('click');
+
+ expect(fetchImport).toHaveBeenCalledWith(expect.anything(), {
+ repoId: repo.importSource.id,
+ optionalStages: {},
+ });
+ });
+
it('passes stats to import status component', () => {
expect(wrapper.findComponent(ImportStatus).props().stats).toBe(FAKE_STATS);
});
});
+ describe('when rendering failed project', () => {
+ const repo = {
+ importSource: {
+ id: 'remote-1',
+ fullName: 'fullName',
+ providerLink: 'providerLink',
+ },
+ importedProject: {
+ id: 1,
+ fullPath: 'fullPath',
+ importSource: 'importSource',
+ importStatus: STATUSES.FAILED,
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({ repo });
+ });
+
+ it('render import button', () => {
+ expect(findImportButton().exists()).toBe(true);
+ });
+ });
+
describe('when rendering incompatible project', () => {
const repo = {
importSource: {
diff --git a/spec/frontend/import_entities/import_projects/store/mutations_spec.js b/spec/frontend/import_entities/import_projects/store/mutations_spec.js
index 7884e9b4307..514a168553a 100644
--- a/spec/frontend/import_entities/import_projects/store/mutations_spec.js
+++ b/spec/frontend/import_entities/import_projects/store/mutations_spec.js
@@ -8,14 +8,14 @@ describe('import_projects store mutations', () => {
const SOURCE_PROJECT = {
id: 1,
- full_name: 'full/name',
- sanitized_name: 'name',
- provider_link: 'https://demo.link/full/name',
+ fullName: 'full/name',
+ sanitizedName: 'name',
+ providerLink: 'https://demo.link/full/name',
};
const IMPORTED_PROJECT = {
name: 'demo',
importSource: 'something',
- providerLink: 'custom-link',
+ providerLink: 'https://demo.link/full/name',
importStatus: 'status',
fullName: 'fullName',
};
@@ -64,21 +64,15 @@ describe('import_projects store mutations', () => {
describe('for imported projects', () => {
const response = {
importedProjects: [IMPORTED_PROJECT],
- providerRepos: [],
+ providerRepos: [SOURCE_PROJECT],
};
- it('recreates importSource from response', () => {
+ it('adds importedProject to relevant provider repo', () => {
state = getInitialState();
mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
- expect(state.repositories[0].importSource).toStrictEqual(
- expect.objectContaining({
- fullName: IMPORTED_PROJECT.importSource,
- sanitizedName: IMPORTED_PROJECT.name,
- providerLink: IMPORTED_PROJECT.providerLink,
- }),
- );
+ expect(state.repositories[0].importedProject).toStrictEqual(IMPORTED_PROJECT);
});
it('passes project to importProject', () => {
@@ -216,13 +210,13 @@ describe('import_projects store mutations', () => {
describe(`${types.RECEIVE_IMPORT_ERROR}`, () => {
beforeEach(() => {
const REPO_ID = 1;
- state = { repositories: [{ importSource: { id: REPO_ID } }] };
+ state = { repositories: [{ importSource: { id: REPO_ID }, importedProject: {} }] };
mutations[types.RECEIVE_IMPORT_ERROR](state, REPO_ID);
});
- it(`removes importedProject entry`, () => {
- expect(state.repositories[0].importedProject).toBeNull();
+ it('sets status to failed', () => {
+ expect(state.repositories[0].importedProject.importStatus).toBe(STATUSES.FAILED);
});
});
diff --git a/spec/frontend/import_entities/import_projects/utils_spec.js b/spec/frontend/import_entities/import_projects/utils_spec.js
index d705f0acbfe..42cdf0f5a19 100644
--- a/spec/frontend/import_entities/import_projects/utils_spec.js
+++ b/spec/frontend/import_entities/import_projects/utils_spec.js
@@ -19,7 +19,7 @@ describe('import_projects utils', () => {
it.each`
status | result
${STATUSES.FINISHED} | ${false}
- ${STATUSES.FAILED} | ${false}
+ ${STATUSES.FAILED} | ${true}
${STATUSES.SCHEDULED} | ${false}
${STATUSES.STARTED} | ${false}
${STATUSES.NONE} | ${true}
diff --git a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
index db1986d1037..77d5a0579a4 100644
--- a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -120,7 +120,9 @@ describe('IssuesDashboardApp component', () => {
return waitForPromises();
});
- it('renders IssuableList component', () => {
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/391722
+ // eslint-disable-next-line jest/no-disabled-tests
+ it.skip('renders IssuableList component', () => {
expect(findIssuableList().props()).toMatchObject({
currentTab: IssuableStates.Opened,
hasNextPage: true,
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
index f13fc8a5007..2ca9dc61745 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js
@@ -104,7 +104,6 @@ describe('MRWidgetConflicts', () => {
it('should tell you about conflicts', () => {
const text = removeBreakLine(wrapper.text()).trim();
- expect(text).toContain(mergeConflictsText);
expect(text).toContain(userCannotMergeText);
});
diff --git a/spec/graphql/resolvers/data_transfer_resolver_spec.rb b/spec/graphql/resolvers/data_transfer_resolver_spec.rb
new file mode 100644
index 00000000000..f5a088dc1c3
--- /dev/null
+++ b/spec/graphql/resolvers/data_transfer_resolver_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DataTransferResolver, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ describe '.source' do
+ context 'with base DataTransferResolver' do
+ it 'raises NotImplementedError' do
+ expect { described_class.source }.to raise_error ::NotImplementedError
+ end
+ end
+
+ context 'with projects DataTransferResolver' do
+ let(:source) { described_class.project.source }
+
+ it 'outputs "Project"' do
+ expect(source).to eq 'Project'
+ end
+ end
+
+ context 'with groups DataTransferResolver' do
+ let(:source) { described_class.group.source }
+
+ it 'outputs "Group"' do
+ expect(source).to eq 'Group'
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
index 9f86b95651a..c0c8e7aba63 100644
--- a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
+++ b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::APIAuthentication::TokenResolver do
+RSpec.describe Gitlab::APIAuthentication::TokenResolver, feature_category: :authentication_and_authorization do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
@@ -115,9 +115,9 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
it_behaves_like 'an unauthorized request'
end
- context 'when the external_authorization_service is enabled' do
+ context 'when the the deploy token is restricted with external_authorization' do
before do
- stub_application_setting(external_authorization_service_enabled: true)
+ allow(Gitlab::ExternalAuthorization).to receive(:allow_deploy_tokens_and_deploy_keys?).and_return(false)
end
context 'with a valid deploy token' do
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index d4d82f659f1..6aedd0a0a23 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth::AuthFinders do
+RSpec.describe Gitlab::Auth::AuthFinders, feature_category: :authentication_and_authorization do
include described_class
include HttpBasicAuthHelpers
@@ -390,9 +390,9 @@ RSpec.describe Gitlab::Auth::AuthFinders do
end
end
- context 'when the external_authorization_service is enabled' do
+ context 'when the the deploy token is restricted with external_authorization' do
before do
- stub_application_setting(external_authorization_service_enabled: true)
+ allow(Gitlab::ExternalAuthorization).to receive(:allow_deploy_tokens_and_deploy_keys?).and_return(false)
set_header(described_class::DEPLOY_TOKEN_HEADER, deploy_token.token)
end
diff --git a/spec/lib/gitlab/external_authorization/config_spec.rb b/spec/lib/gitlab/external_authorization/config_spec.rb
new file mode 100644
index 00000000000..4231b0d3747
--- /dev/null
+++ b/spec/lib/gitlab/external_authorization/config_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ExternalAuthorization::Config, feature_category: :authentication_and_authorization do
+ it 'allows deploy tokens and keys when external authorization is disabled' do
+ stub_application_setting(external_authorization_service_enabled: false)
+ expect(described_class.allow_deploy_tokens_and_deploy_keys?).to be_eql(true)
+ end
+
+ context 'when external authorization is enabled' do
+ it 'disable deploy tokens and keys' do
+ stub_application_setting(external_authorization_service_enabled: true)
+ expect(described_class.allow_deploy_tokens_and_deploy_keys?).to be_eql(false)
+ end
+
+ it "enable deploy tokens and keys when it is explicitly enabled and service url is blank" do
+ stub_application_setting(external_authorization_service_enabled: true)
+ stub_application_setting(allow_deploy_tokens_and_keys_with_external_authn: true)
+ expect(described_class.allow_deploy_tokens_and_deploy_keys?).to be_eql(true)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 5f5ac7fff2a..ea2c239df07 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -113,9 +113,9 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :authen
end
end
- context 'when the external_authorization_service is enabled' do
+ context 'when the the deploy key is restricted with external_authorization' do
before do
- stub_application_setting(external_authorization_service_enabled: true)
+ allow(Gitlab::ExternalAuthorization).to receive(:allow_deploy_tokens_and_deploy_keys?).and_return(false)
end
it 'blocks push and pull with "not found"' do
@@ -191,9 +191,9 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures, feature_category: :authen
end
end
- context 'when the external_authorization_service is enabled' do
+ context 'when the the deploy token is restricted with external_authorization' do
before do
- stub_application_setting(external_authorization_service_enabled: true)
+ allow(Gitlab::ExternalAuthorization).to receive(:allow_deploy_tokens_and_deploy_keys?).and_return(false)
end
it 'blocks pull access' do
diff --git a/spec/lib/gitlab/github_import/logger_spec.rb b/spec/lib/gitlab/github_import/logger_spec.rb
index 6fd0f5db93e..d9ffc03831e 100644
--- a/spec/lib/gitlab/github_import/logger_spec.rb
+++ b/spec/lib/gitlab/github_import/logger_spec.rb
@@ -8,18 +8,14 @@ RSpec.describe Gitlab::GithubImport::Logger do
let(:now) { Time.zone.now }
describe '#format_message' do
- before do
- allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
- end
-
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
- expect(Gitlab::Json.parse(output)).to eq({
+ expect(Gitlab::Json.parse(output)).to include({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'message' => 'Hello world',
- 'correlation_id' => 'new-correlation-id',
+ 'correlation_id' => an_instance_of(String),
'feature_category' => 'importers',
'import_type' => 'github'
})
@@ -28,11 +24,11 @@ RSpec.describe Gitlab::GithubImport::Logger do
it 'formats hashes' do
output = subject.format_message('INFO', now, 'test', { hello: 1 })
- expect(Gitlab::Json.parse(output)).to eq({
+ expect(Gitlab::Json.parse(output)).to include({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'hello' => 1,
- 'correlation_id' => 'new-correlation-id',
+ 'correlation_id' => an_instance_of(String),
'feature_category' => 'importers',
'import_type' => 'github'
})
diff --git a/spec/lib/gitlab/import/logger_spec.rb b/spec/lib/gitlab/import/logger_spec.rb
index 60978aaa25c..cf5e3a00c31 100644
--- a/spec/lib/gitlab/import/logger_spec.rb
+++ b/spec/lib/gitlab/import/logger_spec.rb
@@ -8,18 +8,14 @@ RSpec.describe Gitlab::Import::Logger do
let(:now) { Time.zone.now }
describe '#format_message' do
- before do
- allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
- end
-
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
- expect(Gitlab::Json.parse(output)).to eq({
+ expect(Gitlab::Json.parse(output)).to include({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'message' => 'Hello world',
- 'correlation_id' => 'new-correlation-id',
+ 'correlation_id' => an_instance_of(String),
'feature_category' => 'importers'
})
end
@@ -27,11 +23,11 @@ RSpec.describe Gitlab::Import::Logger do
it 'formats hashes' do
output = subject.format_message('INFO', now, 'test', { hello: 1 })
- expect(Gitlab::Json.parse(output)).to eq({
+ expect(Gitlab::Json.parse(output)).to include({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'hello' => 1,
- 'correlation_id' => 'new-correlation-id',
+ 'correlation_id' => an_instance_of(String),
'feature_category' => 'importers'
})
end
diff --git a/spec/lib/gitlab/import_export/import_export_equivalence_spec.rb b/spec/lib/gitlab/import_export/import_export_equivalence_spec.rb
index d03c21d6b4f..6c997dc1361 100644
--- a/spec/lib/gitlab/import_export/import_export_equivalence_spec.rb
+++ b/spec/lib/gitlab/import_export/import_export_equivalence_spec.rb
@@ -25,7 +25,8 @@ RSpec.describe Gitlab::ImportExport, feature_category: :importers do
end
it 'yields the initial tree when importing and exporting it again' do
- project = create(:project, creator: create(:user, :admin))
+ project = create(:project)
+ user = create(:user, :admin)
# We first generate a test fixture dynamically from a seed-fixture, so as to
# account for any fields in the initial fixture that are missing and set to
@@ -34,6 +35,7 @@ RSpec.describe Gitlab::ImportExport, feature_category: :importers do
expect(
restore_then_save_project(
project,
+ user,
import_path: seed_fixture_path,
export_path: test_fixture_path)
).to be true
@@ -42,6 +44,7 @@ RSpec.describe Gitlab::ImportExport, feature_category: :importers do
expect(
restore_then_save_project(
project,
+ user,
import_path: test_fixture_path,
export_path: test_tmp_path)
).to be true
diff --git a/spec/lib/gitlab/json_logger_spec.rb b/spec/lib/gitlab/json_logger_spec.rb
index 801de357ddc..e975fc1b128 100644
--- a/spec/lib/gitlab/json_logger_spec.rb
+++ b/spec/lib/gitlab/json_logger_spec.rb
@@ -28,10 +28,6 @@ RSpec.describe Gitlab::JsonLogger do
end
describe '#format_message' do
- before do
- allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
- end
-
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
data = Gitlab::Json.parse(output)
@@ -39,7 +35,7 @@ RSpec.describe Gitlab::JsonLogger do
expect(data['severity']).to eq('INFO')
expect(data['time']).to eq(now.utc.iso8601(3))
expect(data['message']).to eq('Hello world')
- expect(data['correlation_id']).to eq('new-correlation-id')
+ expect(data['correlation_id']).to be_an_instance_of(String)
end
it 'formats hashes' do
@@ -50,7 +46,7 @@ RSpec.describe Gitlab::JsonLogger do
expect(data['time']).to eq(now.utc.iso8601(3))
expect(data['hello']).to eq(1)
expect(data['message']).to be_nil
- expect(data['correlation_id']).to eq('new-correlation-id')
+ expect(data['correlation_id']).to be_an_instance_of(String)
end
end
end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 74b38cfa464..423a7e80ead 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -210,7 +210,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
- RSpec.shared_examples_for 'fallback read from the secondary store' do
+ RSpec.shared_examples_for 'fallback read from the non-default store' do
let(:counter) { Gitlab::Metrics::NullMetric.instance }
before do
@@ -218,7 +218,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
it 'fallback and execute on secondary instance' do
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+ expect(multi_store.fallback_store).to receive(name).with(*expected_args).and_call_original
subject
end
@@ -242,7 +242,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when fallback read from the secondary instance raises an exception' do
before do
- allow(secondary_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(multi_store.fallback_store).to receive(name).with(*expected_args).and_raise(StandardError)
end
it 'fails with exception' do
@@ -296,7 +296,7 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
context 'when reading from primary instance is raising an exception' do
before do
- allow(primary_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(multi_store.default_store).to receive(name).with(*expected_args).and_raise(StandardError)
allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
@@ -307,16 +307,16 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
subject
end
- include_examples 'fallback read from the secondary store'
+ include_examples 'fallback read from the non-default store'
end
- context 'when reading from empty primary instance' do
+ context 'when reading from empty default instance' do
before do
- # this ensures a cache miss without having to stub primary store
- primary_store.flushdb
+ # this ensures a cache miss without having to stub the default store
+ multi_store.default_store.flushdb
end
- include_examples 'fallback read from the secondary store'
+ include_examples 'fallback read from the non-default store'
end
context 'when the command is executed within pipelined block' do
diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb
index fc5a9c879f6..e73319cfcd7 100644
--- a/spec/models/ci/group_variable_spec.rb
+++ b/spec/models/ci/group_variable_spec.rb
@@ -2,10 +2,13 @@
require 'spec_helper'
-RSpec.describe Ci::GroupVariable do
- subject { build(:ci_group_variable) }
+RSpec.describe Ci::GroupVariable, feature_category: :pipeline_authoring do
+ let_it_be_with_refind(:group) { create(:group) }
+
+ subject { build(:ci_group_variable, group: group) }
it_behaves_like "CI variable"
+ it_behaves_like 'includes Limitable concern'
it { is_expected.to include_module(Presentable) }
it { is_expected.to include_module(Ci::Maskable) }
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index 5f2b5971508..ce64b3ea158 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -2,10 +2,13 @@
require 'spec_helper'
-RSpec.describe Ci::Variable do
- subject { build(:ci_variable) }
+RSpec.describe Ci::Variable, feature_category: :pipeline_authoring do
+ let_it_be_with_reload(:project) { create(:project) }
+
+ subject { build(:ci_variable, project: project) }
it_behaves_like "CI variable"
+ it_behaves_like 'includes Limitable concern'
describe 'validations' do
it { is_expected.to include_module(Presentable) }
diff --git a/spec/requests/api/ci/variables_spec.rb b/spec/requests/api/ci/variables_spec.rb
index c5d01afb7c4..0f9f1bc80d6 100644
--- a/spec/requests/api/ci/variables_spec.rb
+++ b/spec/requests/api/ci/variables_spec.rb
@@ -114,73 +114,92 @@ RSpec.describe API::Ci::Variables, feature_category: :pipeline_authoring do
describe 'POST /projects/:id/variables' do
context 'authorized user with proper permissions' do
- it 'creates variable' do
- expect do
- post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
- end.to change { project.variables.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq('TEST_VARIABLE_2')
- expect(json_response['value']).to eq('PROTECTED_VALUE_2')
- expect(json_response['protected']).to be_truthy
- expect(json_response['masked']).to be_truthy
- expect(json_response['raw']).to be_truthy
- expect(json_response['variable_type']).to eq('env_var')
- end
+ context 'when the project is below the plan limit for variables' do
+ it 'creates variable' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
+ end.to change { project.variables.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('PROTECTED_VALUE_2')
+ expect(json_response['protected']).to be_truthy
+ expect(json_response['masked']).to be_truthy
+ expect(json_response['raw']).to be_truthy
+ expect(json_response['variable_type']).to eq('env_var')
+ end
- it 'masks the new value when logging' do
- masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+ it 'masks the new value when logging' do
+ masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
- expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
- post api("/projects/#{project.id}/variables", user),
- params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
- end
+ post api("/projects/#{project.id}/variables", user),
+ params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
+ end
- it 'creates variable with optional attributes' do
- expect do
- post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
- end.to change { project.variables.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq('TEST_VARIABLE_2')
- expect(json_response['value']).to eq('VALUE_2')
- expect(json_response['protected']).to be_falsey
- expect(json_response['masked']).to be_falsey
- expect(json_response['raw']).to be_falsey
- expect(json_response['variable_type']).to eq('file')
- end
+ it 'creates variable with optional attributes' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
+ end.to change { project.variables.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_falsey
+ expect(json_response['masked']).to be_falsey
+ expect(json_response['raw']).to be_falsey
+ expect(json_response['variable_type']).to eq('file')
+ end
- it 'does not allow to duplicate variable key' do
- expect do
- post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
- end.to change { project.variables.count }.by(0)
+ it 'does not allow to duplicate variable key' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
+ end.to change { project.variables.count }.by(0)
- expect(response).to have_gitlab_http_status(:bad_request)
- end
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
- it 'creates variable with a specific environment scope' do
- expect do
- post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'VALUE_2', environment_scope: 'review/*' }
- end.to change { project.variables.reload.count }.by(1)
+ it 'creates variable with a specific environment scope' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'VALUE_2', environment_scope: 'review/*' }
+ end.to change { project.variables.reload.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['environment_scope']).to eq('review/*')
+ end
+
+ it 'allows duplicated variable key given different environment scopes' do
+ variable = create(:ci_variable, project: project)
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq('TEST_VARIABLE_2')
- expect(json_response['value']).to eq('VALUE_2')
- expect(json_response['environment_scope']).to eq('review/*')
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2', environment_scope: 'review/*' }
+ end.to change { project.variables.reload.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq(variable.key)
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['environment_scope']).to eq('review/*')
+ end
end
- it 'allows duplicated variable key given different environment scopes' do
- variable = create(:ci_variable, project: project)
+ context 'when the project is at the plan limit for variables' do
+ before do
+ create(:plan_limits, :default_plan, project_ci_variables: 1)
+ end
- expect do
- post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2', environment_scope: 'review/*' }
- end.to change { project.variables.reload.count }.by(1)
+ it 'returns a variable limit error' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TOO_MANY_VARS', value: 'too many' }
+ end.not_to change { project.variables.count }
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq(variable.key)
- expect(json_response['value']).to eq('VALUE_2')
- expect(json_response['environment_scope']).to eq('review/*')
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']['base']).to contain_exactly(
+ 'Maximum number of project ci variables (1) exceeded'
+ )
+ end
end
end
diff --git a/spec/requests/api/draft_notes_spec.rb b/spec/requests/api/draft_notes_spec.rb
index b8331e072cf..e8f519e004d 100644
--- a/spec/requests/api/draft_notes_spec.rb
+++ b/spec/requests/api/draft_notes_spec.rb
@@ -12,6 +12,8 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
let!(:draft_note_by_current_user) { create(:draft_note, merge_request: merge_request, author: user) }
let!(:draft_note_by_random_user) { create(:draft_note, merge_request: merge_request) }
+ let_it_be(:api_stub) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}" }
+
before do
project.add_developer(user)
end
@@ -117,4 +119,60 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do
end
end
end
+
+ describe "Publishing a draft note" do
+ let(:publish_draft_note) do
+ put api(
+ "#{api_stub}/draft_notes/#{draft_note_by_current_user.id}/publish",
+ user
+ )
+ end
+
+ context "when publishing an existing draft note by the user" do
+ it "returns 204 No Content status" do
+ publish_draft_note
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+
+ it "publishes the specified draft note" do
+ expect { publish_draft_note }.to change { Note.count }.by(1)
+ expect(DraftNote.exists?(draft_note_by_current_user.id)).to eq(false)
+ end
+ end
+
+ context "when publishing a non-existent draft note" do
+ it "returns a 404 Not Found" do
+ put api(
+ "#{api_stub}/draft_notes/#{non_existing_record_id}/publish",
+ user
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when publishing a draft note by a different user" do
+ it "returns a 404 Not Found" do
+ put api(
+ "#{api_stub}/draft_notes/#{draft_note_by_random_user.id}/publish",
+ user
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when DraftNotes::PublishService returns a non-success" do
+ it "returns an :internal_server_error and a message" do
+ expect_next_instance_of(DraftNotes::PublishService) do |instance|
+ expect(instance).to receive(:execute).and_return({ status: :failure, message: "Error message" })
+ end
+
+ publish_draft_note
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb
index 90b9606ec7b..e3d538d72ba 100644
--- a/spec/requests/api/group_variables_spec.rb
+++ b/spec/requests/api/group_variables_spec.rb
@@ -88,51 +88,70 @@ RSpec.describe API::GroupVariables, feature_category: :pipeline_authoring do
context 'authorized user with proper permissions' do
let(:access_level) { :owner }
- it 'creates variable' do
- expect do
- post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
- end.to change { group.variables.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq('TEST_VARIABLE_2')
- expect(json_response['value']).to eq('PROTECTED_VALUE_2')
- expect(json_response['protected']).to be_truthy
- expect(json_response['masked']).to be_truthy
- expect(json_response['variable_type']).to eq('env_var')
- expect(json_response['environment_scope']).to eq('*')
- expect(json_response['raw']).to be_truthy
+ context 'when the group is below the plan limit for variables' do
+ it 'creates variable' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
+ end.to change { group.variables.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('PROTECTED_VALUE_2')
+ expect(json_response['protected']).to be_truthy
+ expect(json_response['masked']).to be_truthy
+ expect(json_response['variable_type']).to eq('env_var')
+ expect(json_response['environment_scope']).to eq('*')
+ expect(json_response['raw']).to be_truthy
+ end
+
+ it 'masks the new value when logging' do
+ masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ post api("/groups/#{group.id}/variables", user),
+ params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
+ end
+
+ it 'creates variable with optional attributes' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
+ end.to change { group.variables.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_falsey
+ expect(json_response['masked']).to be_falsey
+ expect(json_response['raw']).to be_falsey
+ expect(json_response['variable_type']).to eq('file')
+ expect(json_response['environment_scope']).to eq('*')
+ end
+
+ it 'does not allow to duplicate variable key' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
+ end.to change { group.variables.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
- it 'masks the new value when logging' do
- masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
-
- expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
-
- post api("/groups/#{group.id}/variables", user),
- params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
- end
-
- it 'creates variable with optional attributes' do
- expect do
- post api("/groups/#{group.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
- end.to change { group.variables.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response['key']).to eq('TEST_VARIABLE_2')
- expect(json_response['value']).to eq('VALUE_2')
- expect(json_response['protected']).to be_falsey
- expect(json_response['masked']).to be_falsey
- expect(json_response['raw']).to be_falsey
- expect(json_response['variable_type']).to eq('file')
- expect(json_response['environment_scope']).to eq('*')
- end
-
- it 'does not allow to duplicate variable key' do
- expect do
- post api("/groups/#{group.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
- end.to change { group.variables.count }.by(0)
-
- expect(response).to have_gitlab_http_status(:bad_request)
+ context 'when the group is at the plan limit for variables' do
+ before do
+ create(:plan_limits, :default_plan, group_ci_variables: 1)
+ end
+
+ it 'returns a variable limit error' do
+ expect do
+ post api("/groups/#{group.id}/variables", user), params: { key: 'TOO_MANY_VARS', value: 'too many' }
+ end.not_to change { group.variables.count }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']['base']).to contain_exactly(
+ 'Maximum number of group ci variables (1) exceeded'
+ )
+ end
end
end
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index cc3635a0afc..06d8523b2e7 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe IssueEntity do
before do
Issues::DuplicateService
- .new(project: project, current_user: member)
+ .new(container: project, current_user: member)
.execute(issue, new_issue)
end
diff --git a/spec/services/issues/after_create_service_spec.rb b/spec/services/issues/after_create_service_spec.rb
index 6b720d6e687..39a6799dbad 100644
--- a/spec/services/issues/after_create_service_spec.rb
+++ b/spec/services/issues/after_create_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Issues::AfterCreateService do
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:issue) { create(:issue, project: project, author: current_user, milestone: milestone, assignee_ids: [assignee.id]) }
- subject(:after_create_service) { described_class.new(project: project, current_user: current_user) }
+ subject(:after_create_service) { described_class.new(container: project, current_user: current_user) }
describe '#execute' do
it 'creates a pending todo for new assignee' do
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index ef24d1e940e..803808e667c 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -20,13 +20,13 @@ RSpec.describe Issues::CloseService do
end
describe '#execute' do
- let(:service) { described_class.new(project: project, current_user: user) }
+ let(:service) { described_class.new(container: project, current_user: user) }
context 'when skip_authorization is true' do
it 'does close the issue even if user is not authorized' do
non_authorized_user = create(:user)
- service = described_class.new(project: project, current_user: non_authorized_user)
+ service = described_class.new(container: project, current_user: non_authorized_user)
expect do
service.execute(issue, skip_authorization: true)
@@ -167,7 +167,7 @@ RSpec.describe Issues::CloseService do
project.reload
expect(project.external_issue_tracker).to receive(:close_issue)
- described_class.new(project: project, current_user: user).close_issue(external_issue)
+ described_class.new(container: project, current_user: user).close_issue(external_issue)
end
end
@@ -178,7 +178,7 @@ RSpec.describe Issues::CloseService do
project.reload
expect(project.external_issue_tracker).not_to receive(:close_issue)
- described_class.new(project: project, current_user: user).close_issue(external_issue)
+ described_class.new(container: project, current_user: user).close_issue(external_issue)
end
end
@@ -189,7 +189,7 @@ RSpec.describe Issues::CloseService do
project.reload
expect(project.external_issue_tracker).not_to receive(:close_issue)
- described_class.new(project: project, current_user: user).close_issue(external_issue)
+ described_class.new(container: project, current_user: user).close_issue(external_issue)
end
end
end
@@ -197,7 +197,7 @@ RSpec.describe Issues::CloseService do
context "closed by a merge request", :sidekiq_might_not_need_inline do
subject(:close_issue) do
perform_enqueued_jobs do
- described_class.new(project: project, current_user: user).close_issue(issue, closed_via: closing_merge_request)
+ described_class.new(container: project, current_user: user).close_issue(issue, closed_via: closing_merge_request)
end
end
@@ -266,7 +266,7 @@ RSpec.describe Issues::CloseService do
context "closed by a commit", :sidekiq_might_not_need_inline do
it 'mentions closure via a commit' do
perform_enqueued_jobs do
- described_class.new(project: project, current_user: user).close_issue(issue, closed_via: closing_commit)
+ described_class.new(container: project, current_user: user).close_issue(issue, closed_via: closing_commit)
end
email = ActionMailer::Base.deliveries.last
@@ -280,7 +280,7 @@ RSpec.describe Issues::CloseService do
it 'does not mention the commit id' do
project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED)
perform_enqueued_jobs do
- described_class.new(project: project, current_user: user).close_issue(issue, closed_via: closing_commit)
+ described_class.new(container: project, current_user: user).close_issue(issue, closed_via: closing_commit)
end
email = ActionMailer::Base.deliveries.last
@@ -296,7 +296,7 @@ RSpec.describe Issues::CloseService do
context "valid params" do
subject(:close_issue) do
perform_enqueued_jobs do
- described_class.new(project: project, current_user: user).close_issue(issue)
+ described_class.new(container: project, current_user: user).close_issue(issue)
end
end
@@ -438,7 +438,7 @@ RSpec.describe Issues::CloseService do
expect(project).to receive(:execute_hooks).with(expected_payload, :issue_hooks)
expect(project).to receive(:execute_integrations).with(expected_payload, :issue_hooks)
- described_class.new(project: project, current_user: user).close_issue(issue)
+ described_class.new(container: project, current_user: user).close_issue(issue)
end
end
@@ -449,7 +449,7 @@ RSpec.describe Issues::CloseService do
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :confidential_issue_hooks)
- described_class.new(project: project, current_user: user).close_issue(issue)
+ described_class.new(container: project, current_user: user).close_issue(issue)
end
end
diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb
index 0eb0bbb1480..f49bce70cd0 100644
--- a/spec/services/issues/duplicate_service_spec.rb
+++ b/spec/services/issues/duplicate_service_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Issues::DuplicateService do
let(:canonical_issue) { create(:issue, project: canonical_project) }
let(:duplicate_issue) { create(:issue, project: duplicate_project) }
- subject { described_class.new(project: duplicate_project, current_user: user) }
+ subject { described_class.new(container: duplicate_project, current_user: user) }
describe '#execute' do
context 'when the issues passed are the same' do
diff --git a/spec/services/issues/referenced_merge_requests_service_spec.rb b/spec/services/issues/referenced_merge_requests_service_spec.rb
index 16166c1fa33..aee3583b834 100644
--- a/spec/services/issues/referenced_merge_requests_service_spec.rb
+++ b/spec/services/issues/referenced_merge_requests_service_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Issues::ReferencedMergeRequestsService do
let_it_be(:referencing_mr) { create_referencing_mr(source_project: project, source_branch: 'csv') }
let_it_be(:referencing_mr_other_project) { create_referencing_mr(source_project: other_project, source_branch: 'csv') }
- let(:service) { described_class.new(project: project, current_user: user) }
+ let(:service) { described_class.new(container: project, current_user: user) }
describe '#execute' do
it 'returns a list of sorted merge requests' do
diff --git a/spec/services/issues/related_branches_service_spec.rb b/spec/services/issues/related_branches_service_spec.rb
index 95d456c1b05..05c61d0abfc 100644
--- a/spec/services/issues/related_branches_service_spec.rb
+++ b/spec/services/issues/related_branches_service_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Issues::RelatedBranchesService do
let(:user) { developer }
- subject { described_class.new(project: project, current_user: user) }
+ subject { described_class.new(container: project, current_user: user) }
before_all do
project.add_developer(developer)
@@ -54,7 +54,7 @@ RSpec.describe Issues::RelatedBranchesService do
merge_request.create_cross_references!(user)
referenced_merge_requests = Issues::ReferencedMergeRequestsService
- .new(project: issue.project, current_user: user)
+ .new(container: issue.project, current_user: user)
.referenced_merge_requests(issue)
expect(referenced_merge_requests).not_to be_empty
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 529b3ff266b..68015a2327e 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Issues::ReopenService do
guest = create(:user)
project.add_guest(guest)
- described_class.new(project: project, current_user: guest).execute(issue)
+ described_class.new(container: project, current_user: guest).execute(issue)
expect(issue).to be_closed
end
@@ -21,7 +21,7 @@ RSpec.describe Issues::ReopenService do
it 'does close the issue even if user is not authorized' do
non_authorized_user = create(:user)
- service = described_class.new(project: project, current_user: non_authorized_user)
+ service = described_class.new(container: project, current_user: non_authorized_user)
expect do
service.execute(issue, skip_authorization: true)
@@ -33,7 +33,7 @@ RSpec.describe Issues::ReopenService do
context 'when user is authorized to reopen issue' do
let(:user) { create(:user) }
- subject(:execute) { described_class.new(project: project, current_user: user).execute(issue) }
+ subject(:execute) { described_class.new(container: project, current_user: user).execute(issue) }
before do
project.add_maintainer(user)
diff --git a/spec/services/issues/reorder_service_spec.rb b/spec/services/issues/reorder_service_spec.rb
index 392930c1b9f..430a9e9f526 100644
--- a/spec/services/issues/reorder_service_spec.rb
+++ b/spec/services/issues/reorder_service_spec.rb
@@ -85,6 +85,6 @@ RSpec.describe Issues::ReorderService do
end
def service(params)
- described_class.new(project: project, current_user: user, params: params)
+ described_class.new(container: project, current_user: user, params: params)
end
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index f1859b2208c..973025bd2e3 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe Issues::UpdateService, :mailer do
end
def update_issue(opts)
- described_class.new(project: project, current_user: user, params: opts).execute(issue)
+ described_class.new(container: project, current_user: user, params: opts).execute(issue)
end
it_behaves_like 'issuable update service updating last_edited_at values' do
@@ -420,7 +420,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts[:move_between_ids] = [issue_1.id, issue_2.id]
- described_class.new(project: issue_3.project, current_user: user, params: opts).execute(issue_3)
+ described_class.new(container: issue_3.project, current_user: user, params: opts).execute(issue_3)
expect(issue_2.relative_position).to be_between(issue_1.relative_position, issue_2.relative_position)
end
end
@@ -428,7 +428,7 @@ RSpec.describe Issues::UpdateService, :mailer do
context 'when current user cannot admin issues in the project' do
it 'filters out params that cannot be set without the :admin_issue permission' do
described_class.new(
- project: project, current_user: guest, params: opts.merge(
+ container: project, current_user: guest, params: opts.merge(
confidential: true,
issue_type: 'test_case'
)
@@ -838,7 +838,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts = { label_ids: [label.id] }
perform_enqueued_jobs do
- @issue = described_class.new(project: project, current_user: user, params: opts).execute(issue)
+ @issue = described_class.new(container: project, current_user: user, params: opts).execute(issue)
end
should_email(subscriber)
@@ -854,7 +854,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts = { label_ids: [label.id, label2.id] }
perform_enqueued_jobs do
- @issue = described_class.new(project: project, current_user: user, params: opts).execute(issue)
+ @issue = described_class.new(container: project, current_user: user, params: opts).execute(issue)
end
should_not_email(subscriber)
@@ -865,7 +865,7 @@ RSpec.describe Issues::UpdateService, :mailer do
opts = { label_ids: [label2.id] }
perform_enqueued_jobs do
- @issue = described_class.new(project: project, current_user: user, params: opts).execute(issue)
+ @issue = described_class.new(container: project, current_user: user, params: opts).execute(issue)
end
should_not_email(subscriber)
@@ -897,7 +897,7 @@ RSpec.describe Issues::UpdateService, :mailer do
line_number: 1
}
}
- service = described_class.new(project: project, current_user: user, params: params)
+ service = described_class.new(container: project, current_user: user, params: params)
expect(Spam::SpamActionService).not_to receive(:new)
@@ -915,7 +915,7 @@ RSpec.describe Issues::UpdateService, :mailer do
line_number: 1
}
}
- service = described_class.new(project: project, current_user: user, params: params)
+ service = described_class.new(container: project, current_user: user, params: params)
expect(service).to receive(:after_update).with(issue, {})
@@ -991,7 +991,7 @@ RSpec.describe Issues::UpdateService, :mailer do
context 'updating labels' do
let(:label3) { create(:label, project: project) }
- let(:result) { described_class.new(project: project, current_user: user, params: params).execute(issue).reload }
+ let(:result) { described_class.new(container: project, current_user: user, params: params).execute(issue).reload }
context 'when add_label_ids and label_ids are passed' do
let(:params) { { label_ids: [label.id], add_label_ids: [label3.id] } }
@@ -1063,7 +1063,7 @@ RSpec.describe Issues::UpdateService, :mailer do
end
context 'updating dates' do
- subject(:result) { described_class.new(project: project, current_user: user, params: params).execute(issue) }
+ subject(:result) { described_class.new(container: project, current_user: user, params: params).execute(issue) }
let(:updated_date) { 1.week.from_now.to_date }
@@ -1428,7 +1428,7 @@ RSpec.describe Issues::UpdateService, :mailer do
it 'raises an error for invalid move ids' do
opts = { move_between_ids: [9000, non_existing_record_id] }
- expect { described_class.new(project: issue.project, current_user: user, params: opts).execute(issue) }
+ expect { described_class.new(container: issue.project, current_user: user, params: opts).execute(issue) }
.to raise_error(ActiveRecord::RecordNotFound)
end
end
@@ -1473,7 +1473,7 @@ RSpec.describe Issues::UpdateService, :mailer do
it_behaves_like 'issuable record that supports quick actions' do
let(:existing_issue) { create(:issue, project: project) }
- let(:issuable) { described_class.new(project: project, current_user: user, params: params).execute(existing_issue) }
+ let(:issuable) { described_class.new(container: project, current_user: user, params: params).execute(existing_issue) }
end
context 'with quick actions' do
diff --git a/spec/services/issues/zoom_link_service_spec.rb b/spec/services/issues/zoom_link_service_spec.rb
index ad1f91ab5e6..230e4c1b5e1 100644
--- a/spec/services/issues/zoom_link_service_spec.rb
+++ b/spec/services/issues/zoom_link_service_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Issues::ZoomLinkService do
let_it_be(:issue) { create(:issue) }
let(:project) { issue.project }
- let(:service) { described_class.new(project: project, current_user: user, params: { issue: issue }) }
+ let(:service) { described_class.new(container: project, current_user: user, params: { issue: issue }) }
let(:zoom_link) { 'https://zoom.us/j/123456789' }
before do
diff --git a/spec/services/tasks_to_be_done/base_service_spec.rb b/spec/services/tasks_to_be_done/base_service_spec.rb
index 8ea9a6a8ec2..cfeff36cc0d 100644
--- a/spec/services/tasks_to_be_done/base_service_spec.rb
+++ b/spec/services/tasks_to_be_done/base_service_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe TasksToBeDone::BaseService do
expect(Issues::UpdateService)
.to receive(:new)
- .with(project: project, current_user: current_user, params: params)
+ .with(container: project, current_user: current_user, params: params)
.and_call_original
expect { service.execute }.not_to change(Issue, :count)
diff --git a/spec/services/work_items/update_service_spec.rb b/spec/services/work_items/update_service_spec.rb
index 87665bcad2c..435995c6570 100644
--- a/spec/services/work_items/update_service_spec.rb
+++ b/spec/services/work_items/update_service_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe WorkItems::UpdateService do
describe '#execute' do
let(:service) do
described_class.new(
- project: project,
+ container: project,
current_user: current_user,
params: opts,
spam_params: spam_params,
@@ -146,7 +146,7 @@ RSpec.describe WorkItems::UpdateService do
let(:service) do
described_class.new(
- project: project,
+ container: project,
current_user: current_user,
params: opts,
spam_params: spam_params,
@@ -362,7 +362,7 @@ RSpec.describe WorkItems::UpdateService do
def update_issuable(update_params)
described_class.new(
- project: project,
+ container: project,
current_user: current_user,
params: update_params,
spam_params: spam_params,
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 632f3ea28ee..eba5771e062 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -185,7 +185,7 @@ module CycleAnalyticsHelpers
def merge_merge_requests_closing_issue(user, project, issue)
merge_requests = Issues::ReferencedMergeRequestsService
- .new(project: project, current_user: user)
+ .new(container: project, current_user: user)
.closed_by_merge_requests(issue)
merge_requests.each { |merge_request| MergeRequests::MergeService.new(project: project, current_user: user, params: { sha: merge_request.diff_head_sha }).execute(merge_request) }
diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb
index 3d7a0d29e71..f8f32fa59d1 100644
--- a/spec/support/import_export/common_util.rb
+++ b/spec/support/import_export/common_util.rb
@@ -51,22 +51,22 @@ module ImportExport
json
end
- def restore_then_save_project(project, import_path:, export_path:)
- project_restorer = get_project_restorer(project, import_path)
- project_saver = get_project_saver(project, export_path)
+ def restore_then_save_project(project, user, import_path:, export_path:)
+ project_restorer = get_project_restorer(project, user, import_path)
+ project_saver = get_project_saver(project, user, export_path)
project_restorer.restore && project_saver.save
end
- def get_project_restorer(project, import_path)
+ def get_project_restorer(project, user, import_path)
Gitlab::ImportExport::Project::TreeRestorer.new(
- user: project.creator, shared: get_shared_env(path: import_path), project: project
+ user: user, shared: get_shared_env(path: import_path), project: project
)
end
- def get_project_saver(project, export_path)
+ def get_project_saver(project, user, export_path)
Gitlab::ImportExport::Project::TreeSaver.new(
- project: project, current_user: project.creator, shared: get_shared_env(path: export_path)
+ project: project, current_user: user, shared: get_shared_env(path: export_path)
)
end
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index b85c3904127..feea21be428 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -26,7 +26,7 @@ RSpec.shared_examples 'issuable update service' do
expect(project).to receive(:execute_hooks).with(expected_payload, hook_event)
expect(project).to receive(:execute_integrations).with(expected_payload, hook_event)
- described_class.new(project: project, current_user: user, params: { state_event: 'reopen' }).execute(closed_issuable)
+ described_class.new(**described_class.constructor_container_arg(project), current_user: user, params: { state_event: 'reopen' }).execute(closed_issuable)
end
end
@@ -48,7 +48,7 @@ RSpec.shared_examples 'issuable update service' do
expect(project).to receive(:execute_hooks).with(expected_payload, hook_event)
expect(project).to receive(:execute_integrations).with(expected_payload, hook_event)
- described_class.new(project: project, current_user: user, params: { state_event: 'close' }).execute(open_issuable)
+ described_class.new(**described_class.constructor_container_arg(project), current_user: user, params: { state_event: 'close' }).execute(open_issuable)
end
end
end
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 61a9c2e8aea..4f3d957ad71 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -106,7 +106,7 @@ RSpec.shared_examples 'work items description' do
wait_for_requests
::WorkItems::UpdateService.new(
- project: work_item.project,
+ container: work_item.project,
current_user: other_user,
params: { description: "oh no!" }
).execute(work_item)
diff --git a/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb
index 381583ff2a9..86a1fd76d09 100644
--- a/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb
@@ -142,7 +142,7 @@ RSpec.shared_examples 'time tracking endpoints' do |issuable_name|
if issuable_name == 'issue'
it 'calls update service without :use_specialized_service param' do
expect(::Issues::UpdateService).to receive(:new).with(
- project: project,
+ container: project,
current_user: user,
params: { spend_time: { duration: 3600, summary: 'summary', user_id: user.id } })
diff --git a/spec/support/shared_examples/services/issuable_shared_examples.rb b/spec/support/shared_examples/services/issuable_shared_examples.rb
index 142d4ae8531..fe868d494d2 100644
--- a/spec/support/shared_examples/services/issuable_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable_shared_examples.rb
@@ -11,7 +11,8 @@ end
RSpec.shared_examples 'updating a single task' do
def update_issuable(opts)
issuable = try(:issue) || try(:merge_request)
- described_class.new(project: project, current_user: user, params: opts).execute(issuable)
+ described_class.new(**described_class.constructor_container_arg(project), current_user: user, params: opts)
+ .execute(issuable)
end
before do
diff --git a/spec/support/shared_examples/services/updating_mentions_shared_examples.rb b/spec/support/shared_examples/services/updating_mentions_shared_examples.rb
index 13a2aa9ddac..0f649173683 100644
--- a/spec/support/shared_examples/services/updating_mentions_shared_examples.rb
+++ b/spec/support/shared_examples/services/updating_mentions_shared_examples.rb
@@ -15,7 +15,8 @@ RSpec.shared_examples 'updating mentions' do |service_class|
def update_mentionable(opts)
perform_enqueued_jobs do
- service_class.new(project: project, current_user: user, params: opts).execute(mentionable)
+ service_class.new(**service_class.constructor_container_arg(project),
+ current_user: user, params: opts).execute(mentionable)
end
mentionable.reload
diff --git a/spec/workers/incident_management/close_incident_worker_spec.rb b/spec/workers/incident_management/close_incident_worker_spec.rb
index c96bb4a3d1e..145ee780573 100644
--- a/spec/workers/incident_management/close_incident_worker_spec.rb
+++ b/spec/workers/incident_management/close_incident_worker_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe IncidentManagement::CloseIncidentWorker do
let(:issue_id) { issue.id }
it 'calls the close issue service' do
- expect_next_instance_of(Issues::CloseService, project: project, current_user: user) do |service|
+ expect_next_instance_of(Issues::CloseService, container: project, current_user: user) do |service|
expect(service).to receive(:execute).with(issue, system_note: false).and_call_original
end
diff --git a/spec/workers/issues/close_worker_spec.rb b/spec/workers/issues/close_worker_spec.rb
index 41611447db1..3902618ae03 100644
--- a/spec/workers/issues/close_worker_spec.rb
+++ b/spec/workers/issues/close_worker_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Issues::CloseWorker do
external_issue = ExternalIssue.new("foo", project)
closer = instance_double(Issues::CloseService, execute: true)
- expect(Issues::CloseService).to receive(:new).with(project: project, current_user: user).and_return(closer)
+ expect(Issues::CloseService).to receive(:new).with(container: project, current_user: user).and_return(closer)
expect(closer).to receive(:execute).with(external_issue, commit: commit)
worker.perform(project.id, external_issue.id, external_issue.class.to_s, opts)
diff --git a/spec/workers/merge_requests/close_issue_worker_spec.rb b/spec/workers/merge_requests/close_issue_worker_spec.rb
index 5e6bdc2a43e..72fb3be7470 100644
--- a/spec/workers/merge_requests/close_issue_worker_spec.rb
+++ b/spec/workers/merge_requests/close_issue_worker_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe MergeRequests::CloseIssueWorker do
let!(:merge_request) { create(:merge_request, source_project: project) }
it 'calls the close issue service' do
- expect_next_instance_of(Issues::CloseService, project: project, current_user: user) do |service|
+ expect_next_instance_of(Issues::CloseService, container: project, current_user: user) do |service|
expect(service).to receive(:execute).with(issue, commit: merge_request)
end