diff --git a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue index fc17669a737..492e68b636f 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue @@ -40,9 +40,9 @@ export default { }, message() { return this.isFastForwardEnabled - ? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.') + ? s__('mrWidgetCommitsAdded|Adds %{commitCount} to %{targetBranch}.') : s__( - 'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}.', + 'mrWidgetCommitsAdded|Adds %{commitCount} and %{mergeCommitCount} to %{targetBranch}%{squashedCommits}.', ); }, textDecorativeComponent() { @@ -69,7 +69,7 @@ export default { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue index 9268e426954..caafd6b995e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue @@ -4,7 +4,7 @@ import { __ } from '../../locale'; export default { i18n: { - removesBranchText: __('The source branch will be deleted'), + removesBranchText: __('Deletes the source branch'), tooltipTitle: __('A user with write access to the source branch selected this option'), }, components: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue index 0eb173edbcb..a44caf886a4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue @@ -177,10 +177,10 @@ export default {

- {{ s__('mrWidget|The source branch will be deleted') }} + {{ s__('mrWidget|Deletes the source branch') }}

- {{ s__('mrWidget|The source branch will not be deleted') }} + {{ s__('mrWidget|Does not delete the source branch') }}

- {{ s__('mrWidget|The changes will be merged into') }} + {{ s__('mrWidget|Merges changes into') }} {{ mr.targetBranch }} diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index 3ca0c387478..aca838ce099 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -710,10 +710,10 @@ export default {

  • diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 2103a37180f..b8ee71daeee 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -404,6 +404,10 @@ module ApplicationSettingsHelper :keep_latest_artifact, :whats_new_variant, :user_deactivation_emails_enabled, + :sentry_enabled, + :sentry_dsn, + :sentry_clientside_dsn, + :sentry_environment, :sidekiq_job_limiter_mode, :sidekiq_job_limiter_compression_threshold_bytes, :sidekiq_job_limiter_limit_bytes, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 5a8cbd8d71c..af5796d682f 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -536,6 +536,18 @@ class ApplicationSetting < ApplicationRecord validates :sidekiq_job_limiter_limit_bytes, numericality: { only_integer: true, greater_than_or_equal_to: 0 } + validates :sentry_enabled, + inclusion: { in: [true, false], message: _('must be a boolean value') } + validates :sentry_dsn, + addressable_url: true, presence: true, length: { maximum: 255 }, + if: :sentry_enabled? + validates :sentry_clientside_dsn, + addressable_url: true, allow_blank: true, length: { maximum: 255 }, + if: :sentry_enabled? + validates :sentry_environment, + presence: true, length: { maximum: 255 }, + if: :sentry_enabled? + attr_encrypted :asset_proxy_secret_key, mode: :per_attribute_iv, key: Settings.attr_encrypted_db_key_base_truncated, diff --git a/app/views/admin/application_settings/_sentry.html.haml b/app/views/admin/application_settings/_sentry.html.haml new file mode 100644 index 00000000000..5fd373d59e9 --- /dev/null +++ b/app/views/admin/application_settings/_sentry.html.haml @@ -0,0 +1,22 @@ += form_for @application_setting, url: metrics_and_profiling_admin_application_settings_path(anchor: 'js-sentry-settings'), html: { class: 'fieldset-form', id: 'sentry-settings' } do |f| + = form_errors(@application_setting) + + %span.text-muted + = _('Changing any setting here requires an application restart') + + %fieldset + .form-group + .form-check + = f.check_box :sentry_enabled, class: 'form-check-input' + = f.label :sentry_enabled, _('Enable Sentry error tracking'), class: 'form-check-label' + .form-group + = f.label :sentry_dsn, _('DSN'), class: 'label-light' + = f.text_field :sentry_dsn, class: 'form-control gl-form-input', placeholder: 'https://public@sentry.example.com/1' + .form-group + = f.label :sentry_clientside_dsn, _('Clientside DSN'), class: 'label-light' + = f.text_field :sentry_clientside_dsn, class: 'form-control gl-form-input', placeholder: 'https://public@sentry.example.com/2' + .form-group + = f.label :sentry_environment, _('Environment'), class: 'label-light' + = f.text_field :sentry_environment, class: 'form-control gl-form-input', placeholder: Rails.env + + = f.submit _('Save changes'), class: 'gl-button btn btn-confirm' diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml index 6087551d7c7..eba50b93bfe 100644 --- a/app/views/admin/application_settings/metrics_and_profiling.html.haml +++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml @@ -54,3 +54,15 @@ = render 'usage' = render_if_exists 'admin/application_settings/pseudonymizer_settings', expanded: expanded_by_default? + +- if Feature.enabled?(:configure_sentry_in_application_settings, default_enabled: :yaml) + %section.settings.as-sentry.no-animate#js-sentry-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'sentry_settings_content' } } + .settings-header + %h4 + = _('Sentry') + %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' } + = expanded_by_default? ? _('Collapse') : _('Expand') + %p + = _('Configure Sentry integration for error tracking') + .settings-content + = render 'sentry' diff --git a/bin/sidekiq-cluster b/bin/sidekiq-cluster index 47f8e82d228..db7833acdc9 100755 --- a/bin/sidekiq-cluster +++ b/bin/sidekiq-cluster @@ -1,13 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'optparse' -require_relative '../lib/gitlab' -require_relative '../lib/gitlab/utils' -require_relative '../lib/gitlab/sidekiq_config/cli_methods' -require_relative '../lib/gitlab/sidekiq_config/worker_matcher' -require_relative '../lib/gitlab/sidekiq_cluster' -require_relative '../lib/gitlab/sidekiq_cluster/cli' +require_relative '../sidekiq_cluster/cli' Thread.abort_on_exception = true diff --git a/config/feature_flags/development/configure_sentry_in_application_settings.yml b/config/feature_flags/development/configure_sentry_in_application_settings.yml new file mode 100644 index 00000000000..82b2261994b --- /dev/null +++ b/config/feature_flags/development/configure_sentry_in_application_settings.yml @@ -0,0 +1,8 @@ +--- +name: configure_sentry_in_application_settings +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73381 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344832 +milestone: '14.5' +type: development +group: group::pipeline execution +default_enabled: false diff --git a/db/migrate/20211021125908_add_sentry_settings_to_application_settings.rb b/db/migrate/20211021125908_add_sentry_settings_to_application_settings.rb new file mode 100644 index 00000000000..d8b40893b47 --- /dev/null +++ b/db/migrate/20211021125908_add_sentry_settings_to_application_settings.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class AddSentrySettingsToApplicationSettings < Gitlab::Database::Migration[1.0] + # rubocop:disable Migration/AddLimitToTextColumns + def change + add_column :application_settings, :sentry_enabled, :boolean, default: false, null: false + add_column :application_settings, :sentry_dsn, :text + add_column :application_settings, :sentry_clientside_dsn, :text + add_column :application_settings, :sentry_environment, :text + end + # rubocop:enable Migration/AddLimitToTextColumns +end diff --git a/db/migrate/20211021134458_add_limits_to_sentry_settings_on_application_settings.rb b/db/migrate/20211021134458_add_limits_to_sentry_settings_on_application_settings.rb new file mode 100644 index 00000000000..34d18741788 --- /dev/null +++ b/db/migrate/20211021134458_add_limits_to_sentry_settings_on_application_settings.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddLimitsToSentrySettingsOnApplicationSettings < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + def up + add_text_limit :application_settings, :sentry_dsn, 255 + add_text_limit :application_settings, :sentry_clientside_dsn, 255 + add_text_limit :application_settings, :sentry_environment, 255 + end + + def down + remove_text_limit :application_settings, :sentry_dsn + remove_text_limit :application_settings, :sentry_clientside_dsn + remove_text_limit :application_settings, :sentry_environment + end +end diff --git a/db/post_migrate/20211005194425_schedule_requirements_migration.rb b/db/post_migrate/20211005194425_schedule_requirements_migration.rb new file mode 100644 index 00000000000..56211989b8e --- /dev/null +++ b/db/post_migrate/20211005194425_schedule_requirements_migration.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class ScheduleRequirementsMigration < Gitlab::Database::Migration[1.0] + DOWNTIME = false + + # 2021-10-05 requirements count: ~12500 + # + # Using 30 as batch size and 120 seconds default interval will produce: + # ~420 jobs - taking ~14 hours to perform + BATCH_SIZE = 30 + + MIGRATION = 'MigrateRequirementsToWorkItems' + + disable_ddl_transaction! + + class Requirement < ActiveRecord::Base + include EachBatch + + self.table_name = 'requirements' + end + + def up + queue_background_migration_jobs_by_range_at_intervals( + Requirement.where(issue_id: nil), + MIGRATION, + 2.minutes, + batch_size: BATCH_SIZE, + track_jobs: true + ) + end + + def down + # NO OP + end +end diff --git a/db/schema_migrations/20211005194425 b/db/schema_migrations/20211005194425 new file mode 100644 index 00000000000..cd3710a6492 --- /dev/null +++ b/db/schema_migrations/20211005194425 @@ -0,0 +1 @@ +6647e94d315c76629f9726e26bafd124fb2fed361568d65315e7c7557f8d9ecf \ No newline at end of file diff --git a/db/schema_migrations/20211021125908 b/db/schema_migrations/20211021125908 new file mode 100644 index 00000000000..9cb92e1eabe --- /dev/null +++ b/db/schema_migrations/20211021125908 @@ -0,0 +1 @@ +d6fbe3efc3e45b750d82e277e30b7b0048b960d9f9f5b4f7c6a7a1ed869e76b5 \ No newline at end of file diff --git a/db/schema_migrations/20211021134458 b/db/schema_migrations/20211021134458 new file mode 100644 index 00000000000..dc168e12229 --- /dev/null +++ b/db/schema_migrations/20211021134458 @@ -0,0 +1 @@ +1baa8db0d42a8d99e48b61930f5c42d1af5f86555488419b6551e1dbf417d3ad \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 531e969b413..588061cdd3f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10457,6 +10457,10 @@ CREATE TABLE application_settings ( encrypted_content_validation_api_key bytea, encrypted_content_validation_api_key_iv bytea, content_validation_endpoint_enabled boolean DEFAULT false NOT NULL, + sentry_enabled boolean DEFAULT false NOT NULL, + sentry_dsn text, + sentry_clientside_dsn text, + sentry_environment text, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), @@ -10465,9 +10469,12 @@ CREATE TABLE application_settings ( CONSTRAINT app_settings_yaml_max_size_positive CHECK ((max_yaml_size_bytes > 0)), CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)), CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)), + CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)), + CONSTRAINT check_4f8b811780 CHECK ((char_length(sentry_dsn) <= 255)), CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)), CONSTRAINT check_57123c9593 CHECK ((char_length(help_page_documentation_base_url) <= 255)), CONSTRAINT check_5a84c3ffdc CHECK ((char_length(content_validation_endpoint_url) <= 255)), + CONSTRAINT check_5bcba483c4 CHECK ((char_length(sentry_environment) <= 255)), CONSTRAINT check_718b4458ae CHECK ((char_length(personal_access_token_prefix) <= 20)), CONSTRAINT check_7227fad848 CHECK ((char_length(rate_limiting_response_text) <= 255)), CONSTRAINT check_85a39b68ff CHECK ((char_length(encrypted_ci_jwt_signing_key_iv) <= 255)), diff --git a/doc/api/packages/maven.md b/doc/api/packages/maven.md index b4b3d579ffb..b046b0dc411 100644 --- a/doc/api/packages/maven.md +++ b/doc/api/packages/maven.md @@ -36,13 +36,13 @@ GET packages/maven/*path/:file_name | `file_name` | string | yes | The name of the Maven package file. | ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" ``` To write the output to file: ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar ``` This writes the downloaded file to `mypkg-1.0-SNAPSHOT.jar` in the current directory. @@ -63,13 +63,13 @@ GET groups/:id/-/packages/maven/*path/:file_name | `file_name` | string | yes | The name of the Maven package file. | ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/groups/1/-/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/groups/1/-/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" ``` To write the output to file: ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/groups/1/-/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/groups/1/-/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar ``` This writes the downloaded file to `mypkg-1.0-SNAPSHOT.jar` in the current directory. @@ -90,13 +90,13 @@ GET projects/:id/packages/maven/*path/:file_name | `file_name` | string | yes | The name of the Maven package file. | ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" ``` To write the output to file: ```shell -curl --header "Private-Token: " "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar +curl --header "Private-Token: " "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.jar" >> mypkg-1.0-SNAPSHOT.jar ``` This writes the downloaded file to `mypkg-1.0-SNAPSHOT.jar` in the current directory. @@ -120,5 +120,5 @@ PUT projects/:id/packages/maven/*path/:file_name curl --request PUT \ --upload-file path/to/mypkg-1.0-SNAPSHOT.pom \ --header "Private-Token: " \ - "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/baz/mypkg-1.0-SNAPSHOT.pom" + "https://gitlab.example.com/api/v4/projects/1/packages/maven/foo/bar/mypkg/1.0-SNAPSHOT/mypkg-1.0-SNAPSHOT.pom" ``` diff --git a/doc/development/avoiding_downtime_in_migrations.md b/doc/development/avoiding_downtime_in_migrations.md index 9418eafa487..a5fc1909551 100644 --- a/doc/development/avoiding_downtime_in_migrations.md +++ b/doc/development/avoiding_downtime_in_migrations.md @@ -377,7 +377,181 @@ ensures that no downtime is needed. This operation does not require downtime. -## Data Migrations +## Migrating `integer` primary keys to `bigint` + +To [prevent the overflow risk](https://gitlab.com/groups/gitlab-org/-/epics/4785) for some tables +with `integer` primary key (PK), we have to migrate their PK to `bigint`. The process to do this +without downtime and causing too much load on the database is described below. + +### Initialize the conversion and start migrating existing data (release N) + +To start the process, add a regular migration to create the new `bigint` columns. Use the provided +`initialize_conversion_of_integer_to_bigint` helper. The helper also creates a database trigger +to keep in sync both columns for any new records ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/migrate/20210608072312_initialize_conversion_of_ci_stages_to_bigint.rb)): + +```ruby +class InitializeConversionOfCiStagesToBigint < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + TABLE = :ci_stages + COLUMNS = %i(id) + + def up + initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS) + end + + def down + revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS) + end +end +``` + +Ignore the new `bigint` columns: + +```ruby +module Ci + class Stage < Ci::ApplicationRecord + include IgnorableColumns + ignore_column :id_convert_to_bigint, remove_with: '14.2', remove_after: '2021-08-22' + end +``` + +To migrate existing data, we introduced new type of _batched background migrations_. +Unlike the classic background migrations, built on top of Sidekiq, batched background migrations +don't have to enqueue and schedule all the background jobs at the beginning. +They also have other advantages, like automatic tuning of the batch size, better progress visibility, +and collecting metrics. To start the process, use the provided `backfill_conversion_of_integer_to_bigint` +helper ([example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/migrate/20210608072346_backfill_ci_stages_for_bigint_conversion.rb)): + +```ruby +class BackfillCiStagesForBigintConversion < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + TABLE = :ci_stages + COLUMNS = %i(id) + + def up + backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS) + end + + def down + revert_backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS) + end +end +``` + +### Monitor the background migration + +Check how the migration is performing while it's running. Multiple ways to do this are described below. + +#### High-level status of batched background migrations + +See how to [check the status of batched background migrations](../update/index.md#checking-for-background-migrations-before-upgrading). + +#### Query the database + +We can query the related database tables directly. Requires access to read-only replica. +Example queries: + +```sql +-- Get details for batched background migration for given table +SELECT * FROM batched_background_migrations WHERE table_name = 'namespaces'\gx + +-- Get count of batched background migration jobs by status for given table +SELECT + batched_background_migrations.id, batched_background_migration_jobs.status, COUNT(*) +FROM + batched_background_migrations + JOIN batched_background_migration_jobs ON batched_background_migrations.id = batched_background_migration_jobs.batched_background_migration_id +WHERE + table_name = 'namespaces' +GROUP BY + batched_background_migrations.id, batched_background_migration_jobs.status; + +-- Batched background migration progress for given table (based on estimated total number of tuples) +SELECT + m.table_name, + LEAST(100 * sum(j.batch_size) / pg_class.reltuples, 100) AS percentage_complete +FROM + batched_background_migrations m + JOIN batched_background_migration_jobs j ON j.batched_background_migration_id = m.id + JOIN pg_class ON pg_class.relname = m.table_name +WHERE + j.status = 3 AND m.table_name = 'namespaces' +GROUP BY m.id, pg_class.reltuples; +``` + +#### Sidekiq logs + +We can also use the Sidekiq logs to monitor the worker that executes the batched background +migrations: + +1. Sign in to [Kibana](https://log.gprd.gitlab.net) with a `@gitlab.com` email address. +1. Change the index pattern to `pubsub-sidekiq-inf-gprd*`. +1. Add filter for `json.queue: cronjob:database_batched_background_migration`. + +#### PostgerSQL slow queries log + +Slow queries log keeps track of low queries that took above 1 second to execute. To see them +for batched background migration: + +1. Sign in to [Kibana](https://log.gprd.gitlab.net) with a `@gitlab.com` email address. +1. Change the index pattern to `pubsub-postgres-inf-gprd*`. +1. Add filter for `json.endpoint_id.keyword: Database::BatchedBackgroundMigrationWorker`. +1. Optional. To see only updates, add a filter for `json.command_tag.keyword: UPDATE`. +1. Optional. To see only failed statements, add a filter for `json.error_severiry.keyword: ERROR`. +1. Optional. Add a filter by table name. + +#### Grafana dashboards + +To monitor the health of the database, use these additional metrics: + +- [PostgreSQL Tuple Statistics](https://dashboards.gitlab.net/d/000000167/postgresql-tuple-statistics?orgId=1&refresh=1m): if you see high rate of updates for the tables being actively converted, or increasing percentage of dead tuples for this table, it might mean that autovacuum cannot keep up. +- [PostgreSQL Overview](https://dashboards.gitlab.net/d/000000144/postgresql-overview?orgId=1): if you see high system usage or transactions per second (TPS) on the primary database server, it might mean that the migration is causing problems. + +### Prometheus metrics + +Number of [metrics](https://gitlab.com/gitlab-org/gitlab/-/blob/294a92484ce4611f660439aa48eee4dfec2230b5/lib/gitlab/database/background_migration/batched_migration_wrapper.rb#L90-128) +for each batched background migration are published to Prometheus. These metrics can be searched for and +visualized in Thanos ([see an example](https://thanos-query.ops.gitlab.net/graph?g0.expr=sum%20(rate(batched_migration_job_updated_tuples_total%7Benv%3D%22gprd%22%7D%5B5m%5D))%20by%20(migration_id)%20&g0.tab=0&g0.stacked=0&g0.range_input=3d&g0.max_source_resolution=0s&g0.deduplicate=1&g0.partial_response=0&g0.store_matches=%5B%5D&g0.end_input=2021-06-13%2012%3A18%3A24&g0.moment_input=2021-06-13%2012%3A18%3A24)). + +### Swap the columns (release N + 1) + +After the background is completed and the new `bigint` columns are populated for all records, we can +swap the columns. Swapping is done with post-deployment migration. The exact process depends on the +table being converted, but in general it's done in the following steps: + +1. Using the provided `ensure_batched_background_migration_is_finished` helper, make sure the batched +migration has finished ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L13-18)). +If the migration has not completed, the subsequent steps fail anyway. By checking in advance we +aim to have more helpful error message. +1. Create indexes using the `bigint` columns that match the existing indexes using the `integer` +column ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L28-34)). +1. Create foreign keys (FK) using the `bigint` columns that match the existing FKs using the +`integer` column. Do this both for FK referencing other tables, and FKs that reference the table +that is being migrated ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L36-43)). +1. Inside a transaction, swap the columns: + 1. Lock the tables involved. To reduce the chance of hitting a deadlock, we recommended to do this in parent to child order ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L47)). + 1. Rename the columns to swap names ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L49-54)) + 1. Reset the trigger function ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L56-57)). + 1. Swap the defaults ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L59-62)). + 1. Swap the PK constraint (if any) ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L64-68)). + 1. Remove old indexes and rename new ones ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L70-72)). + 1. Remove old FKs (if still present) and rename new ones ([see an example](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb#L74)). + +See example [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66088), and [migration](https://gitlab.com/gitlab-org/gitlab/-/blob/41fbe34a4725a4e357a83fda66afb382828767b2/db/post_migrate/20210707210916_finalize_ci_stages_bigint_conversion.rb). + +### Remove the trigger and old `integer` columns (release N + 2) + +Using post-deployment migration and the provided `cleanup_conversion_of_integer_to_bigint` helper, +drop the database trigger and the old `integer` columns ([see an example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69714)). + +### Remove ignore rules (release N + 3) + +In the next release after the columns were dropped, remove the ignore rules as we do not need them +anymore ([see an example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71161)). + +## Data migrations Data migrations can be tricky. The usual approach to migrate data is to take a 3 step approach: diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index e03b96a0e14..d249d36f159 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -135,6 +135,7 @@ various database operations, such as: - [dropping and renaming columns](avoiding_downtime_in_migrations.md#dropping-columns) - [changing column constraints and types](avoiding_downtime_in_migrations.md#changing-column-constraints) - [adding and dropping indexes, tables, and foreign keys](avoiding_downtime_in_migrations.md#adding-indexes) +- [migrating `integer` primary keys to `bigint`](avoiding_downtime_in_migrations.md#adding-indexes) and explains how to perform them without requiring downtime. diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md index e3214ec26fe..3052d85b2cb 100644 --- a/doc/integration/jira/index.md +++ b/doc/integration/jira/index.md @@ -10,7 +10,7 @@ If your organization uses [Jira](https://www.atlassian.com/software/jira) issues you can [migrate your issues from Jira](../../user/project/import/jira.md) and work exclusively in GitLab. However, if you'd like to continue to use Jira, you can integrate it with GitLab. GitLab offers two types of Jira integrations, and you -can use one or both depending on the capabilities you need. It is recommended that you enable both. +can use one or both depending on the capabilities you need. We recommend you enable both. ## Compare integrations @@ -41,7 +41,7 @@ or the Jira DVCS (distributed version control system) connector, ### Direct feature comparison -| Capability | Jira integration | Jira Development panel integration | +| Capability | Jira integration | Jira development panel integration | |-|-|-| | Mention a Jira issue ID in a GitLab commit or merge request, and a link to the Jira issue is created. | Yes. | No. | | Mention a Jira issue ID in GitLab and the Jira issue shows the GitLab issue or merge request. | Yes. A Jira comment with the GitLab issue or MR title links to GitLab. The first mention is also added to the Jira issue under **Web links**. | Yes, in the issue's [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). | @@ -55,11 +55,11 @@ or the Jira DVCS (distributed version control system) connector, ## Authentication in Jira -The process for configuring Jira depends on whether you host Jira on your own server or on +The authentication method in Jira depends on whether you host Jira on your own server or on [Atlassian cloud](https://www.atlassian.com/cloud): - **Jira Server** supports basic authentication. When connecting, a **username and password** are - required. Connecting to Jira Server via CAS is not possible. For more information, read + required. Connecting to Jira Server using the Central Authentication Service (CAS) is not possible. For more information, read how to [set up a user in Jira Server](jira_server_configuration.md). - **Jira on Atlassian cloud** supports authentication through an API token. When connecting to Jira on Atlassian cloud, an email and API token are required. For more information, read @@ -72,11 +72,16 @@ actions in GitLab issues and merge requests linked to a Jira issue leak informat about the private project to non-administrator Jira users. If your installation uses Jira Cloud, you can use the [GitLab.com for Jira Cloud app](connect-app.md) to avoid this risk. +## Third-party Jira integrations + +Developers have built several third-party Jira integrations for GitLab that are +listed on the [Atlassian Marketplace](https://marketplace.atlassian.com/search?product=jira&query=gitlab). + ## Troubleshooting If these features do not work as expected, it is likely due to a problem with the way the integration settings were configured. -### GitLab is unable to comment on a Jira issue +### GitLab cannot comment on a Jira issue If GitLab cannot comment on Jira issues, make sure the Jira user you set up for the integration has permission to: @@ -86,14 +91,16 @@ set up for the integration has permission to: Jira issue references and update comments do not work if the GitLab issue tracker is disabled. -### GitLab is unable to close a Jira issue +### GitLab cannot close a Jira issue -Make sure the `Transition ID` you set in the Jira settings matches the one -your project needs to close an issue. +If GitLab cannot close a Jira issue: -Make sure that the Jira issue is not already marked as resolved. That is, -the Jira issue resolution field is not set, and the issue is not struck through in -Jira lists. +- Make sure the `Transition ID` you set in the Jira settings matches the one + your project needs to close an issue. + +- Make sure the Jira issue is not already marked as resolved: + - Check the Jira issue resolution field is not set. + - Check the issue is not struck through in Jira lists. ### CAPTCHA @@ -104,8 +111,3 @@ authenticate with the Jira site. To fix this error, sign in to your Jira instance and complete the CAPTCHA. - -## Third-party Jira integrations - -Developers have built several third-party Jira integrations for GitLab that are -listed on the [Atlassian Marketplace](https://marketplace.atlassian.com/search?product=jira&query=gitlab). diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md index 27d2bd8f764..a0f1d9fcb67 100644 --- a/doc/user/admin_area/index.md +++ b/doc/user/admin_area/index.md @@ -257,6 +257,10 @@ To edit a topic, select **Edit** in that topic's row. To search for topics by name, enter your criteria in the search box. The topic search is case insensitive, and applies partial matching. +NOTE: +Topics are public and visible to everyone, but assignments to projects are not. +Do not include sensitive information in the name or description of a topic. + ### Administering Jobs You can administer all jobs in the GitLab instance from the Admin Area's Jobs page. diff --git a/doc/user/clusters/agent/repository.md b/doc/user/clusters/agent/repository.md index 4dda2fc4498..182b03d0c9f 100644 --- a/doc/user/clusters/agent/repository.md +++ b/doc/user/clusters/agent/repository.md @@ -173,7 +173,7 @@ To grant projects access to the Agent through the [CI/CD Tunnel](ci_cd_tunnel.md 1. Go to your Agent's configuration project. 1. Edit the Agent's configuration file (`config.yaml`). 1. Add the `projects` attribute into `ci_access`. -1. Identify the new project through its path: +1. Identify the project through its path: ```yaml ci_access: diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md index e9cbe43d7fb..7bfaacd96a3 100644 --- a/doc/user/clusters/management_project.md +++ b/doc/user/clusters/management_project.md @@ -12,6 +12,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w WARNING: This feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5. +To manage cluster applications, use the [GitLab Kubernetes Agent](agent/index.md) +with the [Cluster Management Project Template](management_project_template.md). + A project can be designated as the management project for a cluster. A management project can be used to run deployment jobs with Kubernetes @@ -41,8 +44,7 @@ Management projects are restricted to the following: To use a cluster management project to manage your cluster: 1. Create a new project to serve as the cluster management project -for your cluster. We recommend that you -[create this project based on the Cluster Management project template](management_project_template.md#create-a-new-project-based-on-the-cluster-management-template). +for your cluster. 1. [Associate the cluster with the management project](#associate-the-cluster-management-project-with-the-cluster). 1. [Configure your cluster's pipelines](#configuring-your-pipeline). 1. [Set the environment scope](#setting-the-environment-scope). diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md index ea364063758..c663246cdd8 100644 --- a/doc/user/clusters/management_project_template.md +++ b/doc/user/clusters/management_project_template.md @@ -4,15 +4,17 @@ group: Configure info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- -# Cluster Management project template **(FREE)** +# Manage cluster applications **(FREE)** > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25318) in GitLab 12.10 with Helmfile support via Helm v2. > - Helm v2 support was [dropped](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63577) in GitLab 14.0. Use Helm v3 instead. +> - [Migrated](https://gitlab.com/gitlab-org/project-templates/cluster-management/-/merge_requests/24) to the GitLab Kubernetes Agent in GitLab 14.5. -With a [cluster management project](management_project.md) you can manage -your cluster's deployment and applications through a repository in GitLab. +Use a repository to install, manage, and deploy clusters applications through code. -The Cluster Management project template provides you a baseline to get +## Cluster Management Project Template + +The Cluster Management Project Template provides you a baseline to get started and flexibility to customize your project to your cluster's needs. For instance, you can: @@ -21,49 +23,78 @@ For instance, you can: - Remove the built-in cluster applications you don't need. - Add other cluster applications using the same structure as the ones already available. -The template contains the following [components](#available-components): +The template contains the following [components](#configure-the-available-components): -- A pre-configured GitLab CI/CD file so that you can configure deployment pipelines. +- A pre-configured GitLab CI/CD file so that you can configure CI/CD pipelines using the [CI/CD Tunnel](agent/ci_cd_tunnel.md). - A pre-configured [Helmfile](https://github.com/roboll/helmfile) so that you can manage cluster applications with [Helm v3](https://helm.sh/). - An `applications` directory with a `helmfile.yaml` configured for each application available in the template. -WARNING: -If you used [GitLab Managed Apps](applications.md) to manage your -cluster from GitLab, see how to [migrate from GitLab Managed Apps](migrating_from_gma_to_project_template.md) to the Cluster Management -project. +## Use the Kubernetes Agent with the Cluster Management Project Template -## Set up the management project from the Cluster Management project template +To use a new project created from the Cluster Management Project Template +with a cluster connected to GitLab through the [GitLab Kubernetes Agent](agent/index.md), +you have two options: -To set up your cluster's management project off of the Cluster Management project template: +- [Use one single project](#single-project) to configure the Agent and manage cluster applications. +- [Use separate projects](#separate-projects) - one to configure the Agent and another to manage cluster applications. -1. [Create a new project based on the Cluster Management template](#create-a-new-project-based-on-the-cluster-management-template). -1. [Associate the cluster management project with your cluster](management_project.md#associate-the-cluster-management-project-with-the-cluster). -1. Use the [available components](#available-components) to manage your cluster. +### Single project -### Create a new project based on the Cluster Management template +This setup is particularly useful when you haven't connected your cluster +to GitLab through the Agent yet and you want to use the Cluster Management +Project Template to manage cluster applications. + +To use one single project to configure the Agent and to manage cluster applications: + +1. [Create a new project from the Cluster Management Project Template](#create-a-new-project-based-on-the-cluster-management-template). +1. Configure the new project as the [Agent's configuration repository](agent/repository.md) +(where the Agent is registered and its `config.yaml` is stored). +1. From your project's settings, add a [new environment variable](../../ci/variables/index.md#add-a-cicd-variable-to-a-project) `$KUBE_CONTEXT` and set it to `path/to/agent-configuration-project:your-agent-name`. +1. [Configure the components](#configure-the-available-components) inherited from the template. + +### Separate projects + +This setup is particularly useful **when you already have a cluster** connected +to GitLab through the Agent and want to use the Cluster Management +Project Template to manage cluster applications. + +To use one project to configure the Agent ("project A") and another project to +manage cluster applications ("project B"), follow the steps below. + +We assume that you already have a cluster connected through the Agent and +[configured through the Agent's configuration repository](agent/repository.md) +("project A"). + +1. [Create a new project from the Cluster Management Project Template](#create-a-new-project-based-on-the-cluster-management-template). +This new project is "project B". +1. In your "project A", [grant the Agent access to the new project (B) through the CI/CD Tunnel](agent/repository.md#authorize-projects-to-use-an-agent). +1. From the "project's B" settings, add a [new environment variable](../../ci/variables/index.md#add-a-cicd-variable-to-a-project) `$KUBE_CONTEXT` and set it to `path/to/agent-configuration-project:your-agent-name`. +1. In "project B", [configure the components](#configure-the-available-components) inherited from the template. + +## Create a new project based on the Cluster Management Template To get started, create a new project based on the Cluster Management project template to use as a cluster management project. -You can either create the [new project](../project/working_with_projects.md#create-a-project) -from the template or import the project from the URL. Importing -the project is useful if you are using a GitLab self-managed -instance that may not have the latest version of the template. +You can either create the new project from the template or import the +project from the URL. Importing the project is useful if you are using +a GitLab self-managed instance that may not have the latest version of +the template. -To create the new project: +To [create the new project](../project/working_with_projects.md#create-a-project): - From the template: select the **GitLab Cluster Management** project template. - Importing from the URL: use `https://gitlab.com/gitlab-org/project-templates/cluster-management.git`. -## Available components +## Configure the available components -Use the available components to configure your cluster: +Use the available components to configure your cluster applications: -- [A `.gitlab-ci.yml` file](#the-gitlab-ciyml-file). -- [A main `helmfile.yml` file](#the-main-helmfileyml-file). -- [A directory with built-in applications](#built-in-applications). +- [The `.gitlab-ci.yml` file](#the-gitlab-ciyml-file). +- [The main `helmfile.yml` file](#the-main-helmfileyml-file). +- [The directory with built-in applications](#built-in-applications). ### The `.gitlab-ci.yml` file @@ -107,7 +138,7 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp - [Sentry](../infrastructure/clusters/manage/management_project_applications/sentry.md) - [Vault](../infrastructure/clusters/manage/management_project_applications/vault.md) -#### How to customize your applications +#### Customize your applications Each app has an `applications/{app}/values.yaml` file (`applications/{app}/values.yaml.gotmpl` in case of GitLab Runner). This is the place where you can define default values for your app's Helm chart. Some apps already have defaults diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md index 01260baa432..dd4558b4a3e 100644 --- a/doc/user/group/saml_sso/scim_setup.md +++ b/doc/user/group/saml_sso/scim_setup.md @@ -35,9 +35,10 @@ The following identity providers are supported: Once [Group Single Sign-On](index.md) has been configured, we can: -1. Navigate to the group and click **Administration > SAML SSO**. -1. Click on the **Generate a SCIM token** button. -1. Save the token and URL so they can be used in the next step. +1. On the top bar, select **Menu > Groups** and find your group. +1. On the left sidebar, select **Settings > SAML SSO**. +1. Select **Generate a SCIM token**. +1. Save the token and URL for use in the next step. ![SCIM token configuration](img/scim_token_v13_3.png) @@ -50,14 +51,14 @@ Once [Group Single Sign-On](index.md) has been configured, we can: The SAML application that was created during [Single sign-on](index.md) setup for [Azure](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/view-applications-portal) now needs to be set up for SCIM. -1. Set up automatic provisioning and administrative credentials by following the +1. Enable automatic provisioning and administrative credentials by following the [Azure's SCIM setup documentation](https://docs.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#provisioning-users-and-groups-to-applications-that-support-scim). During this configuration, note the following: -- The `Tenant URL` and `secret token` are the ones retrieved in the +- The `Tenant URL` and `secret token` are the items retrieved in the [previous step](#gitlab-configuration). -- It is recommended to set a notification email and check the **Send an email notification when a failure occurs** checkbox. +- We recommend setting a notification email and selecting the **Send an email notification when a failure occurs** checkbox. - For mappings, we only leave `Synchronize Azure Active Directory Users to AppName` enabled. `Synchronize Azure Active Directory Groups to AppName` is usually disabled. However, this does not mean Azure AD users cannot be provisioned in groups. Leaving it enabled does not break @@ -113,29 +114,27 @@ Make sure that the Okta setup matches our documentation exactly, especially the configuration. Otherwise, the Okta SCIM app may not work properly. 1. Sign in to Okta. -1. If you see an **Admin** button in the top right, click the button. This will - ensure you are in the Admin area. +1. Ensure you are in the Admin section by selecting the **Admin** button located in the top right. The admin button is not visible from the admin page. NOTE: - If you're using the Developer Console, click **Developer Console** in the top - bar and select **Classic UI**. Otherwise, you may not see the buttons described - in the following steps: + If you're using the Developer Console, select **Developer Console** in the top + bar and then select **Classic UI**. Otherwise, you may not see the buttons described in the following steps: -1. In the **Application** tab, click **Add Application**. -1. Search for **GitLab**, find and click on the 'GitLab' application. -1. On the GitLab application overview page, click **Add**. +1. In the **Application** tab, select **Add Application**. +1. Search for **GitLab**, find and select on the 'GitLab' application. +1. On the GitLab application overview page, select **Add**. 1. Under **Application Visibility** select both checkboxes. Currently the GitLab application does not support SAML authentication so the icon should not be shown to users. -1. Click **Done** to finish adding the application. -1. In the **Provisioning** tab, click **Configure API integration**. +1. Select **Done** to finish adding the application. +1. In the **Provisioning** tab, select **Configure API integration**. 1. Select **Enable API integration**. - For **Base URL** enter the URL obtained from the GitLab SCIM configuration page - For **API Token** enter the SCIM token obtained from the GitLab SCIM configuration page -1. Click 'Test API Credentials' to verify configuration. -1. Click **Save** to apply the settings. -1. After saving the API integration details, new settings tabs appear on the left. Choose **To App**. -1. Click **Edit**. -1. Check the box to **Enable** for both **Create Users** and **Deactivate Users**. -1. Click **Save**. +1. Select 'Test API Credentials' to verify configuration. +1. Select **Save** to apply the settings. +1. After saving the API integration details, new settings tabs appear on the left. Select **To App**. +1. Select **Edit**. +1. Select the **Enable** checkbox for both **Create Users** and **Deactivate Users**. +1. Select **Save**. 1. Assign users in the **Assignments** tab. Assigned users are created and managed in your GitLab group. @@ -147,8 +146,8 @@ application described above. ### OneLogin -OneLogin provides a "GitLab (SaaS)" app in their catalog, which includes a SCIM integration. -As the app is developed by OneLogin, please reach out to OneLogin if you encounter issues. +As the developers of this app, OneLogin provides a "GitLab (SaaS)" app in their catalog, which includes a SCIM integration. +Please reach out to OneLogin if you encounter issues. ## User access and linking setup @@ -177,8 +176,8 @@ As long as [Group SAML](index.md) has been configured, existing GitLab.com users - By following these steps: 1. Sign in to GitLab.com if needed. - 1. Click on the GitLab app in the identity provider's dashboard or visit the **GitLab single sign-on URL**. - 1. Click on the **Authorize** button. + 1. In the identity provider's dashboard select the GitLab app or visit the **GitLab single sign-on URL**. + 1. Select the **Authorize**. We recommend users do this prior to turning on sync, because while synchronization is active, there may be provisioning errors for existing users. diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md index 6e3af45df17..1adb806b27a 100644 --- a/doc/user/packages/composer_repository/index.md +++ b/doc/user/packages/composer_repository/index.md @@ -149,7 +149,7 @@ Do not save unless you want to overwrite the existing CI/CD file. When you publish: - The same package with different data, it overwrites the existing package. -- The same package with the same data, a `404 Bad request` error occurs. +- The same package with the same data, a `400 Bad request` error occurs. ## Install a Composer package diff --git a/doc/user/project/settings/img/import_export_download_export.png b/doc/user/project/settings/img/import_export_download_export.png index c7ab7565fc7..62292e99e8e 100644 Binary files a/doc/user/project/settings/img/import_export_download_export.png and b/doc/user/project/settings/img/import_export_download_export.png differ diff --git a/doc/user/project/settings/img/import_export_export_button.png b/doc/user/project/settings/img/import_export_export_button.png index 6933e3edfcc..6f3663d64e8 100644 Binary files a/doc/user/project/settings/img/import_export_export_button.png and b/doc/user/project/settings/img/import_export_export_button.png differ diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md index c0e08987998..9fdcab406cc 100644 --- a/doc/user/project/settings/import_export.md +++ b/doc/user/project/settings/import_export.md @@ -160,6 +160,8 @@ To export a project and its data, follow these steps: 1. Select **Settings** in the sidebar. +1. Scroll down and expand the **Advanced** section. + 1. Scroll down to find the **Export project** button: ![Export button](img/import_export_export_button.png) diff --git a/lib/gitlab/background_migration/migrate_requirements_to_work_items.rb b/lib/gitlab/background_migration/migrate_requirements_to_work_items.rb new file mode 100644 index 00000000000..017791f197c --- /dev/null +++ b/lib/gitlab/background_migration/migrate_requirements_to_work_items.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # No op on CE + class MigrateRequirementsToWorkItems + def perform(start_id, end_id) + end + end + end +end + +Gitlab::BackgroundMigration::MigrateRequirementsToWorkItems.prepend_mod_with('Gitlab::BackgroundMigration::MigrateRequirementsToWorkItems') diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b9709b62906..1720b2be13f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1107,9 +1107,6 @@ msgstr "" msgid "(check progress)" msgstr "" -msgid "(commits will be squashed)" -msgstr "" - msgid "(deleted)" msgstr "" @@ -1128,6 +1125,11 @@ msgstr "" msgid "(revoked)" msgstr "" +msgid "(squashes %d commit)" +msgid_plural "(squashes %d commits)" +msgstr[0] "" +msgstr[1] "" + msgid "(this user)" msgstr "" @@ -6553,6 +6555,9 @@ msgstr "" msgid "Changes to the title have not been saved" msgstr "" +msgid "Changing any setting here requires an application restart" +msgstr "" + msgid "Changing group URL can have unintended side effects." msgstr "" @@ -7196,6 +7201,9 @@ msgstr "" msgid "Clients" msgstr "" +msgid "Clientside DSN" +msgstr "" + msgid "Clone" msgstr "" @@ -8689,6 +8697,9 @@ msgstr "" msgid "Configure Secret Detection in `.gitlab-ci.yml`, creating this file if it does not already exist" msgstr "" +msgid "Configure Sentry integration for error tracking" +msgstr "" + msgid "Configure Tracing" msgstr "" @@ -10397,6 +10408,9 @@ msgstr "" msgid "DORA4Metrics|The chart displays the median time between a merge request being merged and deployed to production environment(s) that are based on the %{linkStart}deployment_tier%{linkEnd} value." msgstr "" +msgid "DSN" +msgstr "" + msgid "Dashboard" msgstr "" @@ -11164,6 +11178,12 @@ msgstr "" msgid "Deleted projects cannot be restored!" msgstr "" +msgid "Deletes the source branch" +msgstr "" + +msgid "Deletes the source branch." +msgstr "" + msgid "Deleting" msgstr "" @@ -12214,6 +12234,9 @@ msgstr "" msgid "Does not apply to projects in personal namespaces, which are deleted immediately on request." msgstr "" +msgid "Does not delete the source branch." +msgstr "" + msgid "Domain" msgstr "" @@ -12709,6 +12732,9 @@ msgstr "" msgid "Enable SSL verification" msgstr "" +msgid "Enable Sentry error tracking" +msgstr "" + msgid "Enable Service Ping" msgstr "" @@ -32506,12 +32532,6 @@ msgstr "" msgid "Source branch" msgstr "" -msgid "Source branch will be deleted." -msgstr "" - -msgid "Source branch will not be deleted." -msgstr "" - msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}" msgstr "" @@ -34507,9 +34527,6 @@ msgstr "" msgid "The snippet is visible to any logged in user except external users." msgstr "" -msgid "The source branch will be deleted" -msgstr "" - msgid "The specified tab is invalid, please select another" msgstr "" @@ -41019,15 +41036,15 @@ msgstr "" msgid "most recent deployment" msgstr "" -msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}." -msgstr "" - -msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}." -msgstr "" - msgid "mrWidgetCommitsAdded|1 merge commit" msgstr "" +msgid "mrWidgetCommitsAdded|Adds %{commitCount} and %{mergeCommitCount} to %{targetBranch}%{squashedCommits}." +msgstr "" + +msgid "mrWidgetCommitsAdded|Adds %{commitCount} to %{targetBranch}." +msgstr "" + msgid "mrWidgetNothingToMerge|This merge request contains no changes." msgstr "" @@ -41135,6 +41152,9 @@ msgstr "" msgid "mrWidget|Delete source branch" msgstr "" +msgid "mrWidget|Deletes the source branch" +msgstr "" + msgid "mrWidget|Deployment statistics are not available currently" msgstr "" @@ -41144,6 +41164,9 @@ msgstr "" msgid "mrWidget|Dismiss" msgstr "" +msgid "mrWidget|Does not delete the source branch" +msgstr "" + msgid "mrWidget|Email patches" msgstr "" @@ -41200,6 +41223,9 @@ msgstr "" msgid "mrWidget|Merged by" msgstr "" +msgid "mrWidget|Merges changes into" +msgstr "" + msgid "mrWidget|Merging! Changes are being shipped…" msgstr "" @@ -41284,9 +41310,6 @@ msgstr "" msgid "mrWidget|The changes were not merged into" msgstr "" -msgid "mrWidget|The changes will be merged into" -msgstr "" - msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions." msgstr "" @@ -41302,12 +41325,6 @@ msgstr "" msgid "mrWidget|The source branch is being deleted" msgstr "" -msgid "mrWidget|The source branch will be deleted" -msgstr "" - -msgid "mrWidget|The source branch will not be deleted" -msgstr "" - msgid "mrWidget|There are merge conflicts" msgstr "" diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb index 2b1c956039f..734529f319a 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :mixed_env, :smoke, only: { subdomain: :staging } do + RSpec.describe 'Manage', only: { subdomain: :staging }, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344213', type: :stale } do describe 'basic user' do it 'remains logged in when redirected from canary to non-canary node', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/2251' do Runtime::Browser.visit(:gitlab, Page::Main::Login) diff --git a/lib/gitlab/sidekiq_cluster/cli.rb b/sidekiq_cluster/cli.rb similarity index 92% rename from lib/gitlab/sidekiq_cluster/cli.rb rename to sidekiq_cluster/cli.rb index 3dee257229d..55b4521d37d 100644 --- a/lib/gitlab/sidekiq_cluster/cli.rb +++ b/sidekiq_cluster/cli.rb @@ -4,27 +4,21 @@ require 'optparse' require 'logger' require 'time' +# In environments where code is preloaded and cached such as `spring`, +# we may run into "already initialized" warnings, hence the check. +require_relative '../lib/gitlab' unless Object.const_defined?('Gitlab') +require_relative '../lib/gitlab/utils' +require_relative '../lib/gitlab/sidekiq_config/cli_methods' +require_relative '../lib/gitlab/sidekiq_config/worker_matcher' +require_relative '../lib/gitlab/sidekiq_logging/json_formatter' +require_relative 'sidekiq_cluster' + module Gitlab module SidekiqCluster class CLI - CHECK_TERMINATE_INTERVAL_SECONDS = 1 - - # How long to wait when asking for a clean termination. - # It maps the Sidekiq default timeout: - # https://github.com/mperham/sidekiq/wiki/Signals#term - # - # This value is passed to Sidekiq's `-t` if none - # is given through arguments. - DEFAULT_SOFT_TIMEOUT_SECONDS = 25 - - # After surpassing the soft timeout. - DEFAULT_HARD_TIMEOUT_SECONDS = 5 - CommandError = Class.new(StandardError) def initialize(log_output = $stderr) - require_relative '../../../lib/gitlab/sidekiq_logging/json_formatter' - # As recommended by https://github.com/mperham/sidekiq/wiki/Advanced-Options#concurrency @max_concurrency = 50 @min_concurrency = 0 diff --git a/sidekiq_cluster/dependencies.rb b/sidekiq_cluster/dependencies.rb new file mode 100644 index 00000000000..91e91475f15 --- /dev/null +++ b/sidekiq_cluster/dependencies.rb @@ -0,0 +1,6 @@ +# rubocop:disable Naming/FileName +# frozen_string_literal: true + +require 'shellwords' + +# rubocop:enable Naming/FileName diff --git a/lib/gitlab/sidekiq_cluster.rb b/sidekiq_cluster/sidekiq_cluster.rb similarity index 89% rename from lib/gitlab/sidekiq_cluster.rb rename to sidekiq_cluster/sidekiq_cluster.rb index cc1bd282da8..49478ba740d 100644 --- a/lib/gitlab/sidekiq_cluster.rb +++ b/sidekiq_cluster/sidekiq_cluster.rb @@ -1,9 +1,22 @@ # frozen_string_literal: true -require 'shellwords' +require_relative 'dependencies' module Gitlab module SidekiqCluster + CHECK_TERMINATE_INTERVAL_SECONDS = 1 + + # How long to wait when asking for a clean termination. + # It maps the Sidekiq default timeout: + # https://github.com/mperham/sidekiq/wiki/Signals#term + # + # This value is passed to Sidekiq's `-t` if none + # is given through arguments. + DEFAULT_SOFT_TIMEOUT_SECONDS = 25 + + # After surpassing the soft timeout. + DEFAULT_HARD_TIMEOUT_SECONDS = 5 + # The signals that should terminate both the master and workers. TERMINATE_SIGNALS = %i(INT TERM).freeze @@ -62,7 +75,7 @@ module Gitlab # directory - The directory of the Rails application. # # Returns an Array containing the PIDs of the started processes. - def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, timeout: CLI::DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false) + def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, timeout: DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false) queues.map.with_index do |pair, index| start_sidekiq(pair, env: env, directory: directory, diff --git a/spec/lib/gitlab/sidekiq_cluster/cli_spec.rb b/spec/commands/sidekiq_cluster/cli_spec.rb similarity index 96% rename from spec/lib/gitlab/sidekiq_cluster/cli_spec.rb rename to spec/commands/sidekiq_cluster/cli_spec.rb index e818b03cf75..baa4a2b4ec3 100644 --- a/spec/lib/gitlab/sidekiq_cluster/cli_spec.rb +++ b/spec/commands/sidekiq_cluster/cli_spec.rb @@ -3,9 +3,11 @@ require 'fast_spec_helper' require 'rspec-parameterized' -RSpec.describe Gitlab::SidekiqCluster::CLI do +require_relative '../../../sidekiq_cluster/cli' + +RSpec.describe Gitlab::SidekiqCluster::CLI do # rubocop:disable RSpec/FilePath let(:cli) { described_class.new('/dev/null') } - let(:timeout) { described_class::DEFAULT_SOFT_TIMEOUT_SECONDS } + let(:timeout) { Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS } let(:default_options) do { env: 'test', directory: Dir.pwd, max_concurrency: 50, min_concurrency: 0, dryrun: false, timeout: timeout } end @@ -103,7 +105,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI do it 'when not given', 'starts Sidekiq workers with default timeout' do expect(Gitlab::SidekiqCluster).to receive(:start) - .with([['foo']], default_options.merge(timeout: described_class::DEFAULT_SOFT_TIMEOUT_SECONDS)) + .with([['foo']], default_options.merge(timeout: Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS)) cli.run(%w(foo)) end @@ -271,7 +273,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI do expect(Gitlab::SidekiqCluster).to receive(:signal_processes) .with([], "-KILL") - stub_const("Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) + stub_const("Gitlab::SidekiqCluster::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) allow(cli).to receive(:terminate_timeout_seconds) { 1 } cli.wait_for_termination @@ -301,7 +303,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI do cli.run(%w(foo)) - stub_const("Gitlab::SidekiqCluster::CLI::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) + stub_const("Gitlab::SidekiqCluster::CHECK_TERMINATE_INTERVAL_SECONDS", 0.1) allow(cli).to receive(:terminate_timeout_seconds) { 1 } cli.wait_for_termination diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb index 5c918267f50..acdeb98bb16 100644 --- a/spec/controllers/concerns/renders_commits_spec.rb +++ b/spec/controllers/concerns/renders_commits_spec.rb @@ -64,6 +64,12 @@ RSpec.describe RendersCommits do subject.prepare_commits_for_rendering(merge_request.commits.take(1)) end + # Populate Banzai::Filter::References::ReferenceCache + subject.prepare_commits_for_rendering(merge_request.commits) + + # Reset lazy_latest_pipeline cache to simulate a new request + BatchLoader::Executor.clear_current + expect do subject.prepare_commits_for_rendering(merge_request.commits) merge_request.commits.each(&:latest_pipeline) diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index af5ba14e310..9057b96bff0 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -36,7 +36,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do click_button "Merge when pipeline succeeds" expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds" - expect(page).to have_content "The source branch will not be deleted" + expect(page).to have_content "Does not delete the source branch" expect(page).to have_selector ".js-cancel-auto-merge" visit project_merge_request_path(project, merge_request) # Needed to refresh the page expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i @@ -126,7 +126,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do it 'allows to delete source branch' do click_button "Delete source branch" - expect(page).to have_content "The source branch will be deleted" + expect(page).to have_content "Deletes the source branch" end context 'when pipeline succeeds' do diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index f74b097ab3e..0117cf01e53 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -426,7 +426,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do it 'user cannot remove source branch', :sidekiq_might_not_need_inline do expect(page).not_to have_field('remove-source-branch-input') - expect(page).to have_content('The source branch will be deleted') + expect(page).to have_content('Deletes the source branch') end end diff --git a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap index 5981d2d7849..56a0218b374 100644 --- a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap +++ b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap @@ -50,7 +50,7 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have - The source branch will not be deleted + Does not delete the source branch - The source branch will not be deleted + Does not delete the source branch { const normalizedText = wrapper.text().replace(/\s+/g, ' '); - expect(normalizedText).toContain('The source branch will be deleted'); - expect(normalizedText).not.toContain('The source branch will not be deleted'); + expect(normalizedText).toContain('Deletes the source branch'); + expect(normalizedText).not.toContain('Does not delete the source branch'); }); it('should not show delete source branch button when user not able to delete source branch', () => { diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js index b6c16958993..e6b2e9fa176 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merging_spec.js @@ -42,7 +42,7 @@ describe('MRWidgetMerging', () => { .trim() .replace(/\s\s+/g, ' ') .replace(/[\r\n]+/g, ' '), - ).toEqual('The changes will be merged into branch'); + ).toEqual('Merges changes into branch'); expect(wrapper.find('a').attributes('href')).toBe('/branch-path'); }); diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js index 844e7330679..550f156d095 100644 --- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js @@ -543,7 +543,7 @@ describe('MrWidgetOptions', () => { nextTick(() => { const tooltip = wrapper.find('[data-testid="question-o-icon"]'); - expect(wrapper.text()).toContain('The source branch will be deleted'); + expect(wrapper.text()).toContain('Deletes the source branch'); expect(tooltip.attributes('title')).toBe( 'A user with write access to the source branch selected this option', ); @@ -559,7 +559,7 @@ describe('MrWidgetOptions', () => { nextTick(() => { expect(wrapper.text()).toContain('The source branch has been deleted'); - expect(wrapper.text()).not.toContain('The source branch will be deleted'); + expect(wrapper.text()).not.toContain('Deletes the source branch'); done(); }); diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 423e19c3971..641c6a2cd91 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -612,5 +612,46 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do expect(json_response.slice(*settings.keys)).to eq(settings) end end + + context 'Sentry settings' do + let(:settings) do + { + sentry_enabled: true, + sentry_dsn: 'http://sentry.example.com', + sentry_clientside_dsn: 'http://sentry.example.com', + sentry_environment: 'production' + } + end + + let(:attribute_names) { settings.keys.map(&:to_s) } + + it 'includes the attributes in the API' do + get api('/application/settings', admin) + + expect(response).to have_gitlab_http_status(:ok) + attribute_names.each do |attribute| + expect(json_response.keys).to include(attribute) + end + end + + it 'allows updating the settings' do + put api('/application/settings', admin), params: settings + + expect(response).to have_gitlab_http_status(:ok) + settings.each do |attribute, value| + expect(ApplicationSetting.current.public_send(attribute)).to eq(value) + end + end + + context 'missing sentry_dsn value when sentry_enabled is true' do + it 'returns a blank parameter error message' do + put api('/application/settings', admin), params: { sentry_enabled: true } + + expect(response).to have_gitlab_http_status(:bad_request) + message = json_response['message'] + expect(message["sentry_dsn"]).to include(a_string_matching("can't be blank")) + end + end + end end end diff --git a/spec/lib/gitlab/sidekiq_cluster_spec.rb b/spec/sidekiq_cluster/sidekiq_cluster_spec.rb similarity index 98% rename from spec/lib/gitlab/sidekiq_cluster_spec.rb rename to spec/sidekiq_cluster/sidekiq_cluster_spec.rb index 3c6ea054968..1d2b47e78ce 100644 --- a/spec/lib/gitlab/sidekiq_cluster_spec.rb +++ b/spec/sidekiq_cluster/sidekiq_cluster_spec.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require 'fast_spec_helper' require 'rspec-parameterized' -RSpec.describe Gitlab::SidekiqCluster do +require_relative '../../sidekiq_cluster/sidekiq_cluster' + +RSpec.describe Gitlab::SidekiqCluster do # rubocop:disable RSpec/FilePath describe '.trap_signals' do it 'traps the given signals' do expect(described_class).to receive(:trap).ordered.with(:INT) diff --git a/spec/support/flaky_tests.rb b/spec/support/flaky_tests.rb index c619f1412f1..535df64f890 100644 --- a/spec/support/flaky_tests.rb +++ b/spec/support/flaky_tests.rb @@ -2,7 +2,7 @@ return unless ENV['CI'] return unless ENV['SKIP_FLAKY_TESTS_AUTOMATICALLY'] == "true" -return if ENV['CI_MERGE_REQUEST_LABELS'].include?(/pipeline:run-flaky-tests/) +return if ENV['CI_MERGE_REQUEST_LABELS'].to_s.include?('pipeline:run-flaky-tests') require_relative '../tooling/rspec_flaky/report' diff --git a/spec/tooling/quality/test_level_spec.rb b/spec/tooling/quality/test_level_spec.rb index 40eb93c838b..94fa9d682e1 100644 --- a/spec/tooling/quality/test_level_spec.rb +++ b/spec/tooling/quality/test_level_spec.rb @@ -49,7 +49,7 @@ RSpec.describe Quality::TestLevel do context 'when level is integration' do it 'returns a pattern' do expect(subject.pattern(:integration)) - .to eq("spec/{controllers,mailers,requests}{,/**/}*_spec.rb") + .to eq("spec/{commands,controllers,mailers,requests}{,/**/}*_spec.rb") end end @@ -131,7 +131,7 @@ RSpec.describe Quality::TestLevel do context 'when level is integration' do it 'returns a regexp' do expect(subject.regexp(:integration)) - .to eq(%r{spec/(controllers|mailers|requests)}) + .to eq(%r{spec/(commands|controllers|mailers|requests)}) end end @@ -204,6 +204,10 @@ RSpec.describe Quality::TestLevel do expect(subject.level_for('spec/mailers/abuse_report_mailer_spec.rb')).to eq(:integration) end + it 'returns the correct level for an integration test in a subfolder' do + expect(subject.level_for('spec/commands/sidekiq_cluster/cli.rb')).to eq(:integration) + end + it 'returns the correct level for a system test' do expect(subject.level_for('spec/features/abuse_report_spec.rb')).to eq(:system) end diff --git a/tooling/quality/test_level.rb b/tooling/quality/test_level.rb index 57eb19517ea..5fbaad073c0 100644 --- a/tooling/quality/test_level.rb +++ b/tooling/quality/test_level.rb @@ -54,6 +54,7 @@ module Quality tooling ], integration: %w[ + commands controllers mailers requests