diff options
41 files changed, 366 insertions, 196 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e0f68ea4ed..cae75baf059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 15.7.3 (2023-01-11) + +### Fixed (3 changes) + +- [Reset Container Repository Sync status on secondary](gitlab-org/gitlab@5a6d024e199c9ab9fd39df2db44a133c022eadd5) ([merge request](gitlab-org/gitlab!108679)) +- [Enforce memory-watchdog by default](gitlab-org/gitlab@6f7fcb0f50330af46a5f7311796e5375d6d59816) ([merge request](gitlab-org/gitlab!108679)) +- [Geo: Container Repository push events don't work](gitlab-org/gitlab@721227d157cd2f4fd842e5dcf54180bcc470336a) ([merge request](gitlab-org/gitlab!108679)) + ## 15.7.2 (2023-01-09) ### Security (9 changes) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 80f3271ae4a..efadc82b103 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -5ac19c65a70ffe94d1cc52232f2f23071e782cef +7a5fbaf0eb3e4278d179cbad253a94f07f88dffc diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue index 1335a3b108b..970e3509d20 100644 --- a/app/assets/javascripts/boards/components/board_app.vue +++ b/app/assets/javascripts/boards/components/board_app.vue @@ -11,7 +11,7 @@ export default { BoardSettingsSidebar, BoardTopBar, }, - inject: ['disabled', 'fullBoardId'], + inject: ['fullBoardId'], computed: { ...mapGetters(['isSidebarOpen']), }, @@ -27,7 +27,7 @@ export default { <template> <div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }"> <board-top-bar /> - <board-content :disabled="disabled" :board-id="fullBoardId" /> + <board-content :board-id="fullBoardId" /> <board-settings-sidebar /> </div> </template> diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index f3307977be9..0c64cbad5b1 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -9,6 +9,7 @@ export default { BoardCardInner, }, mixins: [Tracking.mixin()], + inject: ['disabled'], props: { list: { type: Object, @@ -20,11 +21,6 @@ export default { default: () => ({}), required: false, }, - disabled: { - type: Boolean, - default: false, - required: false, - }, index: { type: Number, default: 0, @@ -35,6 +31,11 @@ export default { default: false, required: false, }, + canAdmin: { + type: Boolean, + required: false, + default: true, + }, }, computed: { ...mapState(['selectedBoardItems', 'activeId']), @@ -48,10 +49,10 @@ export default { ); }, isDisabled() { - return this.disabled || !this.item.id || this.item.isLoading; + return this.disabled || !this.item.id || this.item.isLoading || !this.canAdmin; }, isDraggable() { - return !this.disabled && this.item.id && !this.item.isLoading; + return !this.isDisabled; }, cardStyle() { return this.isColorful && this.item.color ? { borderColor: this.item.color } : ''; diff --git a/app/assets/javascripts/boards/components/board_column.vue b/app/assets/javascripts/boards/components/board_column.vue index 8fc76c02e14..b728b8dd22a 100644 --- a/app/assets/javascripts/boards/components/board_column.vue +++ b/app/assets/javascripts/boards/components/board_column.vue @@ -20,10 +20,6 @@ export default { default: () => ({}), required: false, }, - disabled: { - type: Boolean, - required: true, - }, }, computed: { ...mapState(['filterParams', 'highlightedLists']), @@ -87,8 +83,8 @@ export default { class="board-inner gl-display-flex gl-flex-direction-column gl-relative gl-h-full gl-rounded-base gl-bg-gray-50" :class="{ 'board-column-highlighted': highlighted }" > - <board-list-header :list="list" :disabled="disabled" /> - <board-list ref="board-list" :disabled="disabled" :board-items="listItems" :list="list" /> + <board-list-header :list="list" /> + <board-list ref="board-list" :board-items="listItems" :list="list" /> </div> </div> </template> diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue index 1d585e3407b..92f79e61f14 100644 --- a/app/assets/javascripts/boards/components/board_content.vue +++ b/app/assets/javascripts/boards/components/board_content.vue @@ -36,13 +36,10 @@ export default { 'isIssueBoard', 'isEpicBoard', 'isGroupBoard', + 'disabled', 'isApolloBoard', ], props: { - disabled: { - type: Boolean, - required: true, - }, boardId: { type: String, required: true, @@ -177,7 +174,6 @@ export default { ref="board" :list="list" :data-draggable-item-type="$options.draggableItemTypes.list" - :disabled="disabled" :class="{ 'gl-xs-display-none!': addColumnFormVisible }" /> @@ -191,7 +187,6 @@ export default { ref="swimlanes" :lists="boardListsToUse" :can-admin-list="canAdminList" - :disabled="disabled" :style="{ height: boardHeight }" /> diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 215691c7ba2..060a708a22f 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -31,12 +31,8 @@ export default { BoardCardMoveToPosition, }, mixins: [Tracking.mixin()], - inject: ['isEpicBoard'], + inject: ['isEpicBoard', 'disabled'], props: { - disabled: { - type: Boolean, - required: true, - }, list: { type: Object, required: true, @@ -314,7 +310,6 @@ export default { :list="list" :item="item" :data-draggable-item-type="$options.draggableItemTypes.card" - :disabled="disabled" :show-work-item-type-icon="!isEpicBoard" > <!-- TODO: remove the condition when https://gitlab.com/gitlab-org/gitlab/-/issues/377862 is resolved --> diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index bfc4b52baaf..14dff8de70f 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -60,6 +60,9 @@ export default { isEpicBoard: { default: false, }, + disabled: { + default: true, + }, }, props: { list: { @@ -67,10 +70,6 @@ export default { default: () => ({}), required: false, }, - disabled: { - type: Boolean, - required: true, - }, isSwimlanesHeader: { type: Boolean, required: false, diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 5f00b4d85c6..f6cbe889128 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -94,6 +94,10 @@ module MergeRequests private + def refresh_pipelines_on_merge_requests(merge_request, allow_duplicate: false) + create_pipeline_for(merge_request, current_user, async: true, allow_duplicate: allow_duplicate) + end + def enqueue_jira_connect_messages_for(merge_request) return unless project.jira_subscription_exists? diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 533d0052fb8..ce49d5dd43c 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -162,10 +162,6 @@ module MergeRequests @outdate_service ||= Suggestions::OutdateService.new end - def refresh_pipelines_on_merge_requests(merge_request) - create_pipeline_for(merge_request, current_user, async: true) - end - def abort_auto_merges(merge_request) abort_auto_merge(merge_request, 'source branch was updated') end diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 745647b727c..a273b853c0d 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -169,6 +169,8 @@ module MergeRequests merge_request.target_branch ) + refresh_pipelines_on_merge_requests(merge_request, allow_duplicate: true) + abort_auto_merge(merge_request, 'target branch was changed') end diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index 5e89b9f3362..f9e12c5135a 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -18,9 +18,8 @@ class RepositoryImportWorker # rubocop:disable Scalability/IdempotentWorker sidekiq_options memory_killer_max_memory_growth_kb: ENV.fetch('MEMORY_KILLER_REPOSITORY_IMPORT_WORKER_MAX_MEMORY_GROWTH_KB', 300_000).to_i def perform(project_id) - @project = Project.find(project_id) - - return unless start_import + @project = Project.find_by_id(project_id) + return if project.nil? || !start_import? Gitlab::Metrics.add_event(:import_repository) @@ -42,7 +41,7 @@ class RepositoryImportWorker # rubocop:disable Scalability/IdempotentWorker attr_reader :project - def start_import + def start_import? return true if start(project.import_state) Gitlab::Import::Logger.info( diff --git a/db/migrate/20221221171239_rename_amount_used_column.rb b/db/migrate/20221221171239_rename_amount_used_column.rb new file mode 100644 index 00000000000..f25407a85af --- /dev/null +++ b/db/migrate/20221221171239_rename_amount_used_column.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class RenameAmountUsedColumn < Gitlab::Database::Migration[2.1] + TRIGGER_NAME = 'sync_projects_amount_used_columns' + def up + rename_column :ci_project_monthly_usages, :amount_used, :tmp_amount_used + rename_column :ci_project_monthly_usages, :new_amount_used, :amount_used + rename_column :ci_project_monthly_usages, :tmp_amount_used, :new_amount_used + + remove_rename_triggers(:ci_project_monthly_usages, TRIGGER_NAME) + install_rename_triggers(:ci_project_monthly_usages, :amount_used, :new_amount_used, trigger_name: TRIGGER_NAME) + end + + def down + rename_column :ci_project_monthly_usages, :amount_used, :tmp_amount_used + rename_column :ci_project_monthly_usages, :new_amount_used, :amount_used + rename_column :ci_project_monthly_usages, :tmp_amount_used, :new_amount_used + + remove_rename_triggers(:ci_project_monthly_usages, TRIGGER_NAME) + install_rename_triggers(:ci_project_monthly_usages, :amount_used, :new_amount_used, trigger_name: TRIGGER_NAME) + end +end diff --git a/db/migrate/20230111092510_add_migrate_projects_to_bulk_import_entities.rb b/db/migrate/20230111092510_add_migrate_projects_to_bulk_import_entities.rb new file mode 100644 index 00000000000..d09a796ba5c --- /dev/null +++ b/db/migrate/20230111092510_add_migrate_projects_to_bulk_import_entities.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddMigrateProjectsToBulkImportEntities < Gitlab::Database::Migration[2.1] + def change + add_column :bulk_import_entities, :migrate_projects, :boolean, null: false, default: true + end +end diff --git a/db/post_migrate/20221222092958_sync_new_amount_used_with_amount_used.rb b/db/post_migrate/20221222092958_sync_new_amount_used_with_amount_used.rb new file mode 100644 index 00000000000..9d8e2ee54d6 --- /dev/null +++ b/db/post_migrate/20221222092958_sync_new_amount_used_with_amount_used.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class SyncNewAmountUsedWithAmountUsed < Gitlab::Database::Migration[2.1] + restrict_gitlab_migration gitlab_schema: :gitlab_ci + + def up + # This migration will only run on rollback, there is no need for the positive case + end + + def down + project_usages = define_batchable_model('ci_project_monthly_usages') + + project_usages.each_batch(of: 500) do |batch| + batch.where('amount_used > 0').update_all('new_amount_used = amount_used') + end + end +end diff --git a/db/post_migrate/20230104103748_remove_new_amount_used_column.rb b/db/post_migrate/20230104103748_remove_new_amount_used_column.rb new file mode 100644 index 00000000000..0aaa7c1bd8f --- /dev/null +++ b/db/post_migrate/20230104103748_remove_new_amount_used_column.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class RemoveNewAmountUsedColumn < Gitlab::Database::Migration[2.1] + TRIGGER_NAME = 'sync_projects_amount_used_columns' + def up + remove_rename_triggers :ci_project_monthly_usages, TRIGGER_NAME + remove_column :ci_project_monthly_usages, :new_amount_used + end + + def down + return if column_exists?(:ci_project_monthly_usages, :new_amount_used) + + # rubocop:disable Migration/SchemaAdditionMethodsNoPost, Migration/AddColumnsToWideTables + add_column :ci_project_monthly_usages, :new_amount_used, :decimal, default: 0.0, + precision: 18, scale: 2, null: false + # rubocop:enable Migration/SchemaAdditionMethodsNoPost, Migration/AddColumnsToWideTables + + install_rename_triggers :ci_project_monthly_usages, :amount_used, :new_amount_used, trigger_name: TRIGGER_NAME + end +end diff --git a/db/schema_migrations/20221221171239 b/db/schema_migrations/20221221171239 new file mode 100644 index 00000000000..41e529467fe --- /dev/null +++ b/db/schema_migrations/20221221171239 @@ -0,0 +1 @@ +58a1e0ebf310f443b268491b5fa5e88ed392390aa028bed57c0292b270a3ec2d
\ No newline at end of file diff --git a/db/schema_migrations/20221222092958 b/db/schema_migrations/20221222092958 new file mode 100644 index 00000000000..eabf9eedc5f --- /dev/null +++ b/db/schema_migrations/20221222092958 @@ -0,0 +1 @@ +689029c5d5ec374f12827d47602096d7bdaab0c1a6c378f45382cd612d3ba002
\ No newline at end of file diff --git a/db/schema_migrations/20230104103748 b/db/schema_migrations/20230104103748 new file mode 100644 index 00000000000..e948ea381c4 --- /dev/null +++ b/db/schema_migrations/20230104103748 @@ -0,0 +1 @@ +7e6fb82580d45777ca0e656c589dc0eed5a7d090fc38096b395a10967acd08f4
\ No newline at end of file diff --git a/db/schema_migrations/20230111092510 b/db/schema_migrations/20230111092510 new file mode 100644 index 00000000000..b84ab421d2d --- /dev/null +++ b/db/schema_migrations/20230111092510 @@ -0,0 +1 @@ +d80ba166cee17bce1ac7825d9acdc9eeaf78aca5df276cfe2c3b2b076112dd1e
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index b4a9509ea5b..bb71082d93a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -234,15 +234,6 @@ BEGIN END; $$; -CREATE FUNCTION sync_projects_amount_used_columns() RETURNS trigger - LANGUAGE plpgsql - AS $$ -BEGIN - NEW."new_amount_used" := NEW."amount_used"; - RETURN NEW; -END; -$$; - CREATE FUNCTION trigger_1a857e8db6cd() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -12462,6 +12453,7 @@ CREATE TABLE bulk_import_entities ( created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, source_xid integer, + migrate_projects boolean DEFAULT true NOT NULL, CONSTRAINT check_13f279f7da CHECK ((char_length(source_full_path) <= 255)), CONSTRAINT check_715d725ea2 CHECK ((char_length(destination_name) <= 255)), CONSTRAINT check_796a4d9cc6 CHECK ((char_length(jid) <= 255)), @@ -13343,10 +13335,9 @@ CREATE TABLE ci_project_monthly_usages ( id bigint NOT NULL, project_id bigint NOT NULL, date date NOT NULL, - amount_used numeric(18,2) DEFAULT 0.0 NOT NULL, shared_runners_duration integer DEFAULT 0 NOT NULL, created_at timestamp with time zone, - new_amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, + amount_used numeric(18,4) DEFAULT 0.0 NOT NULL, CONSTRAINT ci_project_monthly_usages_year_month_constraint CHECK ((date = date_trunc('month'::text, (date)::timestamp with time zone))) ); @@ -33129,8 +33120,6 @@ CREATE TRIGGER projects_loose_fk_trigger AFTER DELETE ON projects REFERENCING OL CREATE TRIGGER sync_namespaces_amount_used_columns BEFORE INSERT OR UPDATE ON ci_namespace_monthly_usages FOR EACH ROW EXECUTE FUNCTION sync_namespaces_amount_used_columns(); -CREATE TRIGGER sync_projects_amount_used_columns BEFORE INSERT OR UPDATE ON ci_project_monthly_usages FOR EACH ROW EXECUTE FUNCTION sync_projects_amount_used_columns(); - CREATE TRIGGER trigger_1a857e8db6cd BEFORE INSERT OR UPDATE ON vulnerability_occurrences FOR EACH ROW EXECUTE FUNCTION trigger_1a857e8db6cd(); CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace(); diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 0718ae93915..b768bab3180 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -3289,7 +3289,9 @@ Use `retry:when` with `retry:max` to retry jobs for only specific failure cases. - `always`: Retry on any failure (default). - `unknown_failure`: Retry when the failure reason is unknown. -- `script_failure`: Retry when the script failed. +- `script_failure`: Retry when: + - The script failed. + - The runner failed to pull the Docker image. For `docker`, `docker+machine`, `kubernetes` [executors](https://docs.gitlab.com/runner/executors/). - `api_failure`: Retry on API failure. - `stuck_or_timeout_failure`: Retry when the job got stuck or timed out. - `runner_system_failure`: Retry if there is a runner system failure (for example, job setup failed). diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index c7bdbbbea31..f774f5bd0cc 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -186,6 +186,10 @@ Instead, use **assign**. For example: - Assign the issue to an epic. - Assign a user to the issue. +## authenticated user + +Use **authenticated user** instead of other variations, like **signed in user** or **logged in user**. + ## below Try to avoid **below** when referring to an example or table in a documentation page. If required, use **following** instead. For example: @@ -691,6 +695,10 @@ Do not use **limitations**. Use **known issues** instead. Do not use **log in** or **log on**. Use [sign in](#sign-in) instead. If the user interface has **Log in**, you can use it. +## logged-in user, logged in user + +Use **authenticated user** instead of **logged-in user** or **logged in user**. + ## lower Do not use **lower** when talking about version numbers. @@ -1075,6 +1083,10 @@ You can use **single sign-on**. Use **register** instead of **sign up** when talking about creating an account. +## signed-in user, signed in user + +Use **authenticated user** instead of **signed-in user** or **signed in user**. + ## simply, simple Do not use **simply** or **simple**. If the user doesn't find the process to be simple, we lose their trust. ([Vale](../testing.md#vale) rule: [`Simplicity.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Simplicity.yml)) diff --git a/doc/integration/jira/dvcs.md b/doc/integration/jira/dvcs.md index 7f431de1323..1300eb21ced 100644 --- a/doc/integration/jira/dvcs.md +++ b/doc/integration/jira/dvcs.md @@ -284,3 +284,15 @@ To resolve the issue, enable the relevant feature: 1. On the left sidebar, select **Settings > General**. 1. Expand **Visibility, project features, permissions**. 1. Use the toggles to enable the features as needed. + +### Find webhook logs in a DVCS-linked project + +To find webhook logs in a DVCS-linked project: + +1. On the top bar, select **Main menu > Projects** and find your project. +1. On the left sidebar, select **Settings > Webhooks**. +1. Scroll down to **Project Hooks**. +1. Next to the log that points to your Jira instance, select **Edit**. +1. Scroll down to **Recent events**. + +If you can't find webhook logs in your project, check your DVCS setup for problems. diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md index 43769410eba..fbc01bee6f1 100644 --- a/doc/topics/autodevops/customize.md +++ b/doc/topics/autodevops/customize.md @@ -12,6 +12,30 @@ You can customize components of Auto DevOps to fit your needs. For example, you - Enable staging and canary deployments with a custom [CI/CD configuration](#customize-gitlab-ciyml). - Extend Auto DevOps with the [GitLab API](#extend-auto-devops-with-the-api). +## Auto DevOps banner + +When Auto DevOps is not enabled, a banner displays for users with at +least the Maintainer role: + +![Auto DevOps banner](img/autodevops_banner_v12_6.png) + +The banner can be disabled for: + +- A user, when they dismiss it themselves. +- A project, by explicitly [disabling Auto DevOps](index.md#enable-or-disable-auto-devops). +- An entire GitLab instance: + - By an administrator running the following in a Rails console: + + ```ruby + Feature.enable(:auto_devops_banner_disabled) + ``` + + - Through the REST API with an administrator access token: + + ```shell + curl --data "value=true" --header "PRIVATE-TOKEN: <personal_access_token>" "https://gitlab.example.com/api/v4/features/auto_devops_banner_disabled" + ``` + ## Custom buildpacks You can customize your buildpacks when either: @@ -58,7 +82,7 @@ To use only a single custom buildpack, you should provide the project CI/CD vari ## Custom Dockerfiles -> Support for `DOCKERFILE_PATH` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35662) in GitLab 13.2 +> `DOCKERFILE_PATH` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35662) in GitLab 13.2. If you have a Dockerfile in the root of your project repository, Auto DevOps builds a Docker image based on the Dockerfile. This can be @@ -198,7 +222,7 @@ To override settings like `replicaCount`, use the `REPLICAS` [build and deployme ### Customize `helm upgrade` -The `helm upgrade` command is used by the [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image). +The [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) uses the `helm upgrade` command. To customize this command, pass it options with the `HELM_UPGRADE_EXTRA_ARGS` CI/CD variable. For example, to disable pre- and post-upgrade hooks when `helm upgrade` runs: @@ -239,28 +263,14 @@ To remove behaviors from the Auto DevOps pipeline: into your project. 1. Edit your copy of the template as needed. -## Use multiple Kubernetes clusters - -See [Multiple Kubernetes clusters for Auto DevOps](multiple_clusters_auto_devops.md). - -## Customizing the Kubernetes namespace - -In GitLab 14.5 and earlier, you could use `environment:kubernetes:namespace` -to specify a namespace for the environment. -However, this feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8), -along with certificate-based integration. - -You should now use the `KUBE_NAMESPACE` environment variable and -[limit its environment scope](../../ci/environments/index.md#scope-environments-with-specs). - -## Use individual components of Auto DevOps +### Use individual components of Auto DevOps If you only require a subset of the features offered by Auto DevOps, you can include individual Auto DevOps jobs in your own `.gitlab-ci.yml`. Be sure to also define the stage required by each job in your `.gitlab-ci.yml` file. -For example, to make use of [Auto Build](stages.md#auto-build), you can add the following to +For example, to use [Auto Build](stages.md#auto-build), you can add the following to your `.gitlab-ci.yml`: ```yaml @@ -278,12 +288,26 @@ From [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/213336), Auto DevOps templates that use the [`only`](../../ci/yaml/index.md#only--except) or [`except`](../../ci/yaml/index.md#only--except) syntax have switched to the [`rules`](../../ci/yaml/index.md#rules) syntax. -If your `.gitlab-ci.yml` extends these Auto DevOps templates and overrides the `only` or -`except` keywords, you must migrate your templates to use the +If your `.gitlab-ci.yml` extends these Auto DevOps templates and overrides `only` or +`except`, migrate your templates to the [`rules`](../../ci/yaml/index.md#rules) syntax. -If you cannot migrate just yet, you can alternatively pin your templates to +If you cannot migrate, you can pin your templates to the [GitLab 12.10 based templates](https://gitlab.com/gitlab-org/auto-devops-v12-10). +## Use multiple Kubernetes clusters + +See [Multiple Kubernetes clusters for Auto DevOps](multiple_clusters_auto_devops.md). + +## Customizing the Kubernetes namespace + +In GitLab 14.5 and earlier, you could use `environment:kubernetes:namespace` +to specify a namespace for the environment. +However, this feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8), +along with certificate-based integration. + +You should now use the `KUBE_NAMESPACE` environment variable and +[limit its environment scope](../../ci/environments/index.md#scope-environments-with-specs). + ## Use images hosted in a local Docker registry You can configure many Auto DevOps jobs to run in an [offline environment](../../user/application_security/offline_deployments/index.md): @@ -307,10 +331,13 @@ You can configure many Auto DevOps jobs to run in an [offline environment](../.. ## PostgreSQL database support -To support applications requiring a database, -[PostgreSQL](https://www.postgresql.org/) is provisioned by default. The credentials to access -the database are preconfigured, but can be customized by setting the associated -[CI/CD variables](cicd_variables.md). You can use these credentials to define a `DATABASE_URL`: +To support applications that require a database, +[PostgreSQL](https://www.postgresql.org/) is provisioned by default. +The credentials to access the database are preconfigured. + +To customize the credentials, set the associated +[CI/CD variables](cicd_variables.md). You can also +define a custom `DATABASE_URL`: ```yaml postgres://user:password@postgres-host:postgres-port/postgres-database @@ -318,23 +345,20 @@ postgres://user:password@postgres-host:postgres-port/postgres-database ### Upgrading PostgreSQL -The version of the chart used to provision PostgreSQL: - -- Is 8.2.1 in GitLab 13.0 and later, but can be set back to 0.7.1 if needed. -- Can be set to from 0.7.1 to 8.2.1 in GitLab 12.9 and 12.10. -- Is 0.7.1 in GitLab 12.8 and earlier. +GitLab uses chart version 8.2.1 to provision PostgreSQL by default. +You can set the version from 0.7.1 to 8.2.1. -GitLab encourages users to [migrate their database](upgrading_postgresql.md) +If you use an older chart version, you should [migrate your database](upgrading_postgresql.md) to the newer PostgreSQL. The CI/CD variable `AUTO_DEVOPS_POSTGRES_CHANNEL` that controls default provisioned -PostgreSQL was changed to `2` in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/210499). +PostgreSQL changed to `2` in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/210499). To use the old PostgreSQL, set the `AUTO_DEVOPS_POSTGRES_CHANNEL` variable to `1`. ### Customize values for PostgreSQL Helm Chart -> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/issues/113) in auto-deploy-image v2, in GitLab 13.8. +> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/issues/113) in GitLab 13.8 with auto-deploy-image v2. To set custom values, do one of the following: @@ -347,9 +371,9 @@ To set custom values, do one of the following: ### Use external PostgreSQL database providers -Auto DevOps provides out-of-the-box support for a PostgreSQL container for -production environments. However, you might want to use an external managed provider (such as -AWS Relational Database Service) for PostgreSQL. +Auto DevOps provides out-of-the-box support for a PostgreSQL container +for production environments. However, you might want to use an +external managed provider like AWS Relational Database Service. To use an external managed provider: @@ -368,27 +392,3 @@ To use an external managed provider: ``` 1. Ensure your Kubernetes cluster has network access to where PostgreSQL is hosted. - -## Auto DevOps banner - -The following Auto DevOps banner displays for users with Maintainer or greater -permissions on new projects when Auto DevOps is not enabled: - -![Auto DevOps banner](img/autodevops_banner_v12_6.png) - -The banner can be disabled for: - -- A user, when they dismiss it themselves. -- A project, by explicitly [disabling Auto DevOps](index.md#enable-or-disable-auto-devops). -- An entire GitLab instance: - - By an administrator running the following in a Rails console: - - ```ruby - Feature.enable(:auto_devops_banner_disabled) - ``` - - - Through the REST API with an administrator access token: - - ```shell - curl --data "value=true" --header "PRIVATE-TOKEN: <personal_access_token>" "https://gitlab.example.com/api/v4/features/auto_devops_banner_disabled" - ``` diff --git a/doc/user/namespace/index.md b/doc/user/namespace/index.md index bc7ec25b19c..7463b8f1099 100644 --- a/doc/user/namespace/index.md +++ b/doc/user/namespace/index.md @@ -35,3 +35,10 @@ To determine whether you're viewing a group or personal namespace, you can view | A user named `alex`. | `https://gitlab.example.com/alex` | `alex` | | A group named `alex-team`. | `https://gitlab.example.com/alex-team` | `alex-team` | | A group named `alex-team` with a subgroup named `marketing`. | `https://gitlab.example.com/alex-team/marketing` | `alex-team/marketing` | + +## Naming limitations for namespaces + +When choosing a name for your namespace, keep in mind the [character limitations](../reserved_names.md#limitations-on-project-and-group-names) and [reserved group names](../reserved_names.md#reserved-group-names). + +NOTE: +If your namespace contains a `.`, you will encounter issues with the validation of your SSL certificates and the source path when [publishing Terraform modules](../packages/terraform_module_registry/index.md#publish-a-terraform-module). diff --git a/doc/user/workspace/index.md b/doc/user/workspace/index.md index 3806c78589a..e4e1edd6346 100644 --- a/doc/user/workspace/index.md +++ b/doc/user/workspace/index.md @@ -4,7 +4,7 @@ group: Organization info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Workspace +# Organization DISCLAIMER: This page contains information related to upcoming products, features, and functionality. @@ -15,9 +15,9 @@ The development, release, and timing of any products, features, or functionality sole discretion of GitLab Inc. NOTE: -Workspace is in development. +Organization is in development. -Workspace will be above the [top-level namespaces](../namespace/index.md) for you to manage +Organization will be above the [top-level namespaces](../namespace/index.md) for you to manage everything you do as a GitLab administrator, including: - Defining and applying settings to all of your groups, subgroups, and projects. @@ -26,11 +26,11 @@ everything you do as a GitLab administrator, including: Our goal is to reach feature parity between SaaS and self-managed installations, with all [Admin Area settings](/ee/user/admin_area/settings/index.md) moving to either: -- Groups. Available in the Workspace, top-level groups, and subgroups. +- Groups. Available in the Organization, and subgroups. - Hardware Controls. For functionality that does not apply to groups, Hardware Controls are only applicable to self-managed installations. There is one Hardware Controls section per installation. -For more information about the state of workspace development, +For more information about the state of organization development, see [epic 9265](https://gitlab.com/groups/gitlab-org/-/epics/9265). <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> @@ -39,4 +39,4 @@ For a video introduction to the new hierarchy concept for groups and projects fo ## Related topics -- [Workspace developer documentation](../../development/workspace/index.md) +- [Organization developer documentation](../../development/workspace/index.md) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3a34cc3a341..9c0f5505c8c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -14399,6 +14399,9 @@ msgstr "" msgid "DevopsAdoption|You cannot remove the group you are currently in." msgstr "" +msgid "DevopsMetricsDashboard|%{strongStart}Beta feature:%{strongEnd} Leave your thoughts in the %{linkStart}feedback issue%{linkEnd}." +msgstr "" + msgid "DevopsReport|DevOps Score" msgstr "" @@ -31834,6 +31837,9 @@ msgstr "" msgid "Product Analytics|Analyze your product with Product Analytics" msgstr "" +msgid "Product Analytics|Creating your product analytics instance..." +msgstr "" + msgid "Product Analytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project." msgstr "" @@ -31855,7 +31861,7 @@ msgstr "" msgid "Product Analytics|Set up Product Analytics to track how your product is performing. Combine it with your GitLab data to better understand where you can improve your product and development processes." msgstr "" -msgid "Product Analytics|Set up product analytics..." +msgid "Product Analytics|Set up product analytics" msgstr "" msgid "Product Analytics|Steps to add product analytics as a CommonJS module" @@ -31870,6 +31876,9 @@ msgstr "" msgid "Product Analytics|The host to send all tracking events to" msgstr "" +msgid "Product Analytics|This might take a while, feel free to navigate away from this page and come back later." +msgstr "" + msgid "Product Analytics|To instrument your application, select one of the options below. After an option has been instrumented and data is being collected, this page will progress to the next step." msgstr "" diff --git a/rubocop/rubocop-migrations.yml b/rubocop/rubocop-migrations.yml index ccde12bca77..36ef17ad6a3 100644 --- a/rubocop/rubocop-migrations.yml +++ b/rubocop/rubocop-migrations.yml @@ -12,10 +12,14 @@ Migration/UpdateLargeTable: - :ci_builds_metadata - :ci_build_trace_metadata - :ci_job_artifacts - - :ci_pipeline_messages + - :ci_job_artifact_states + - :ci_job_variables + - :ci_namespace_mirrors - :ci_pipelines - :ci_pipelines_config + - :ci_pipeline_messages - :ci_pipeline_variables + - :ci_refs - :ci_stages - :deployments - :description_versions diff --git a/spec/frontend/boards/board_list_helper.js b/spec/frontend/boards/board_list_helper.js index af5509fd2e9..1ba546f24a8 100644 --- a/spec/frontend/boards/board_list_helper.js +++ b/spec/frontend/boards/board_list_helper.js @@ -86,7 +86,6 @@ export default function createComponent({ apolloProvider: fakeApollo, store, propsData: { - disabled: false, list, boardItems: [issue], canAdminList: true, @@ -104,6 +103,7 @@ export default function createComponent({ isEpicBoard: false, isGroupBoard: false, isProjectBoard: true, + disabled: false, ...provide, }, stubs, diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js index 34c0504143c..abe8c230bd8 100644 --- a/spec/frontend/boards/board_list_spec.js +++ b/spec/frontend/boards/board_list_spec.js @@ -267,7 +267,7 @@ describe('Board list component', () => { describe('when dragging is not allowed', () => { beforeEach(() => { wrapper = createComponent({ - componentProps: { + provide: { disabled: true, }, }); diff --git a/spec/frontend/boards/components/board_app_spec.js b/spec/frontend/boards/components/board_app_spec.js index c209f2f82e6..872a67a71fb 100644 --- a/spec/frontend/boards/components/board_app_spec.js +++ b/spec/frontend/boards/components/board_app_spec.js @@ -23,11 +23,10 @@ describe('BoardApp', () => { }); }; - const createComponent = ({ provide = { disabled: true } } = {}) => { + const createComponent = () => { wrapper = shallowMount(BoardApp, { store, provide: { - ...provide, fullBoardId: 'gid://gitlab/Board/1', }, }); diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js index cd3882dc9ee..f8ad7c468c1 100644 --- a/spec/frontend/boards/components/board_card_spec.js +++ b/spec/frontend/boards/components/board_card_spec.js @@ -49,7 +49,6 @@ describe('Board card', () => { propsData: { list: mockLabelList, item, - disabled: false, index: 0, ...propsData, }, @@ -61,6 +60,7 @@ describe('Board card', () => { issuableType: 'issue', isProjectBoard: false, isGroupBoard: true, + disabled: false, ...provide, }, }); diff --git a/spec/frontend/boards/components/board_column_spec.js b/spec/frontend/boards/components/board_column_spec.js index c13f7caba76..d34e228a2d7 100644 --- a/spec/frontend/boards/components/board_column_spec.js +++ b/spec/frontend/boards/components/board_column_spec.js @@ -34,7 +34,6 @@ describe('Board Column Component', () => { wrapper = shallowMount(BoardColumn, { store, propsData: { - disabled: false, list: listMock, }, }); diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js index 98f66ed804a..97596c86198 100644 --- a/spec/frontend/boards/components/board_content_spec.js +++ b/spec/frontend/boards/components/board_content_spec.js @@ -60,7 +60,6 @@ describe('BoardContent', () => { wrapper = shallowMount(BoardContent, { apolloProvider: fakeApollo, propsData: { - disabled: false, boardId: 'gid://gitlab/Board/1', ...props, }, @@ -72,6 +71,7 @@ describe('BoardContent', () => { isIssueBoard, isEpicBoard, isGroupBoard: true, + disabled: false, isApolloBoard, }, store, diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js index 4633612891c..a16b99728c3 100644 --- a/spec/frontend/boards/components/board_list_header_spec.js +++ b/spec/frontend/boards/components/board_list_header_spec.js @@ -68,7 +68,6 @@ describe('Board List Header Component', () => { apolloProvider: fakeApollo, store, propsData: { - disabled: false, list: listMock, }, provide: { @@ -76,6 +75,7 @@ describe('Board List Header Component', () => { weightFeatureAvailable: false, currentUserId, isEpicBoard: false, + disabled: false, }, }), ); diff --git a/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js b/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js index 368d5017056..896e9356b7d 100644 --- a/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js +++ b/spec/frontend/issues/related_merge_requests/components/related_merge_requests_spec.js @@ -51,7 +51,9 @@ describe('RelatedMergeRequests', () => { }); }); - it('should return an array with single assingee', () => { + // https://gitlab.com/gitlab-org/gitlab/-/issues/387789 + // eslint-disable-next-line jest/no-disabled-tests + it.skip('should return an array with single assingee', () => { const mr = { assignee: assignees[0] }; expect(wrapper.vm.getAssignees(mr)).toEqual([assignees[0]]); diff --git a/spec/migrations/20221222092958_sync_new_amount_used_with_amount_used_spec.rb b/spec/migrations/20221222092958_sync_new_amount_used_with_amount_used_spec.rb new file mode 100644 index 00000000000..158560a2432 --- /dev/null +++ b/spec/migrations/20221222092958_sync_new_amount_used_with_amount_used_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SyncNewAmountUsedWithAmountUsed, migration: :gitlab_ci, feature_category: :continuous_integration do + let(:project_usages) { table(:ci_project_monthly_usages) } + let(:migration) { described_class.new } + + before do + # Disabling the trigger temporarily to allow records being created with out-of-sync + # `new_amount_used` and `amount_used`. This will simulate existing records before + # we add the trigger. + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages DISABLE TRIGGER sync_projects_amount_used_columns") + + this_month = Time.now.utc.beginning_of_month + last_month = 1.month.ago.utc.beginning_of_month + last_year = 1.year.ago.utc.beginning_of_month + + project_usages.create!(project_id: 1, date: last_year) + project_usages.create!(project_id: 1, date: this_month, amount_used: 10, new_amount_used: 0) + project_usages.create!(project_id: 1, date: last_month, amount_used: 20, new_amount_used: 0) + + project_usages.create!(project_id: 2, date: last_year) + project_usages.create!(project_id: 2, date: this_month, amount_used: 30, new_amount_used: 0) + project_usages.create!(project_id: 2, date: last_month, amount_used: 40, new_amount_used: 0) + + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages ENABLE TRIGGER sync_projects_amount_used_columns") + end + + describe '#up' do + it "doesnt change new_amount_used values" do + data = project_usages.all + data.each do |item| + expect { migration.up }.to not_change { item.new_amount_used } + end + end + end + + describe '#down' do + it 'updates `new_amount_used` with values from `amount_used`' do + expect(project_usages.where(new_amount_used: 0).count).to eq(6) + + migration.down + + expect(project_usages.where(new_amount_used: 0).count).to eq(2) + expect(project_usages.order(:id).pluck(:new_amount_used)) + .to contain_exactly(0, 0, 10, 20, 30, 40) + end + end +end diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb index ba1a29a8b27..e5232026c39 100644 --- a/spec/models/project_import_state_spec.rb +++ b/spec/models/project_import_state_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ProjectImportState, type: :model do +RSpec.describe ProjectImportState, type: :model, feature_category: :importers do let_it_be(:correlation_id) { 'cid' } let_it_be(:import_state, refind: true) { create(:import_state, correlation_id_value: correlation_id) } @@ -17,22 +17,19 @@ RSpec.describe ProjectImportState, type: :model do end describe 'Project import job' do - let_it_be(:import_state) { create(:import_state, import_url: generate(:url)) } - let_it_be(:project) { import_state.project } + let_it_be(:project) { create(:project) } - before do - allow_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository) - .with(project.import_url, http_authorization_header: '', mirror: false, resolved_address: '').and_return(true) + let(:import_state) { create(:import_state, import_url: generate(:url), project: project) } + let(:jid) { '551d3ceac5f67a116719ce41' } + before do # Works around https://github.com/rspec/rspec-mocks/issues/910 allow(Project).to receive(:find).with(project.id).and_return(project) - expect(project).to receive(:after_import).and_call_original + allow(project).to receive(:add_import_job).and_return(jid) end it 'imports a project', :sidekiq_might_not_need_inline do - expect(RepositoryImportWorker).to receive(:perform_async).and_call_original - - expect { import_state.schedule }.to change { import_state.status }.from('none').to('finished') + expect { import_state.schedule }.to change { import_state.status }.from('none').to('scheduled') end it 'records job and correlation IDs', :sidekiq_might_not_need_inline do @@ -40,7 +37,8 @@ RSpec.describe ProjectImportState, type: :model do import_state.schedule - expect(import_state.jid).to be_an_instance_of(String) + expect(project).to have_received(:add_import_job) + expect(import_state.jid).to eq(jid) expect(import_state.correlation_id).to eq(correlation_id) end end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 353af5a594a..344d93fc5ca 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -479,6 +479,16 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re end end + shared_examples_for "creates a new pipeline" do + it "creates a new pipeline" do + expect(MergeRequests::CreatePipelineWorker) + .to receive(:perform_async) + .with(project.id, user.id, merge_request.id, { "allow_duplicate" => true }) + + update_merge_request(target_branch: new_target_branch) + end + end + shared_examples_for 'correct merge behavior' do let(:opts) do { @@ -799,6 +809,10 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re update_merge_request({ target_branch: "target" }) end + + it_behaves_like "creates a new pipeline" do + let(:new_target_branch) { "target" } + end end context 'when auto merge is enabled and target branch changed' do @@ -813,6 +827,10 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re update_merge_request({ target_branch: 'target' }) end + + it_behaves_like "creates a new pipeline" do + let(:new_target_branch) { "target" } + end end end @@ -1237,6 +1255,10 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re expect { update_merge_request(target_branch: 'master', target_branch_was_deleted: true) } .to change { merge_request.reload.target_branch }.from('mr-a').to('master') end + + it_behaves_like "creates a new pipeline" do + let(:new_target_branch) { "target" } + end end it_behaves_like 'issuable record that supports quick actions' do diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb index 1dc77fbf83f..ca7c13fe24e 100644 --- a/spec/workers/repository_import_worker_spec.rb +++ b/spec/workers/repository_import_worker_spec.rb @@ -2,92 +2,88 @@ require 'spec_helper' -RSpec.describe RepositoryImportWorker do +RSpec.describe RepositoryImportWorker, feature_category: :importers do describe '#perform' do - let(:project) { create(:project, :import_scheduled) } - let(:import_state) { project.import_state } - - context 'when worker was reset without cleanup' do - it 'imports the project successfully' do - jid = '12345678' - started_project = create(:project) - started_import_state = create(:import_state, :started, project: started_project, jid: jid) - - allow(subject).to receive(:jid).and_return(jid) + let(:project) { build_stubbed(:project, :import_scheduled, import_state: import_state, import_url: 'url') } + let(:import_state) { create(:import_state, status: :scheduled) } + let(:jid) { '12345678' } + + before do + allow(subject).to receive(:jid).and_return(jid) + allow(Project).to receive(:find_by_id).with(project.id).and_return(project) + allow(project).to receive(:after_import) + allow(import_state).to receive(:start).and_return(true) + end - expect_next_instance_of(Projects::ImportService) do |instance| - expect(instance).to receive(:execute).and_return({ status: :ok }) - end + context 'when project not found (deleted)' do + before do + allow(Project).to receive(:find_by_id).with(project.id).and_return(nil) + end - # Works around https://github.com/rspec/rspec-mocks/issues/910 - expect(Project).to receive(:find).with(started_project.id).and_return(started_project) - expect(started_project.repository).to receive(:expire_emptiness_caches) - expect(started_project.wiki.repository).to receive(:expire_emptiness_caches) - expect(started_import_state).to receive(:finish) + it 'does not raise any exception' do + expect(Projects::ImportService).not_to receive(:new) - subject.perform(started_project.id) + expect { subject.perform(project.id) }.not_to raise_error end end - context 'when the import was successful' do - it 'imports a project' do + context 'when import_state is scheduled' do + it 'imports the project successfully' do expect_next_instance_of(Projects::ImportService) do |instance| expect(instance).to receive(:execute).and_return({ status: :ok }) end - # Works around https://github.com/rspec/rspec-mocks/issues/910 - expect(Project).to receive(:find).with(project.id).and_return(project) - expect(project.repository).to receive(:expire_emptiness_caches) - expect(project.wiki.repository).to receive(:expire_emptiness_caches) - expect(import_state).to receive(:finish) - subject.perform(project.id) + + expect(project).to have_received(:after_import) + expect(import_state).to have_received(:start) end end - context 'when the import has failed' do - it 'updates the error on Import/Export & hides credentials from import URL' do - import_url = 'https://user:pass@test.com/root/repoC.git/' - error = "#{import_url} not found" - - import_state.update!(jid: '123') - project.update!(import_type: 'gitlab_project') + context 'when worker was reset without cleanup (import_state is started)' do + let(:import_state) { create(:import_state, :started, jid: jid) } + it 'imports the project successfully' do expect_next_instance_of(Projects::ImportService) do |instance| - expect(instance).to receive(:track_start_import).and_raise(StandardError, error) + expect(instance).to receive(:execute).and_return({ status: :ok }) end - expect { subject.perform(project.id) }.not_to raise_error + subject.perform(project.id) - import_state.reload - expect(import_state.jid).to eq('123') - expect(import_state.status).to eq('failed') - expect(import_state.last_error).to include("[FILTERED] not found") - expect(import_state.last_error).not_to include(import_url) + expect(project).to have_received(:after_import) + expect(import_state).not_to have_received(:start) end end context 'when using an asynchronous importer' do it 'does not mark the import process as finished' do - service = double(:service) + expect_next_instance_of(Projects::ImportService) do |instance| + expect(instance).to receive(:execute).and_return({ status: :ok }) + expect(instance).to receive(:async?).and_return(true) + end + + subject.perform(project.id) - allow(Projects::ImportService) - .to receive(:new) - .and_return(service) + expect(project).not_to have_received(:after_import) + end + end - allow(service) - .to receive(:execute) - .and_return(true) + context 'when the import has failed' do + let(:error) { "https://user:pass@test.com/root/repoC.git/ not found" } - allow(service) - .to receive(:async?) - .and_return(true) + before do + allow(import_state).to receive(:mark_as_failed) + end - expect_next_instance_of(ProjectImportState) do |instance| - expect(instance).not_to receive(:finish) + it 'marks import_state as failed' do + expect_next_instance_of(Projects::ImportService) do |instance| + expect(instance).to receive(:execute).and_return({ status: :error, message: error }) end subject.perform(project.id) + + expect(import_state).to have_received(:mark_as_failed).with(error) + expect(project).not_to have_received(:after_import) end end end |