diff options
39 files changed, 407 insertions, 584 deletions
diff --git a/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.stories.js b/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.stories.js new file mode 100644 index 00000000000..a572d5af31b --- /dev/null +++ b/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.stories.js @@ -0,0 +1,46 @@ +import SectionedPercentageBar from './sectioned_percentage_bar.vue'; + +export default { + component: SectionedPercentageBar, + title: 'usage_quotas/sectioned_percentage_bar', +}; + +const Template = (args, { argTypes }) => ({ + components: { SectionedPercentageBar }, + props: Object.keys(argTypes), + template: '<sectioned-percentage-bar :sections="sections" />', +}); + +export const Default = Template.bind({}); +Default.args = { + sections: [ + { + id: 'artifacts', + label: 'Artifacts', + value: 2000, + formattedValue: '1.95 KiB', + cssClasses: 'gl-bg-data-viz-blue-500', + }, + { + id: 'repository', + label: 'Repository', + value: 4000, + formattedValue: '3.90 KiB', + cssClasses: 'gl-bg-data-viz-orange-500', + }, + { + id: 'packages', + label: 'Packages', + value: 3000, + formattedValue: '2.93 KiB', + cssClasses: 'gl-bg-data-viz-aqua-500', + }, + { + id: 'registry', + label: 'Registry', + value: 5000, + formattedValue: '4.88 KiB', + cssClasses: 'gl-bg-data-viz-green-500', + }, + ], +}; diff --git a/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.vue b/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.vue new file mode 100644 index 00000000000..3d9ce591450 --- /dev/null +++ b/app/assets/javascripts/usage_quotas/components/sectioned_percentage_bar.vue @@ -0,0 +1,87 @@ +<script> +import { colorFromDefaultPalette } from '@gitlab/ui/dist/utils/charts/theme'; +import { roundOffFloat } from '~/lib/utils/common_utils'; +import { formatNumber } from '~/locale'; + +export default { + props: { + /** + * { + * id: string; + * label: string; + * value: number; + * formattedValue: number | string; + * }[] + */ + sections: { + type: Array, + required: true, + }, + }, + computed: { + sectionsCombinedValue() { + return this.sections.reduce((accumulator, section) => { + return accumulator + section.value; + }, 0); + }, + computedSections() { + return this.sections.map((section, index) => { + const percentage = section.value / this.sectionsCombinedValue; + + return { + ...section, + backgroundColor: colorFromDefaultPalette(index), + cssPercentage: `${roundOffFloat(percentage * 100, 4)}%`, + srLabelPercentage: formatNumber(percentage, { + style: 'percent', + minimumFractionDigits: 1, + }), + }; + }); + }, + }, +}; +</script> + +<template> + <div> + <div class="gl-display-flex gl-rounded-pill gl-overflow-hidden gl-w-full"> + <div + v-for="{ id, label, backgroundColor, cssPercentage, srLabelPercentage } in computedSections" + :key="id" + class="gl-h-5" + :style="{ + backgroundColor, + width: cssPercentage, + }" + :data-testid="`percentage-bar-section-${id}`" + > + <span class="gl-sr-only">{{ label }} {{ srLabelPercentage }}</span> + </div> + </div> + <div class="gl-mt-5"> + <div class="gl-display-flex gl-align-items-center gl-flex-wrap gl-my-n3 gl-mx-n3"> + <div + v-for="{ id, label, backgroundColor, formattedValue } in computedSections" + :key="id" + class="gl-display-flex gl-align-items-center gl-p-3" + :data-testid="`percentage-bar-legend-section-${id}`" + > + <div + class="gl-h-2 gl-w-5 gl-mr-2 gl-display-inline-block" + :style="{ backgroundColor }" + data-testid="legend-section-color" + ></div> + <p class="gl-m-0 gl-font-sm"> + <span class="gl-mr-2 gl-font-weight-bold"> + {{ label }} + </span> + <span class="gl-text-gray-500"> + {{ formattedValue }} + </span> + </p> + </div> + </div> + </div> + </div> +</template> diff --git a/app/controllers/concerns/impersonation.rb b/app/controllers/concerns/impersonation.rb index e562cf5dbe4..aac55af0bac 100644 --- a/app/controllers/concerns/impersonation.rb +++ b/app/controllers/concerns/impersonation.rb @@ -6,7 +6,7 @@ module Impersonation SESSION_KEYS_TO_DELETE = %w[ github_access_token gitea_access_token gitlab_access_token bitbucket_token bitbucket_refresh_token bitbucket_server_personal_access_token - bulk_import_gitlab_access_token fogbugz_token + bulk_import_gitlab_access_token fogbugz_token cloud_platform_access_token ].freeze def current_user diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index 29f94adcc78..42ffe338367 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -38,7 +38,7 @@ module MembersHelper def leave_confirmation_message(member_source) "Are you sure you want to leave the " \ - "\"#{member_source.human_name}\" #{member_source.class.to_s.humanize(capitalize: false)}?" + "\"#{member_source.human_name}\" #{member_source.model_name.to_s.humanize(capitalize: false)}?" end def filter_group_project_member_path(options = {}) diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index 09b0b7a4d9b..6fd5802213a 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -1,7 +1,7 @@ = render 'shared/alerts/positioning_disabled' if @sort == 'relative_position' %ul.content-list.issues-list.issuable-list{ class: issue_manual_ordering_class } - = render partial: "projects/issues/issue", collection: @issues + = render partial: 'projects/issues/service_desk/issue', collection: @issues - if @issues.blank? - empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues') = render empty_state_path diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/service_desk/_issue.html.haml index fc6ef2ea153..65887fbe325 100644 --- a/app/views/projects/issues/_issue.html.haml +++ b/app/views/projects/issues/service_desk/_issue.html.haml @@ -44,7 +44,7 @@ - presented_labels_sorted_by_title(issue.labels, issue.project).each do |label| = link_to_label(label, small: true) - = render "projects/issues/issue_estimate", issue: issue + = render 'projects/issues/service_desk/issue_estimate', issue: issue .issuable-meta %ul.controls diff --git a/app/views/projects/issues/_issue_estimate.html.haml b/app/views/projects/issues/service_desk/_issue_estimate.html.haml index c49bf626f4e..c49bf626f4e 100644 --- a/app/views/projects/issues/_issue_estimate.html.haml +++ b/app/views/projects/issues/service_desk/_issue_estimate.html.haml diff --git a/app/views/projects/issues/service_desk/_service_desk_empty_state.html.haml b/app/views/projects/issues/service_desk/_service_desk_empty_state.html.haml index 1c9143c633d..855625368a9 100644 --- a/app/views/projects/issues/service_desk/_service_desk_empty_state.html.haml +++ b/app/views/projects/issues/service_desk/_service_desk_empty_state.html.haml @@ -6,7 +6,7 @@ - if Gitlab::ServiceDesk.supported? .empty-state .svg-content - = render partial: 'shared/empty_states/icons/service_desk_empty_state', formats: :svg + = render partial: 'projects/issues/service_desk/icons/service_desk_empty_state', formats: :svg .text-content %h4= title_text @@ -25,7 +25,7 @@ - else .empty-state .svg-content - = render partial: 'shared/empty_states/icons/service_desk_setup', formats: :svg + = render partial: 'projects/issues/service_desk/icons/service_desk_setup', formats: :svg .text-content - if can_edit_project_settings %h4= s_('ServiceDesk|Service Desk is not supported') diff --git a/app/views/projects/issues/service_desk/_service_desk_info_content.html.haml b/app/views/projects/issues/service_desk/_service_desk_info_content.html.haml index 2ed5675c0ad..95837748c7f 100644 --- a/app/views/projects/issues/service_desk/_service_desk_info_content.html.haml +++ b/app/views/projects/issues/service_desk/_service_desk_info_content.html.haml @@ -6,7 +6,7 @@ .media.gl-border-b.gl-pb-3.gl-text-left .svg-content - = render partial: 'shared/empty_states/icons/service_desk_callout', formats: :svg + = render partial: 'projects/issues/service_desk/icons/service_desk_callout', formats: :svg .gl-mt-3.gl-ml-3 %h5= title_text diff --git a/app/views/shared/empty_states/icons/_service_desk_callout.svg b/app/views/projects/issues/service_desk/icons/_service_desk_callout.svg index 2886388279e..2886388279e 100644 --- a/app/views/shared/empty_states/icons/_service_desk_callout.svg +++ b/app/views/projects/issues/service_desk/icons/_service_desk_callout.svg diff --git a/app/views/shared/empty_states/icons/_service_desk_empty_state.svg b/app/views/projects/issues/service_desk/icons/_service_desk_empty_state.svg index 04c4870be07..04c4870be07 100644 --- a/app/views/shared/empty_states/icons/_service_desk_empty_state.svg +++ b/app/views/projects/issues/service_desk/icons/_service_desk_empty_state.svg diff --git a/app/views/shared/empty_states/icons/_service_desk_setup.svg b/app/views/projects/issues/service_desk/icons/_service_desk_setup.svg index bb791b58593..bb791b58593 100644 --- a/app/views/shared/empty_states/icons/_service_desk_setup.svg +++ b/app/views/projects/issues/service_desk/icons/_service_desk_setup.svg diff --git a/app/workers/database/batched_background_migration/execution_worker.rb b/app/workers/database/batched_background_migration/execution_worker.rb index 53c92ab8969..1bdc829418a 100644 --- a/app/workers/database/batched_background_migration/execution_worker.rb +++ b/app/workers/database/batched_background_migration/execution_worker.rb @@ -15,6 +15,7 @@ module Database included do data_consistency :always feature_category :database + prefer_calling_context_feature_category true queue_namespace :batched_background_migrations end diff --git a/app/workers/database/batched_background_migration/single_database_worker.rb b/app/workers/database/batched_background_migration/single_database_worker.rb index b7b46937db2..ebf63d34cbf 100644 --- a/app/workers/database/batched_background_migration/single_database_worker.rb +++ b/app/workers/database/batched_background_migration/single_database_worker.rb @@ -16,7 +16,6 @@ module Database included do data_consistency :always feature_category :database - prefer_calling_context_feature_category true idempotent! end @@ -58,39 +57,19 @@ module Database Gitlab::Database::SharedModel.using_connection(base_model.connection) do break unless self.class.enabled? - if parallel_execution_enabled? - migrations = Gitlab::Database::BackgroundMigration::BatchedMigration - .active_migrations_distinct_on_table(connection: base_model.connection, limit: max_running_migrations).to_a + migrations = Gitlab::Database::BackgroundMigration::BatchedMigration + .active_migrations_distinct_on_table(connection: base_model.connection, limit: max_running_migrations).to_a - queue_migrations_for_execution(migrations) if migrations.any? - else - break unless active_migration - - with_exclusive_lease(active_migration.interval) do - run_active_migration - end - end + queue_migrations_for_execution(migrations) if migrations.any? end end private - def parallel_execution_enabled? - Feature.enabled?(:batched_migrations_parallel_execution) - end - def max_running_migrations execution_worker_class.max_running_jobs end - def active_migration - @active_migration ||= Gitlab::Database::BackgroundMigration::BatchedMigration.active_migration(connection: base_model.connection) - end - - def run_active_migration - execution_worker_class.new.perform_work(tracking_database, active_migration.id) - end - def tracking_database self.class.tracking_database end diff --git a/config/feature_flags/development/batched_migrations_parallel_execution.yml b/config/feature_flags/development/batched_migrations_parallel_execution.yml deleted file mode 100644 index 343225a68dc..00000000000 --- a/config/feature_flags/development/batched_migrations_parallel_execution.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: batched_migrations_parallel_execution -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104027 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/384883 -milestone: '15.7' -type: development -group: group::database -default_enabled: true diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md index 06f7203f695..50c4b004f9c 100644 --- a/doc/administration/raketasks/maintenance.md +++ b/doc/administration/raketasks/maintenance.md @@ -350,37 +350,54 @@ status in the output of the `sudo gitlab-rake db:migrate:status` command. sudo gitlab-ctl restart sidekiq ``` -## Rebuild database indexes +## Rebuild database indexes (Experiment) WARNING: -This is an experimental feature that isn't enabled by default. It requires PostgreSQL 12 or later. +This feature is experimental, and isn't enabled by default. Use caution when +running in a production environment, and run during off-peak times. -Database indexes can be rebuilt regularly to reclaim space and maintain healthy levels of index bloat over time. +Database indexes can be rebuilt regularly to reclaim space and maintain healthy +levels of index bloat over time. Reindexing can also be run as a +[regular cron job](https://docs.gitlab.com/omnibus/settings/database.html#automatic-database-reindexing). +A "healthy" level of bloat is highly dependent on the specific index, but generally +should be below 30%. -To rebuild the two indexes with the highest estimated bloat, use the following Rake task: +Prerequisites: -```shell -sudo gitlab-rake gitlab:db:reindex -``` +- This feature requires PostgreSQL 12 or later. +- These index types are not supported: expression indexes, partitioned indexes, + and indexes used for constraint exclusion. -To target a specific index, use the following Rake task: +To manually rebuild a database index: -```shell -sudo gitlab-rake gitlab:db:reindex['public.a_specific_index'] -``` +1. Optional. To send annotations to a Grafana (4.6 or later) endpoint, enable annotations + with these custom environment variables (see [setting custom environment variables](https://docs.gitlab.com/omnibus/settings/environment-variables.html)): + + 1. `GRAFANA_API_URL`: The base URL for Grafana, such as `http://some-host:3000`. + 1. `GRAFANA_API_KEY`: A Grafana API key with at least `Editor role`. + +1. Run the Rake task to rebuild the two indexes with the highest estimated bloat: + + ```shell + sudo gitlab-rake gitlab:db:reindex + ``` -The following index types are not supported: +1. The reindexing task (`gitlab:db:reindex`) rebuilds only the two indexes in each database + with the highest bloat. To rebuild more than two indexes, run the task again + until all desired indexes have been rebuilt. -1. Indexes used for constraint exclusion -1. Partitioned indexes -1. Expression indexes +### Notes -Optionally, this Rake task sends annotations to a Grafana (4.6 or later) endpoint. Use the following custom environment variables to enable annotations: +- Rebuilding database indexes is a disk-intensive task, so you should perform the +task during off-peak hours. Running the task during peak hours can lead to +_increased_ bloat, and can also cause certain queries to perform slowly. -1. `GRAFANA_API_URL` - The base URL for Grafana, for example `http://some-host:3000`. -1. `GRAFANA_API_KEY` - Grafana API key with at least `Editor role`. +- The task requires free disk space for the index being restored. The created +indexes are appended with `_ccnew`. If the reindexing task fails, re-running the +task cleans up the temporary indexes. -You can also [enable reindexing as a regular cron job](https://docs.gitlab.com/omnibus/settings/database.html#automatic-database-reindexing). +- The time it takes for database index rebuilding to complete depends on the size +of the target database. It can take between several hours and several days. ## Import common metrics diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md index 58bdfc7e603..12e0402be25 100644 --- a/doc/ci/secrets/id_token_authentication.md +++ b/doc/ci/secrets/id_token_authentication.md @@ -74,8 +74,6 @@ The token also includes custom claims provided by GitLab: | `runner_id` | Always | ID of the runner executing the job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. | | `runner_environment` | Always | The type of runner used by the job. Can be either `gitlab-hosted` or `self-hosted`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. | | `sha` | Always | The commit SHA for the job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0. | -| `pipeline_ref` | Always | Fully qualified URL for the pipeline definition (e.g. `https://gitlab.example.com/my-group/my-project/-/blob/714a629c0b401fdce83e847fc9589983fc6f46bc/.gitlab-ci.yml`). Might point to a remote location [depending on project configuration](../pipelines/settings.md#specify-a-custom-cicd-configuration-file). | -| `pipeline_sha` | Always | Git commit SHA for the project where the pipeline definition is stored. Only populated when the pipeline definition is stored in the project running the job. | ```json { @@ -103,8 +101,6 @@ The token also includes custom claims provided by GitLab: "runner_id": 1, "runner_environment": "self-hosted", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", - "pipeline_ref": "https://gitlab.example.com/my-group/my-project/-/blob/714a629c0b401fdce83e847fc9589983fc6f46bc/.gitlab-ci.yml", - "pipeline_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "jti": "235b3a54-b797-45c7-ae9a-f72d7bc6ef5b", "iss": "https://gitlab.example.com", "iat": 1681395193, diff --git a/doc/update/background_migrations.md b/doc/update/background_migrations.md index be6ad43fa8a..581bd5ff32a 100644 --- a/doc/update/background_migrations.md +++ b/doc/update/background_migrations.md @@ -207,11 +207,8 @@ Feature.disable(:optimize_batched_migrations) > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104027) > in GitLab 15.7, [behind a feature flag](../user/feature_flags.md), -> [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/372316). -> - Enabled on GitLab.com. -> - Recommended for production use. -> - For GitLab self-managed instances, GitLab administrators can opt to -> [disable it](#enable-or-disable-parallel-execution-for-batched-background-migrations). +> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/372316) in GitLab 15.11. +> - Feature flag `batched_migrations_parallel_execution` removed in GitLab 16.1. There can be [risks when disabling released features](../administration/feature_flags.md#risks-when-disabling-released-features). Refer to this feature's version history for more details. @@ -225,25 +222,6 @@ the number of batched background migrations executed in parallel: ApplicationSetting.update_all(database_max_running_batched_background_migrations: 4) ``` -#### Enable or disable parallel execution for batched background migrations - -Parallel execution for batched background migrations is under development but ready for production use. -It is deployed behind a feature flag that is **enabled by default**. -[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md) -can opt to disable it. - -To enable it: - -```ruby -Feature.enable(:batched_migrations_parallel_execution) -``` - -To disable it: - -```ruby -Feature.disable(:batched_migrations_parallel_execution) -``` - ## Troubleshooting ### Enable or disable background migrations diff --git a/lib/gitlab/ci/jwt_v2.rb b/lib/gitlab/ci/jwt_v2.rb index 34549f4e019..aff30455d09 100644 --- a/lib/gitlab/ci/jwt_v2.rb +++ b/lib/gitlab/ci/jwt_v2.rb @@ -45,30 +45,10 @@ module Gitlab super.merge( runner_id: runner&.id, runner_environment: runner_environment, - sha: pipeline.sha, - pipeline_ref: pipeline_ref, - pipeline_sha: pipeline.repository_source? ? pipeline.sha : nil + sha: pipeline.sha ) end - def pipeline_ref - project_config = Gitlab::Ci::ProjectConfig.new( - project: project, - sha: pipeline.sha, - pipeline_source: pipeline.source&.to_sym, - pipeline_source_bridge: pipeline.source_bridge, - pipeline: pipeline - ) - - project_config&.url - - # Errors are rescued to mitigate risk. This can be removed if no errors are observed. - # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117923#note_1387660746 for context. - rescue StandardError => e - Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, pipeline_id: pipeline.id) - nil - end - def runner_environment return unless runner diff --git a/lib/gitlab/ci/project_config.rb b/lib/gitlab/ci/project_config.rb index 0eed673f266..00b2ad58428 100644 --- a/lib/gitlab/ci/project_config.rb +++ b/lib/gitlab/ci/project_config.rb @@ -21,14 +21,11 @@ module Gitlab ProjectConfig::AutoDevops ].freeze - def initialize( - project:, sha:, custom_content: nil, pipeline_source: nil, - pipeline_source_bridge: nil, pipeline: nil - ) - @config = find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge, pipeline) + def initialize(project:, sha:, custom_content: nil, pipeline_source: nil, pipeline_source_bridge: nil) + @config = find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge) end - delegate :content, :source, :url, to: :@config, allow_nil: true + delegate :content, :source, to: :@config, allow_nil: true delegate :internal_include_prepended?, to: :@config def exists? @@ -37,9 +34,9 @@ module Gitlab private - def find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge, pipeline) + def find_config(project, sha, custom_content, pipeline_source, pipeline_source_bridge) sources.each do |source| - config = source.new(project, sha, custom_content, pipeline_source, pipeline_source_bridge, pipeline) + config = source.new(project, sha, custom_content, pipeline_source, pipeline_source_bridge) return config if config.exists? end diff --git a/lib/gitlab/ci/project_config/auto_devops.rb b/lib/gitlab/ci/project_config/auto_devops.rb index 24e19a1183b..c5f010ebaea 100644 --- a/lib/gitlab/ci/project_config/auto_devops.rb +++ b/lib/gitlab/ci/project_config/auto_devops.rb @@ -21,10 +21,6 @@ module Gitlab :auto_devops_source end - def url - Gitlab::Source.blob_url('lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml') - end - private def template_name diff --git a/lib/gitlab/ci/project_config/bridge.rb b/lib/gitlab/ci/project_config/bridge.rb index 4c64e43b8a5..c342ab2c215 100644 --- a/lib/gitlab/ci/project_config/bridge.rb +++ b/lib/gitlab/ci/project_config/bridge.rb @@ -13,19 +13,6 @@ module Gitlab def source :bridge_source end - - def url - source_pipeline = pipeline_source_bridge.pipeline - - Repository.new( - source_pipeline.project, - source_pipeline.sha, - custom_content, - source_pipeline.source.to_sym, - source_pipeline.source_bridge, - source_pipeline - ).url - end end end end diff --git a/lib/gitlab/ci/project_config/external_project.rb b/lib/gitlab/ci/project_config/external_project.rb index c65d1e658b9..0afdab23886 100644 --- a/lib/gitlab/ci/project_config/external_project.rb +++ b/lib/gitlab/ci/project_config/external_project.rb @@ -25,17 +25,6 @@ module Gitlab :external_project_source end - def url - path_file, path_project, ref = extract_location_tokens - ref ||= 'HEAD' - - namespace, _, project = path_project.partition('/') - return unless namespace.present? && project.present? - - blob = File.join(ref, path_file) - Rails.application.routes.url_helpers.namespace_project_blob_url(namespace, project, blob) - end - private # Example: path/to/.gitlab-ci.yml@another-group/another-project diff --git a/lib/gitlab/ci/project_config/parameter.rb b/lib/gitlab/ci/project_config/parameter.rb index 4a7b68c59e8..69e699c27f1 100644 --- a/lib/gitlab/ci/project_config/parameter.rb +++ b/lib/gitlab/ci/project_config/parameter.rb @@ -15,10 +15,6 @@ module Gitlab def source :parameter_source end - - def url - nil - end end end end diff --git a/lib/gitlab/ci/project_config/remote.rb b/lib/gitlab/ci/project_config/remote.rb index dabb107aee7..19cbf8e9c1e 100644 --- a/lib/gitlab/ci/project_config/remote.rb +++ b/lib/gitlab/ci/project_config/remote.rb @@ -19,10 +19,6 @@ module Gitlab def source :remote_source end - - def url - ci_config_path - end end end end diff --git a/lib/gitlab/ci/project_config/repository.rb b/lib/gitlab/ci/project_config/repository.rb index e5afb2565db..272425fd546 100644 --- a/lib/gitlab/ci/project_config/repository.rb +++ b/lib/gitlab/ci/project_config/repository.rb @@ -20,10 +20,6 @@ module Gitlab :repository_source end - def url - Rails.application.routes.url_helpers.project_blob_url(project, File.join(sha, ci_config_path)) - end - private def file_in_repository? diff --git a/lib/gitlab/ci/project_config/source.rb b/lib/gitlab/ci/project_config/source.rb index 195a77f2f3d..9a4a6394fa1 100644 --- a/lib/gitlab/ci/project_config/source.rb +++ b/lib/gitlab/ci/project_config/source.rb @@ -6,13 +6,12 @@ module Gitlab class Source include Gitlab::Utils::StrongMemoize - def initialize(project, sha, custom_content, pipeline_source, pipeline_source_bridge, pipeline) + def initialize(project, sha, custom_content, pipeline_source, pipeline_source_bridge) @project = project @sha = sha @custom_content = custom_content @pipeline_source = pipeline_source @pipeline_source_bridge = pipeline_source_bridge - @pipeline = pipeline end def exists? @@ -34,14 +33,9 @@ module Gitlab raise NotImplementedError end - # Used to populate the pipeline_ref claim in Ci::JwtV2 - def url - raise NotImplementedError - end - private - attr_reader :project, :sha, :custom_content, :pipeline_source, :pipeline_source_bridge, :pipeline + attr_reader :project, :sha, :custom_content, :pipeline_source, :pipeline_source_bridge def ci_config_path @ci_config_path ||= project.ci_config_path_or_default diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb index a883996a5c5..2c1a14c56f6 100644 --- a/lib/gitlab/database/background_migration/batched_migration.rb +++ b/lib/gitlab/database/background_migration/batched_migration.rb @@ -92,10 +92,6 @@ module Gitlab for_configuration(gitlab_schema, job_class_name, table_name, column_name, job_arguments).first end - def self.active_migration(connection:) - active_migrations_distinct_on_table(connection: connection, limit: 1).first - end - def self.find_executable(id, connection:) for_gitlab_schema(Gitlab::Database.gitlab_schemas_for_connection(connection)) .executable.find_by_id(id) diff --git a/lib/gitlab/source.rb b/lib/gitlab/source.rb index 0944b5cfc51..0e9fb39156d 100644 --- a/lib/gitlab/source.rb +++ b/lib/gitlab/source.rb @@ -19,12 +19,6 @@ module Gitlab Gitlab::Utils.append_path(host_url, path) end - def blob_url(source_file_path) - blob_id = File.join(ref, source_file_path) - - host_url + url_helpers.namespace_project_blob_path(group, project, blob_id) - end - private def host_url diff --git a/spec/frontend/usage_quotas/components/sectioned_percentage_bar_spec.js b/spec/frontend/usage_quotas/components/sectioned_percentage_bar_spec.js new file mode 100644 index 00000000000..22b449c2a70 --- /dev/null +++ b/spec/frontend/usage_quotas/components/sectioned_percentage_bar_spec.js @@ -0,0 +1,101 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue'; + +describe('SectionedPercentageBar', () => { + let wrapper; + + const PERCENTAGE_BAR_SECTION_TESTID_PREFIX = 'percentage-bar-section-'; + const PERCENTAGE_BAR_LEGEND_SECTION_TESTID_PREFIX = 'percentage-bar-legend-section-'; + const LEGEND_SECTION_COLOR_TESTID = 'legend-section-color'; + const SECTION_1 = 'section1'; + const SECTION_2 = 'section2'; + const SECTION_3 = 'section3'; + const SECTION_4 = 'section4'; + + const defaultPropsData = { + sections: [ + { + id: SECTION_1, + label: 'Section 1', + value: 2000, + formattedValue: '1.95 KiB', + }, + { + id: SECTION_2, + label: 'Section 2', + value: 4000, + formattedValue: '3.90 KiB', + }, + { + id: SECTION_3, + label: 'Section 3', + value: 3000, + formattedValue: '2.93 KiB', + }, + { + id: SECTION_4, + label: 'Section 4', + value: 5000, + formattedValue: '4.88 KiB', + }, + ], + }; + + const createComponent = ({ propsData = {} } = {}) => { + wrapper = shallowMountExtended(SectionedPercentageBar, { + propsData: { ...defaultPropsData, ...propsData }, + }); + }; + + it('displays sectioned percentage bar', () => { + createComponent(); + + const section1 = wrapper.findByTestId(PERCENTAGE_BAR_SECTION_TESTID_PREFIX + SECTION_1); + const section2 = wrapper.findByTestId(PERCENTAGE_BAR_SECTION_TESTID_PREFIX + SECTION_2); + const section3 = wrapper.findByTestId(PERCENTAGE_BAR_SECTION_TESTID_PREFIX + SECTION_3); + const section4 = wrapper.findByTestId(PERCENTAGE_BAR_SECTION_TESTID_PREFIX + SECTION_4); + + expect(section1.attributes('style')).toBe( + 'background-color: rgb(97, 122, 226); width: 14.2857%;', + ); + expect(section2.attributes('style')).toBe( + 'background-color: rgb(177, 79, 24); width: 28.5714%;', + ); + expect(section3.attributes('style')).toBe( + 'background-color: rgb(0, 144, 177); width: 21.4286%;', + ); + expect(section4.attributes('style')).toBe( + 'background-color: rgb(54, 104, 0); width: 35.7143%;', + ); + expect(section1.text()).toMatchInterpolatedText('Section 1 14.3%'); + expect(section2.text()).toMatchInterpolatedText('Section 2 28.6%'); + expect(section3.text()).toMatchInterpolatedText('Section 3 21.4%'); + expect(section4.text()).toMatchInterpolatedText('Section 4 35.7%'); + }); + + it('displays sectioned percentage bar legend', () => { + createComponent(); + + const section1 = wrapper.findByTestId(PERCENTAGE_BAR_LEGEND_SECTION_TESTID_PREFIX + SECTION_1); + const section2 = wrapper.findByTestId(PERCENTAGE_BAR_LEGEND_SECTION_TESTID_PREFIX + SECTION_2); + const section3 = wrapper.findByTestId(PERCENTAGE_BAR_LEGEND_SECTION_TESTID_PREFIX + SECTION_3); + const section4 = wrapper.findByTestId(PERCENTAGE_BAR_LEGEND_SECTION_TESTID_PREFIX + SECTION_4); + + expect(section1.text()).toMatchInterpolatedText('Section 1 1.95 KiB'); + expect(section2.text()).toMatchInterpolatedText('Section 2 3.90 KiB'); + expect(section3.text()).toMatchInterpolatedText('Section 3 2.93 KiB'); + expect(section4.text()).toMatchInterpolatedText('Section 4 4.88 KiB'); + expect( + section1.find(`[data-testid="${LEGEND_SECTION_COLOR_TESTID}"]`).attributes('style'), + ).toBe('background-color: rgb(97, 122, 226);'); + expect( + section2.find(`[data-testid="${LEGEND_SECTION_COLOR_TESTID}"]`).attributes('style'), + ).toBe('background-color: rgb(177, 79, 24);'); + expect( + section3.find(`[data-testid="${LEGEND_SECTION_COLOR_TESTID}"]`).attributes('style'), + ).toBe('background-color: rgb(0, 144, 177);'); + expect( + section4.find(`[data-testid="${LEGEND_SECTION_COLOR_TESTID}"]`).attributes('style'), + ).toBe('background-color: rgb(54, 104, 0);'); + }); +}); diff --git a/spec/lib/gitlab/ci/jwt_v2_spec.rb b/spec/lib/gitlab/ci/jwt_v2_spec.rb index a2aa80648b4..528be4b5da7 100644 --- a/spec/lib/gitlab/ci/jwt_v2_spec.rb +++ b/spec/lib/gitlab/ci/jwt_v2_spec.rb @@ -111,79 +111,6 @@ RSpec.describe Gitlab::Ci::JwtV2, feature_category: :continuous_integration do expect(payload[:sha]).to eq(pipeline.sha) end end - - describe 'pipeline_ref' do - let(:project_config) { instance_double(Gitlab::Ci::ProjectConfig, url: url) } - let(:url) { 'https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml' } - - before do - allow(Gitlab::Ci::ProjectConfig).to receive(:new).with( - project: project, - sha: pipeline.sha, - pipeline_source: pipeline.source.to_sym, - pipeline_source_bridge: pipeline.source_bridge, - pipeline: build.pipeline - ).and_return(project_config) - end - - it 'delegates to ProjectConfig#url' do - expect(payload[:pipeline_ref]).to eq(url) - end - - context 'when project config is nil' do - before do - allow(Gitlab::Ci::ProjectConfig).to receive(:new).and_return(nil) - end - - it 'is nil' do - expect(payload[:pipeline_ref]).to be_nil - end - end - - context 'when ProjectConfig#url raises an error' do - before do - allow_next_instance_of(Gitlab::Ci::ProjectConfig) do |instance| - allow(instance).to receive(:url).and_raise(RuntimeError) - end - end - - it 'raises the same error' do - expect { payload }.to raise_error(RuntimeError) - end - - context 'in production' do - before do - stub_rails_env('production') - end - - it 'is nil' do - expect(payload[:pipeline_ref]).to be_nil - end - end - end - end - - describe 'pipeline_sha' do - context 'when pipeline config_source is repository' do - before do - pipeline.config_source = Enums::Ci::Pipeline.config_sources[:repository_source] - end - - it 'is the pipeline\'s sha' do - expect(payload[:pipeline_sha]).to eq(pipeline.sha) - end - end - - context 'when pipeline config_source is not repository' do - before do - pipeline.config_source = Enums::Ci::Pipeline.config_sources[:unknown_source] - end - - it 'is nil' do - expect(payload[:pipeline_sha]).to eq(nil) - end - end - end end end end diff --git a/spec/lib/gitlab/ci/project_config/repository_spec.rb b/spec/lib/gitlab/ci/project_config/repository_spec.rb index d4d6e46152c..e8a997a7e43 100644 --- a/spec/lib/gitlab/ci/project_config/repository_spec.rb +++ b/spec/lib/gitlab/ci/project_config/repository_spec.rb @@ -3,12 +3,11 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::ProjectConfig::Repository, feature_category: :continuous_integration do - let(:files) { { 'README.md' => 'hello' } } let(:project) { create(:project, :custom_repo, files: files) } let(:sha) { project.repository.head_commit.sha } - let(:pipeline) { create(:ci_pipeline, project: project) } + let(:files) { { 'README.md' => 'hello' } } - subject(:config) { described_class.new(project, sha, nil, nil, nil, pipeline) } + subject(:config) { described_class.new(project, sha, nil, nil, nil) } describe '#content' do subject(:content) { config.content } @@ -51,10 +50,4 @@ RSpec.describe Gitlab::Ci::ProjectConfig::Repository, feature_category: :continu it { is_expected.to eq(true) } end - - describe '#url' do - subject { config.url } - - it { is_expected.to eq("#{Settings.gitlab.base_url}/#{project.full_path}/-/blob/#{sha}/.gitlab-ci.yml") } - end end diff --git a/spec/lib/gitlab/ci/project_config/source_spec.rb b/spec/lib/gitlab/ci/project_config/source_spec.rb index 57bb064dce6..eefabe1babb 100644 --- a/spec/lib/gitlab/ci/project_config/source_spec.rb +++ b/spec/lib/gitlab/ci/project_config/source_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Gitlab::Ci::ProjectConfig::Source, feature_category: :continuous_ let_it_be(:project) { build_stubbed(:project) } let_it_be(:sha) { '123456' } - subject(:custom_config) { custom_config_class.new(project, sha, nil, nil, nil, nil) } + subject(:custom_config) { custom_config_class.new(project, sha, nil, nil, nil) } describe '#content' do subject(:content) { custom_config.content } @@ -26,10 +26,4 @@ RSpec.describe Gitlab::Ci::ProjectConfig::Source, feature_category: :continuous_ it { expect(internal_include_prepended).to eq(false) } end - - describe '#url' do - subject(:url) { custom_config.url } - - it { expect { url }.to raise_error(NotImplementedError) } - end end diff --git a/spec/lib/gitlab/ci/project_config_spec.rb b/spec/lib/gitlab/ci/project_config_spec.rb index f00801d62d8..c4b179c9ef5 100644 --- a/spec/lib/gitlab/ci/project_config_spec.rb +++ b/spec/lib/gitlab/ci/project_config_spec.rb @@ -2,9 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_composition do - let_it_be(:project) { create(:project, :empty_repo) } - let_it_be(:pipeline) { create(:ci_pipeline, project: project) } +RSpec.describe Gitlab::Ci::ProjectConfig do + let(:project) { create(:project, :empty_repo, ci_config_path: ci_config_path) } let(:sha) { '123456' } let(:content) { nil } let(:source) { :push } @@ -12,17 +11,12 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio subject(:config) do described_class.new(project: project, sha: sha, - custom_content: content, pipeline_source: source, - pipeline_source_bridge: bridge, pipeline: pipeline) - end - - before do - project.ci_config_path = ci_config_path + custom_content: content, pipeline_source: source, pipeline_source_bridge: bridge) end context 'when bridge job is passed in as parameter' do let(:ci_config_path) { nil } - let(:bridge) { build_stubbed(:ci_bridge) } + let(:bridge) { create(:ci_bridge) } before do allow(bridge).to receive(:yaml_for_downstream).and_return('the-yaml') @@ -32,25 +26,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio expect(config.source).to eq(:bridge_source) expect(config.content).to eq('the-yaml') end - - it 'delegates url to upstream pipeline' do - pipeline = bridge.pipeline - - expected_args = [ - pipeline.project, - pipeline.sha, - nil, - pipeline.source.to_sym, - pipeline.source_bridge, - pipeline - ] - - expect_next_instance_of(Gitlab::Ci::ProjectConfig::Repository, *expected_args) do |instance| - expect(instance).to receive(:url) - end - - config.url - end end context 'when config is defined in a custom path in the repository' do @@ -73,7 +48,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns root config including the local custom file' do expect(config.source).to eq(:repository_source) expect(config.content).to eq(config_content_result) - expect(config.url).to eq("#{Settings.gitlab.base_url}/#{project.full_path}/-/blob/#{sha}/#{ci_config_path}") end end @@ -90,7 +64,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns root config including the remote config' do expect(config.source).to eq(:remote_source) expect(config.content).to eq(config_content_result) - expect(config.url).to eq(ci_config_path) end end @@ -108,9 +81,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns root config including the path to another repository' do expect(config.source).to eq(:external_project_source) expect(config.content).to eq(config_content_result) - expect(config.url).to eq(<<~TEXT.chomp) - #{Settings.gitlab.base_url}/another-group/another-repo/-/blob/HEAD/path/to/.gitlab-ci.yml - TEXT end context 'when path specifies a refname' do @@ -128,17 +98,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns root config including the path and refname to another repository' do expect(config.source).to eq(:external_project_source) expect(config.content).to eq(config_content_result) - expect(config.url).to eq(<<~TEXT.chomp) - #{Settings.gitlab.base_url}/another-group/another-repo/-/blob/refname/path/to/.gitlab-ci.yml - TEXT - end - end - - context 'when config path is malformed' do - let(:ci_config_path) { 'path/to/.gitlab-ci.yml@malformed' } - - it 'returns nil' do - expect(config.url).to be_nil end end end @@ -163,7 +122,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns root config including the canonical CI config file' do expect(config.source).to eq(:repository_source) expect(config.content).to eq(config_content_result) - expect(config.url).to eq("#{Settings.gitlab.base_url}/#{project.full_path}/-/blob/#{sha}/.gitlab-ci.yml") end end @@ -185,12 +143,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio expect(config.source).to eq(:auto_devops_source) expect(config.content).to eq(config_content_result) end - - it 'delegates url to Gitlab::Source' do - expect(Gitlab::Source).to receive(:blob_url).with('lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml') - - config.url - end end context 'when config is passed as a parameter' do @@ -207,7 +159,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns the parameter content' do expect(config.source).to eq(:parameter_source) expect(config.content).to eq(content) - expect(config.url).to be_nil end end @@ -221,7 +172,6 @@ RSpec.describe Gitlab::Ci::ProjectConfig, feature_category: :pipeline_compositio it 'returns nil' do expect(config.source).to be_nil expect(config.content).to be_nil - expect(config.url).to be_nil end end end diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb index 546f9353808..b85a8a93d42 100644 --- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb +++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb @@ -173,52 +173,6 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m end end - describe '.active_migration' do - let(:connection) { Gitlab::Database.database_base_models[:main].connection } - let!(:migration1) { create(:batched_background_migration, :finished) } - - subject(:active_migration) { described_class.active_migration(connection: connection) } - - around do |example| - Gitlab::Database::SharedModel.using_connection(connection) do - example.run - end - end - - context 'when there are no migrations on hold' do - let!(:migration2) { create(:batched_background_migration, :active) } - let!(:migration3) { create(:batched_background_migration, :active) } - - it 'returns the first active migration according to queue order' do - expect(active_migration).to eq(migration2) - end - end - - context 'when there are migrations on hold' do - let!(:migration2) { create(:batched_background_migration, :active, on_hold_until: 10.minutes.from_now) } - let!(:migration3) { create(:batched_background_migration, :active, on_hold_until: 2.minutes.ago) } - - it 'returns the first active migration that is not on hold according to queue order' do - expect(active_migration).to eq(migration3) - end - end - - context 'when there are migrations not available for the current connection' do - let!(:migration2) { create(:batched_background_migration, :active, gitlab_schema: :gitlab_not_existing) } - let!(:migration3) { create(:batched_background_migration, :active, gitlab_schema: :gitlab_main) } - - it 'returns the first active migration that is available for the current connection' do - expect(active_migration).to eq(migration3) - end - end - - context 'when there are no active migrations available' do - it 'returns nil' do - expect(active_migration).to eq(nil) - end - end - end - describe '.find_executable' do let(:connection) { Gitlab::Database.database_base_models[:main].connection } let(:migration_id) { migration.id } diff --git a/spec/lib/gitlab/source_spec.rb b/spec/lib/gitlab/source_spec.rb index d00b946d954..0b2515baf2b 100644 --- a/spec/lib/gitlab/source_spec.rb +++ b/spec/lib/gitlab/source_spec.rb @@ -54,30 +54,4 @@ RSpec.describe Gitlab::Source, feature_category: :shared do end end end - - describe '.blob_url' do - let(:source_file_path) { 'lib/gitlab/source.rb' } - - subject(:blob_url) { described_class.blob_url(source_file_path) } - - context 'when not on a pre-release' do - before do - stub_version('15.0.0-ee', 'a123a123') - end - - it 'returns blob url with tag as ref' do - expect(blob_url).to match("https://gitlab.com/gitlab-org/gitlab(-foss)?/-/blob/v15.0.0-ee/#{source_file_path}") - end - end - - context 'when on a pre-release' do - before do - stub_version('15.0.0-pre', 'a123a123') - end - - it 'returns blob url with commit as ref' do - expect(blob_url).to match("https://gitlab.com/gitlab-org/gitlab(-foss)?/-/blob/a123a123/#{source_file_path}") - end - end - end end diff --git a/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb b/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb index 095c32c3136..8fdd59d1d8c 100644 --- a/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb +++ b/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb @@ -202,6 +202,21 @@ RSpec.shared_examples 'batched background migrations execution worker' do worker.perform_work(database_name, migration.id) end + + it 'assigns proper feature category to the context and the worker' do + # max_value is set to create and execute a batched_job, where we fetch feature_category from the job_class + migration.update!(max_value: create(:event).id) + expect(migration.job_class).to receive(:feature_category).and_return(:code_review_workflow) + + allow_next_instance_of(migration.job_class) do |job_class| + allow(job_class).to receive(:perform) + end + + expect { worker.perform_work(database_name, migration.id) }.to change { + Gitlab::ApplicationContext.current["meta.feature_category"] + }.to('code_review_workflow') + .and change { described_class.get_feature_category }.from(:database).to('code_review_workflow') + end end end end diff --git a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb index 06877aee565..975c7a7447c 100644 --- a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb +++ b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb @@ -64,8 +64,7 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d end it 'does nothing' do - expect(worker).not_to receive(:active_migration) - expect(worker).not_to receive(:run_active_migration) + expect(worker).not_to receive(:queue_migrations_for_execution) expect { worker.perform }.not_to raise_error end @@ -94,8 +93,7 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d end it 'does nothing' do - expect(worker).not_to receive(:active_migration) - expect(worker).not_to receive(:run_active_migration) + expect(worker).not_to receive(:queue_migrations_for_execution) worker.perform end @@ -106,66 +104,47 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d skip_if_shared_database(tracking_database) end - context 'when the feature flag is disabled' do + context 'when the execute_batched_migrations_on_schedule feature flag is disabled' do before do stub_feature_flags(execute_batched_migrations_on_schedule: false) end it 'does nothing' do - expect(worker).not_to receive(:active_migration) - expect(worker).not_to receive(:run_active_migration) + expect(worker).not_to receive(:queue_migrations_for_execution) worker.perform end end - context 'when the feature flag is enabled' do + context 'when the execute_batched_migrations_on_schedule feature flag is enabled' do let(:base_model) { Gitlab::Database.database_base_models[tracking_database] } let(:connection) { base_model.connection } before do stub_feature_flags(execute_batched_migrations_on_schedule: true) - - allow(Gitlab::Database::BackgroundMigration::BatchedMigration).to receive(:active_migration) - .with(connection: connection) - .and_return(nil) end context 'when database config is shared' do it 'does nothing' do expect(Gitlab::Database).to receive(:db_config_share_with) - .with(base_model.connection_db_config).and_return('main') + .with(base_model.connection_db_config).and_return('main') - expect(worker).not_to receive(:active_migration) - expect(worker).not_to receive(:run_active_migration) + expect(worker).not_to receive(:queue_migrations_for_execution) worker.perform end end context 'when no active migrations exist' do - context 'when parallel execution is disabled' do - before do - stub_feature_flags(batched_migrations_parallel_execution: false) - end - - it 'does nothing' do - expect(worker).not_to receive(:run_active_migration) - - worker.perform - end - end - - context 'when parallel execution is enabled' do - before do - stub_feature_flags(batched_migrations_parallel_execution: true) - end + it 'does nothing' do + allow(Gitlab::Database::BackgroundMigration::BatchedMigration) + .to receive(:active_migrations_distinct_on_table) + .with(connection: connection, limit: worker.execution_worker_class.max_running_jobs) + .and_return([]) - it 'does nothing' do - expect(worker).not_to receive(:queue_migrations_for_execution) + expect(worker).not_to receive(:queue_migrations_for_execution) - worker.perform - end + worker.perform end end @@ -190,75 +169,20 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d end end - before do - allow(Gitlab::Database::BackgroundMigration::BatchedMigration).to receive(:active_migration) - .with(connection: connection) - .and_return(migration) - end - - context 'when parallel execution is disabled' do - before do - stub_feature_flags(batched_migrations_parallel_execution: false) - end - - let(:execution_worker) { instance_double(execution_worker_class) } - - context 'when the calculated timeout is less than the minimum allowed' do - let(:minimum_timeout) { described_class::MINIMUM_LEASE_TIMEOUT } - let(:job_interval) { 2.minutes } - - it 'sets the lease timeout to the minimum value' do - expect_to_obtain_exclusive_lease(lease_key, timeout: minimum_timeout) - - expect(execution_worker_class).to receive(:new).and_return(execution_worker) - expect(execution_worker).to receive(:perform_work).with(tracking_database, migration_id) - - expect(worker).to receive(:run_active_migration).and_call_original - - worker.perform - end - end - - it 'always cleans up the exclusive lease' do - lease = stub_exclusive_lease_taken(lease_key, timeout: lease_timeout) - - expect(lease).to receive(:try_obtain).and_return(true) - - expect(worker).to receive(:run_active_migration).and_raise(RuntimeError, 'I broke') - expect(lease).to receive(:cancel) - - expect { worker.perform }.to raise_error(RuntimeError, 'I broke') - end - - it 'delegetes the execution to ExecutionWorker' do - expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(connection).and_yield - expect(execution_worker_class).to receive(:new).and_return(execution_worker) - expect(execution_worker).to receive(:perform_work).with(tracking_database, migration_id) - - worker.perform - end - end - - context 'when parallel execution is enabled' do - before do - stub_feature_flags(batched_migrations_parallel_execution: true) - end - - it 'delegetes the execution to ExecutionWorker' do - expect(Gitlab::Database::BackgroundMigration::BatchedMigration) - .to receive(:active_migrations_distinct_on_table).with( - connection: base_model.connection, - limit: execution_worker_class.max_running_jobs - ).and_return([migration]) + it 'delegetes the execution to ExecutionWorker' do + expect(Gitlab::Database::BackgroundMigration::BatchedMigration) + .to receive(:active_migrations_distinct_on_table).with( + connection: base_model.connection, + limit: execution_worker_class.max_running_jobs + ).and_return([migration]) - expected_arguments = [ - [tracking_database.to_s, migration_id] - ] + expected_arguments = [ + [tracking_database.to_s, migration_id] + ] - expect(execution_worker_class).to receive(:perform_with_capacity).with(expected_arguments) + expect(execution_worker_class).to receive(:perform_with_capacity).with(expected_arguments) - worker.perform - end + worker.perform end end end @@ -266,67 +190,68 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d end end - describe 'executing an entire migration', :freeze_time, if: Gitlab::Database.has_database?(tracking_database) do - include Gitlab::Database::DynamicModelHelpers - include Database::DatabaseHelpers - - let(:migration_class) do - Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) do - job_arguments :matching_status - operation_name :update_all - feature_category :code_review_workflow - - def perform - each_sub_batch( - batching_scope: -> (relation) { relation.where(status: matching_status) } - ) do |sub_batch| - sub_batch.update_all(some_column: 0) + describe 'executing an entire migration', :freeze_time, :sidekiq_inline, + if: Gitlab::Database.has_database?(tracking_database) do + include Gitlab::Database::DynamicModelHelpers + include Database::DatabaseHelpers + + let(:migration_class) do + Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) do + job_arguments :matching_status + operation_name :update_all + feature_category :code_review_workflow + + def perform + each_sub_batch( + batching_scope: -> (relation) { relation.where(status: matching_status) } + ) do |sub_batch| + sub_batch.update_all(some_column: 0) + end end end end - end - let(:gitlab_schema) { "gitlab_#{tracking_database}" } - let!(:migration) do - create( - :batched_background_migration, - :active, - table_name: new_table_name, - column_name: :id, - max_value: migration_records, - batch_size: batch_size, - sub_batch_size: sub_batch_size, - job_class_name: 'ExampleDataMigration', - job_arguments: [1], - gitlab_schema: gitlab_schema - ) - end + let(:gitlab_schema) { "gitlab_#{tracking_database}" } + let!(:migration) do + create( + :batched_background_migration, + :active, + table_name: new_table_name, + column_name: :id, + max_value: migration_records, + batch_size: batch_size, + sub_batch_size: sub_batch_size, + job_class_name: 'ExampleDataMigration', + job_arguments: [1], + gitlab_schema: gitlab_schema + ) + end - let(:base_model) { Gitlab::Database.database_base_models[tracking_database] } - let(:new_table_name) { '_test_example_data' } - let(:batch_size) { 5 } - let(:sub_batch_size) { 2 } - let(:number_of_batches) { 10 } - let(:migration_records) { batch_size * number_of_batches } + let(:base_model) { Gitlab::Database.database_base_models[tracking_database] } + let(:new_table_name) { '_test_example_data' } + let(:batch_size) { 5 } + let(:sub_batch_size) { 2 } + let(:number_of_batches) { 10 } + let(:migration_records) { batch_size * number_of_batches } - let(:connection) { Gitlab::Database.database_base_models[tracking_database].connection } - let(:example_data) { define_batchable_model(new_table_name, connection: connection) } + let(:connection) { Gitlab::Database.database_base_models[tracking_database].connection } + let(:example_data) { define_batchable_model(new_table_name, connection: connection) } - around do |example| - Gitlab::Database::SharedModel.using_connection(connection) do - example.run + around do |example| + Gitlab::Database::SharedModel.using_connection(connection) do + example.run + end end - end - - before do - stub_feature_flags(execute_batched_migrations_on_schedule: true) - # Create example table populated with test data to migrate. - # - # Test data should have two records that won't be updated: - # - one record beyond the migration's range - # - one record that doesn't match the migration job's batch condition - connection.execute(<<~SQL) + before do + stub_feature_flags(execute_batched_migrations_on_schedule: true) + + # Create example table populated with test data to migrate. + # + # Test data should have two records that won't be updated: + # - one record beyond the migration's range + # - one record that doesn't match the migration job's batch condition + connection.execute(<<~SQL) CREATE TABLE #{new_table_name} ( id integer primary key, some_column integer, @@ -339,21 +264,20 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d UPDATE #{new_table_name} SET status = 0 WHERE some_column = #{migration_records - 5}; - SQL + SQL - stub_const('Gitlab::BackgroundMigration::ExampleDataMigration', migration_class) - end + stub_const('Gitlab::BackgroundMigration::ExampleDataMigration', migration_class) + end - subject(:full_migration_run) do - # process all batches, then do an extra execution to mark the job as finished - (number_of_batches + 1).times do - described_class.new.perform + subject(:full_migration_run) do + # process all batches, then do an extra execution to mark the job as finished + (number_of_batches + 1).times do + described_class.new.perform - travel_to((migration.interval + described_class::INTERVAL_VARIANCE).seconds.from_now) + travel_to((migration.interval + described_class::INTERVAL_VARIANCE).seconds.from_now) + end end - end - shared_examples 'batched background migration execution' do it 'marks the migration record as finished' do expect { full_migration_run }.to change { migration.reload.status }.from(1).to(3) # active -> finished end @@ -416,30 +340,4 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d end end end - - context 'when parallel execution is disabled' do - before do - stub_feature_flags(batched_migrations_parallel_execution: false) - end - - it_behaves_like 'batched background migration execution' - - it 'assigns proper feature category to the context and the worker' do - expected_feature_category = migration_class.feature_category.to_s - - expect { full_migration_run }.to change { - Gitlab::ApplicationContext.current["meta.feature_category"] - }.to(expected_feature_category) - .and change { described_class.get_feature_category }.from(:database).to(expected_feature_category) - end - end - - context 'when parallel execution is enabled', :sidekiq_inline do - before do - stub_feature_flags(batched_migrations_parallel_execution: true) - end - - it_behaves_like 'batched background migration execution' - end - end end diff --git a/spec/views/projects/issues/_issue.html.haml_spec.rb b/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb index e4485f253b6..fab872d4019 100644 --- a/spec/views/projects/issues/_issue.html.haml_spec.rb +++ b/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb @@ -2,19 +2,19 @@ require 'spec_helper' -RSpec.describe 'projects/issues/_issue.html.haml' do +RSpec.describe 'projects/issues/service_desk/_issue.html.haml', feature_category: :service_desk do before do assign(:project, issue.project) assign(:issuable_meta_data, { issue.id => Gitlab::IssuableMetadata::IssuableMeta.new(1, 1, 1, 1) }) - render partial: 'projects/issues/issue', locals: { issue: issue } + render partial: 'projects/issues/service_desk/issue', locals: { issue: issue } end describe 'timestamp', :freeze_time do context 'when issue is open' do - let(:issue) { create(:issue, updated_at: 1.day.ago) } + let(:issue) { create(:issue, updated_at: 1.day.ago) } # rubocop:disable RSpec/FactoryBot/AvoidCreate it 'shows last updated date' do expect(rendered).to have_content("updated #{format_timestamp(1.day.ago)}") @@ -22,7 +22,7 @@ RSpec.describe 'projects/issues/_issue.html.haml' do end context 'when issue is closed' do - let(:issue) { create(:issue, :closed, closed_at: 2.days.ago, updated_at: 1.day.ago) } + let(:issue) { create(:issue, :closed, closed_at: 2.days.ago, updated_at: 1.day.ago) } # rubocop:disable RSpec/FactoryBot/AvoidCreate it 'shows closed date' do expect(rendered).to have_content("closed #{format_timestamp(2.days.ago)}") @@ -30,7 +30,7 @@ RSpec.describe 'projects/issues/_issue.html.haml' do end context 'when issue is closed but closed_at is empty' do - let(:issue) { create(:issue, :closed, closed_at: nil, updated_at: 1.day.ago) } + let(:issue) { create(:issue, :closed, closed_at: nil, updated_at: 1.day.ago) } # rubocop:disable RSpec/FactoryBot/AvoidCreate it 'shows last updated date' do expect(rendered).to have_content("updated #{format_timestamp(1.day.ago)}") @@ -40,7 +40,7 @@ RSpec.describe 'projects/issues/_issue.html.haml' do context 'when issue is service desk issue' do let_it_be(:email) { 'user@example.com' } let_it_be(:obfuscated_email) { 'us*****@e*****.c**' } - let_it_be(:issue) { create(:issue, author: User.support_bot, service_desk_reply_to: email) } + let_it_be(:issue) { create(:issue, author: User.support_bot, service_desk_reply_to: email) } # rubocop:disable RSpec/FactoryBot/AvoidCreate context 'with anonymous user' do it 'obfuscates service_desk_reply_to email for anonymous user' do @@ -49,7 +49,7 @@ RSpec.describe 'projects/issues/_issue.html.haml' do end context 'with signed in user' do - let_it_be(:user) { create(:user) } + let_it_be(:user) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate before do allow(view).to receive(:current_user).and_return(user) |