diff options
66 files changed, 412 insertions, 89 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 1671a1da714..1fb1c887e56 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -579,6 +579,7 @@ rspec:skipped-flaky-tests-report: variables: SKIPPED_FLAKY_TESTS_REPORT: skipped_flaky_tests_report.txt before_script: + - 'echo "SKIP_FLAKY_TESTS_AUTOMATICALLY: $SKIP_FLAKY_TESTS_AUTOMATICALLY"' - mkdir -p rspec_flaky script: - find rspec_flaky/ -type f -name 'skipped_flaky_tests_*_report.txt' -exec cat {} + >> "${SKIPPED_FLAKY_TESTS_REPORT}" diff --git a/.gitlab/issue_templates/Empty state.md b/.gitlab/issue_templates/Empty state.md new file mode 100644 index 00000000000..d92ea8522e1 --- /dev/null +++ b/.gitlab/issue_templates/Empty state.md @@ -0,0 +1,80 @@ +<!-- Before implementing a new empty state solution, make sure to read the +Empty State region docs in Pajamas: https://design.gitlab.com/regions/empty-states --> + +## Description + +<!-- Describe the solution you're proposing for your empty state region. +Include links to user research (if applicable). --> + +## Location + +<!-- Provide a link and location of the new empty state solution. +For example: https://gitlab.com/gitlab-org/gitlab-services/design.gitlab.com/-/issues --> + +## Use case + +<!-- What is the use case for the solution you're proposing? +Read the Empty State docs and select the use case below: https://design.gitlab.com/regions/empty-states --> + +- [ ] Blank content +- [ ] Empty search results +- [ ] Configuration required +- [ ] Higher tier + +## Checklist + +<!-- Follow the steps below that correspond with the use case selected above. +Follow the steps to complete this issue --> + +### Blank content + +- [ ] The solution follows the `Blank content` specifications [in Pajamas](https://design.gitlab.com/regions/empty-states#blank-content). +- [ ] Follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. + +### Empty search results + +- [ ] The solution follows the `Empty search results` specifications [in Pajamas](https://design.gitlab.com/regions/empty-states#empty-search-results). +- [ ] Follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. + +### Configuration required + +- [ ] The solution follows the `Configuration required` specifications [in Pajamas](https://design.gitlab.com/regions/empty-states#configuration-required). +- [ ] Ask a [Growth product manager or Designer](https://about.gitlab.com/handbook/engineering/development/growth/#stable-counterparts) to review your solution. +- [ ] Is your solution introducing a new empty states or modifying an existing one? + - [ ] Introducing a new empty state: Follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. + - [ ] Modifying an existing empty state: Follow the [`Experimentation` process](#experimentation) below. _Note_: If the empty state you want to replace hasn't been updated in a long time, doesn't pitch the value of the feature, or does not contain a next step action CTA, then we recommend you skip the experimentation process to implement and add tracking to your new empty state. + +<!-- IF experimentation --> +#### Experimentation + +- [ ] Collaborate with a [Growth product manager](https://about.gitlab.com/handbook/engineering/development/growth/#stable-counterparts) to help you determine if you can validate your solution through an experiment on SaaS. +- [ ] If an experiment is possible, create an issue using the [experiment idea template](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Experiment%20Idea) and follow the template intructions. Otherwise, follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. +- [ ] Ask a [Growth product manager or Designer](https://about.gitlab.com/handbook/engineering/development/growth/#stable-counterparts) to review your experiment set-up. +- [ ] Implement and monitor the experiment following the [implementation guide](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/experiment_guide/gitlab_experiment.md#implement-an-experiment). +- [ ] Review and discuss the findings. +- [ ] Add the findings to the [Growth experimentation knowledge](https://about.gitlab.com/direction/growth/#growth-experiments-knowledge-base---concluded-experiments). + +### Higher tier + +- [ ] The solution follows the `Higher tier` specifications [in Pajamas](https://design.gitlab.com/regions/empty-states#higher-tier). +- [ ] Ask a Product Manager or Designer from the [Conversion group](https://about.gitlab.com/handbook/engineering/development/growth/conversion/#group-members) to review your solution. +- [ ] Is your solution introducing a new empty states or modifying an existing one? + - [ ] Introducing a new empty state: follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. + - [ ] Modifying an existing empty state, follow the [`Experimentation` process](#experimentation) below. + +<!-- IF experimentation --> +#### Experimentation + +- [ ] Collaborate with a [Growth product manager](https://about.gitlab.com/handbook/engineering/development/growth/#stable-counterparts) to help you determine if you can validate your solution through an experiment on SaaS. +- [ ] If an experiment is possible, create an issue using the [experiment idea template](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Experiment%20Idea) and follow the template intructions. Otherwise, follow the instructions from the [`After merge` section](#after-merge) below to add Snowplow tracking. +- [ ] Add a ~"Category:Conversion Experiment" label to the experiment idea issue. +- [ ] Ask a Product Manager or Designer from the [Conversion group](https://about.gitlab.com/handbook/engineering/development/growth/conversion/#group-members) to review your experiment set-up. +- [ ] Implement and monitor the experiment following the [implementation guide](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/experiment_guide/gitlab_experiment.md#implement-an-experiment) . +- [ ] Review and discuss the findings. +- [ ] Add the findings to the [Growth experimentation knowledge](https://about.gitlab.com/direction/growth/#growth-experiments-knowledge-base---concluded-experiments). + + +## After merge + +- [ ] Use the `Snowplow event tracking` [issue template](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Snowplow%20event%20tracking) and open an issue to add Snowplow event tracking to your new empty state solution. + - [ ] Add your ~devops:: and ~group:: labels to the new issue. diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index bc2c01b8e1f..5a277f5259e 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -8f04e23b9f004d70635aaeecd30d837a584572f8 +284a2395b24fcbf1614f486a190379bf42eac6a6 diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 1e780f9ef84..563bed6a6b8 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -83,7 +83,7 @@ export default { :data-item-path="item.referencePath" data-testid="board_card" class="board-card gl-p-5 gl-rounded-base" - @mouseup="toggleIssue($event)" + @click="toggleIssue($event)" > <board-card-inner :list="list" :item="item" :update-filters="true" /> </li> diff --git a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue index dd4b2b23efc..bdb9c2be836 100644 --- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue @@ -160,7 +160,6 @@ export default { icon: 'issues', title: type, type: 'types', - operators: [{ value: '=', description: is }], token: GlFilteredSearchToken, unique: true, options: [ diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb index 70a1a855e91..600516f95a2 100644 --- a/app/controllers/projects/ci/pipeline_editor_controller.rb +++ b/app/controllers/projects/ci/pipeline_editor_controller.rb @@ -19,8 +19,9 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController end def setup_walkthrough_experiment - experiment(:pipeline_editor_walkthrough, actor: current_user) do |e| + experiment(:pipeline_editor_walkthrough, namespace: @project.namespace, sticky_to: current_user) do |e| e.candidate {} + e.record! end end end diff --git a/app/finders/tags_finder.rb b/app/finders/tags_finder.rb index 36ca2c7f281..6bc5419e704 100644 --- a/app/finders/tags_finder.rb +++ b/app/finders/tags_finder.rb @@ -5,9 +5,36 @@ class TagsFinder < GitRefsFinder super(repository, params) end - def execute - tags = repository.tags_sorted_by(sort) + def execute(gitaly_pagination: false) + tags = if gitaly_pagination + repository.tags_sorted_by(sort, pagination_params) + else + repository.tags_sorted_by(sort) + end by_search(tags) + + rescue ArgumentError => e + raise Gitlab::Git::InvalidPageToken, "Invalid page token: #{page_token}" if e.message.include?('page token') + + raise + end + + def total + repository.tag_count + end + + private + + def per_page + params[:per_page].presence + end + + def page_token + "#{Gitlab::Git::TAG_REF_PREFIX}#{@params[:page_token]}" if params[:page_token] + end + + def pagination_params + { limit: per_page, page_token: page_token } end end diff --git a/app/services/ci/job_artifacts/destroy_batch_service.rb b/app/services/ci/job_artifacts/destroy_batch_service.rb index 8faecfbd4ee..866b40c32d8 100644 --- a/app/services/ci/job_artifacts/destroy_batch_service.rb +++ b/app/services/ci/job_artifacts/destroy_batch_service.rb @@ -26,12 +26,15 @@ module Ci def execute(update_stats: true) return success(destroyed_artifacts_count: 0, statistics_updates: {}) if @job_artifacts.empty? + destroy_related_records(@job_artifacts) + Ci::DeletedObject.transaction do Ci::DeletedObject.bulk_import(@job_artifacts, @pick_up_at) Ci::JobArtifact.id_in(@job_artifacts.map(&:id)).delete_all - destroy_related_records(@job_artifacts) end + after_batch_destroy_hook(@job_artifacts) + # This is executed outside of the transaction because it depends on Redis update_project_statistics! if update_stats increment_monitoring_statistics(artifacts_count, artifacts_bytes) @@ -43,9 +46,12 @@ module Ci private - # This method is implemented in EE and it must do only database work + # Overriden in EE def destroy_related_records(artifacts); end + # Overriden in EE + def after_batch_destroy_hook(artifacts); end + # using ! here since this can't be called inside a transaction def update_project_statistics! affected_project_statistics.each do |project, delta| diff --git a/config/feature_flags/development/tag_list_keyset_pagination.yml b/config/feature_flags/development/tag_list_keyset_pagination.yml new file mode 100644 index 00000000000..54bd96d82cf --- /dev/null +++ b/config/feature_flags/development/tag_list_keyset_pagination.yml @@ -0,0 +1,8 @@ +--- +name: tag_list_keyset_pagination +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74239 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345595 +milestone: '14.5' +type: development +group: group::source code +default_enabled: false diff --git a/data/deprecations/14-0-nfs-fot-git-repository-storage.yml b/data/deprecations/14-0-nfs-fot-git-repository-storage.yml index 3127720e709..6884f6e3f69 100644 --- a/data/deprecations/14-0-nfs-fot-git-repository-storage.yml +++ b/data/deprecations/14-0-nfs-fot-git-repository-storage.yml @@ -19,4 +19,4 @@ documentation_url: # (optional) This is a link to the current documentation page image_url: # (optional) This is a link to a thumbnail image depicting the feature video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg - removal_date: "2022-06-22" # (optional - may be required in the future) YYYY-MM-DD format - the date of the milestone release when this feature is planned to be removed + removal_date: "2022-05-22" # (optional - may be required in the future) YYYY-MM-DD format - the date of the milestone release when this feature is planned to be removed diff --git a/data/deprecations/14-2-deprecation-task-runner.yml b/data/deprecations/14-2-deprecation-task-runner.yml index 3c600e5a0bf..52fd1f0f288 100644 --- a/data/deprecations/14-2-deprecation-task-runner.yml +++ b/data/deprecations/14-2-deprecation-task-runner.yml @@ -13,4 +13,4 @@ documentation_url: # (optional) This is a link to the current documentation page image_url: # (optional) This is a link to a thumbnail image depicting the feature video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg - removal_date: "2021-10-22" # (optional - may be required in the future) YYYY-MM-DD format - the date of the milestone release when this feature is planned to be removed + removal_date: "2021-11-22" # (optional - may be required in the future) YYYY-MM-DD format - the date of the milestone release when this feature is planned to be removed diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt index f1caf49e9aa..df228e61278 100644 --- a/doc/.vale/gitlab/spelling-exceptions.txt +++ b/doc/.vale/gitlab/spelling-exceptions.txt @@ -187,6 +187,7 @@ downvotes Dpl Dreamweaver Ecto +ElastiCache Elasticsearch enablement enqueued diff --git a/doc/integration/jira/dvcs.md b/doc/integration/jira/dvcs.md index 68c1f1410ea..2b7cc5ff0a6 100644 --- a/doc/integration/jira/dvcs.md +++ b/doc/integration/jira/dvcs.md @@ -111,12 +111,12 @@ it completes, refreshes every 60 minutes: 1. To create a new integration, select the appropriate value for **Host**: - *For Jira versions 8.14 and later:* Select **GitLab** or **GitLab Self-Managed**. - - *For Jira versions 8.13 and earlier:* Select **GitHub Enterprise**. + - *For Jira Cloud or Jira versions 8.13 and earlier:* Select **GitHub Enterprise**. 1. For **Team or User Account**, enter either: - *For Jira versions 8.14 and later:* - The relative path of a top-level GitLab group that [the GitLab user](#configure-a-gitlab-application-for-dvcs) has access to. - - *For Jira versions 8.13 and earlier:* + - *For Jira Cloud or Jira versions 8.13 and earlier:* - The relative path of a top-level GitLab group that [the GitLab user](#configure-a-gitlab-application-for-dvcs) has access to. - The relative path of your personal namespace. diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md index c0227cca94d..4d6cff96169 100644 --- a/doc/user/discussions/index.md +++ b/doc/user/discussions/index.md @@ -10,7 +10,7 @@ type: reference, howto GitLab encourages communication through comments, threads, and [code suggestions](../project/merge_requests/reviews/suggestions.md). -There are two types of comments: +Two types of comments are available: - A standard comment. - A comment in a thread, which can be [resolved](#resolve-a-thread). @@ -141,8 +141,6 @@ You can also make an [entire issue confidential](../project/issues/confidential_ ## Show only comments -> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/26723) in GitLab 11.5. - For issues and merge requests with many comments, you can filter the page to show comments only. 1. Open a merge request's **Discussion** tab, or epic or issue's **Overview** tab. @@ -170,8 +168,6 @@ You can assign an issue to a user who made a comment. ## Create a thread by replying to a standard comment -> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/30299) in GitLab 11.9. - When you reply to a standard comment, you create a thread. Prerequisites: @@ -185,7 +181,7 @@ To create a thread by replying to a comment: ![Reply to comment button](img/reply_to_comment_button.png) - The reply area is displayed. + The reply section is displayed. 1. Enter your reply. 1. Select **Comment** or **Add comment now** (depending on where in the UI you are replying). @@ -214,8 +210,7 @@ A threaded comment is created. ## Resolve a thread -> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5022) in GitLab 8.11. -> - Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6. +> Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6. In a merge request, you can resolve a thread when you want to finish a conversation. diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 043d6d77f93..1b37d38ef06 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -21,14 +21,17 @@ module API optional :order_by, type: String, values: %w[name updated], default: 'updated', desc: 'Return tags ordered by `name` or `updated` fields.' optional :search, type: String, desc: 'Return list of tags matching the search criteria' + optional :page_token, type: String, desc: 'Name of tag to start the paginaition from' use :pagination end get ':id/repository/tags', feature_category: :source_code_management, urgency: :low do - tags = ::TagsFinder.new(user_project.repository, + tags_finder = ::TagsFinder.new(user_project.repository, sort: "#{params[:order_by]}_#{params[:sort]}", - search: params[:search]).execute + search: params[:search], + page_token: params[:page_token], + per_page: params[:per_page]) - paginated_tags = paginate(::Kaminari.paginate_array(tags)) + paginated_tags = Gitlab::Pagination::GitalyKeysetPager.new(self, user_project).paginate(tags_finder) if Feature.enabled?(:api_caching_tags, user_project, type: :development) present_cached paginated_tags, with: Entities::Tag, project: user_project, cache_context: -> (_tag) { user_project.cache_key } @@ -36,6 +39,8 @@ module API present paginated_tags, with: Entities::Tag, project: user_project end + rescue Gitlab::Git::InvalidPageToken => e + unprocessable_entity!(e.message) rescue Gitlab::Git::CommandError service_unavailable! end diff --git a/lib/gitlab/database/load_balancing/connection_proxy.rb b/lib/gitlab/database/load_balancing/connection_proxy.rb index 9c51fa21936..a91df2eccdd 100644 --- a/lib/gitlab/database/load_balancing/connection_proxy.rb +++ b/lib/gitlab/database/load_balancing/connection_proxy.rb @@ -13,15 +13,14 @@ module Gitlab WriteInsideReadOnlyTransactionError = Class.new(StandardError) READ_ONLY_TRANSACTION_KEY = :load_balacing_read_only_transaction - # The load balancer is intentionally not exposed since the returned instance - # might be different `model.connection.load_balancer` vs `model.load_balancer` + # The load balancer returned by connection might be different + # between `model.connection.load_balancer` vs `model.load_balancer` # # The used `model.connection` is dependent on `use_model_load_balancing`. # See more in: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73949. # # Always use `model.load_balancer` or `model.sticking`. - # - # attr_reader :load_balancer + attr_reader :load_balancer # These methods perform writes after which we need to stick to the # primary. diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index a1855132b0c..2da30b88d55 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -17,6 +17,7 @@ module Gitlab OSError = Class.new(BaseError) UnknownRef = Class.new(BaseError) CommandTimedOut = Class.new(CommandError) + InvalidPageToken = Class.new(BaseError) class << self include Gitlab::EncodingHelper diff --git a/lib/gitlab/pagination/gitaly_keyset_pager.rb b/lib/gitlab/pagination/gitaly_keyset_pager.rb index a16bf7a379c..99a3145104a 100644 --- a/lib/gitlab/pagination/gitaly_keyset_pager.rb +++ b/lib/gitlab/pagination/gitaly_keyset_pager.rb @@ -30,6 +30,8 @@ module Gitlab if finder.is_a?(BranchesFinder) Feature.enabled?(:branch_list_keyset_pagination, project, default_enabled: :yaml) + elsif finder.is_a?(TagsFinder) + Feature.enabled?(:tag_list_keyset_pagination, project, default_enabled: :yaml) elsif finder.is_a?(::Repositories::TreeFinder) Feature.enabled?(:repository_tree_gitaly_pagination, project, default_enabled: :yaml) else @@ -42,6 +44,8 @@ module Gitlab if finder.is_a?(BranchesFinder) Feature.enabled?(:branch_list_keyset_pagination, project, default_enabled: :yaml) + elsif finder.is_a?(TagsFinder) + Feature.enabled?(:tag_list_keyset_pagination, project, default_enabled: :yaml) elsif finder.is_a?(::Repositories::TreeFinder) Feature.enabled?(:repository_tree_gitaly_pagination, project, default_enabled: :yaml) else diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb index b389ac368db..f31262bfcc9 100644 --- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb +++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb @@ -84,7 +84,11 @@ module Gitlab Sidekiq.redis do |redis| redis.multi do |multi| job_wal_locations.each do |connection_name, location| - multi.eval(LUA_SET_WAL_SCRIPT, keys: [wal_location_key(connection_name)], argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL]) + multi.eval( + LUA_SET_WAL_SCRIPT, + keys: [wal_location_key(connection_name)], + argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL] + ) end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c4b0d77b128..792011abb1a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -20748,9 +20748,6 @@ msgstr "" msgid "Licenses|Detected licenses that are out-of-compliance with the project's assigned policies" msgstr "" -msgid "Licenses|Disallow Merge request if detected and will instruct the developer to remove" -msgstr "" - msgid "Licenses|Displays licenses detected in the project, based on the %{linkStart}latest successful%{linkEnd} scan" msgstr "" @@ -20778,6 +20775,9 @@ msgstr "" msgid "Licenses|The license list details information about the licenses used within your project." msgstr "" +msgid "Licenses|Unacceptable license, if detected it will disallow a merge request until it's removed" +msgstr "" + msgid "Licenses|View license details for your project" msgstr "" diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index 51ccf9895c2..8714f1c0060 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -159,6 +159,7 @@ function rspec_paralellized_job() { fi echo "KNAPSACK_TEST_FILE_PATTERN: ${KNAPSACK_TEST_FILE_PATTERN}" + echo "SKIP_FLAKY_TESTS_AUTOMATICALLY: ${SKIP_FLAKY_TESTS_AUTOMATICALLY}" if [[ -d "ee/" ]]; then export KNAPSACK_GENERATE_REPORT="true" diff --git a/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb b/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb index 7952c9774af..d55aad20689 100644 --- a/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb +++ b/spec/controllers/projects/ci/pipeline_editor_controller_spec.rb @@ -42,13 +42,10 @@ RSpec.describe Projects::Ci::PipelineEditorController do project.add_developer(user) end - it 'tracks the assignment', :experiment do - expect(experiment(:pipeline_editor_walkthrough)) - .to track(:assignment) - .with_context(actor: user) - .on_next_instance + subject(:action) { show_request } - show_request + it_behaves_like 'tracks assignment and records the subject', :pipeline_editor_walkthrough, :namespace do + subject { project.namespace } end end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 1354e894872..14c613ff9c4 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -44,7 +44,7 @@ RSpec.describe Projects::PipelinesController do end end - it 'does not execute N+1 queries' do + it 'does not execute N+1 queries', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/345470' do get_pipelines_index_json control_count = ActiveRecord::QueryRecorder.new do diff --git a/spec/finders/tags_finder_spec.rb b/spec/finders/tags_finder_spec.rb index 790e1cad570..acc86547271 100644 --- a/spec/finders/tags_finder_spec.rb +++ b/spec/finders/tags_finder_spec.rb @@ -7,8 +7,8 @@ RSpec.describe TagsFinder do let_it_be(:project) { create(:project, :repository) } let_it_be(:repository) { project.repository } - def load_tags(params) - described_class.new(repository, params).execute + def load_tags(params, gitaly_pagination: false) + described_class.new(repository, params).execute(gitaly_pagination: gitaly_pagination) end describe '#execute' do @@ -96,6 +96,72 @@ RSpec.describe TagsFinder do end end + context 'with Gitaly pagination' do + subject { load_tags(params, gitaly_pagination: true) } + + context 'by page_token and per_page' do + let(:params) { { page_token: 'v1.0.0', per_page: 1 } } + + it 'filters tags' do + result = subject + + expect(result.map(&:name)).to eq(%w(v1.1.0)) + end + end + + context 'by next page_token and per_page' do + let(:params) { { page_token: 'v1.1.0', per_page: 2 } } + + it 'filters branches' do + result = subject + + expect(result.map(&:name)).to eq(%w(v1.1.1)) + end + end + + context 'by per_page only' do + let(:params) { { per_page: 2 } } + + it 'filters branches' do + result = subject + + expect(result.map(&:name)).to eq(%w(v1.0.0 v1.1.0)) + end + end + + context 'by page_token only' do + let(:params) { { page_token: 'feature' } } + + it 'raises an error' do + expect do + subject + end.to raise_error(Gitlab::Git::InvalidPageToken, 'Invalid page token: refs/tags/feature') + end + end + + context 'pagination and sort' do + context 'by per_page' do + let(:params) { { sort: 'updated_desc', per_page: 5 } } + + it 'filters branches' do + result = subject + + expect(result.map(&:name)).to eq(%w(v1.1.1 v1.1.0 v1.0.0)) + end + end + + context 'by page_token and per_page' do + let(:params) { { sort: 'updated_desc', page_token: 'v1.1.1', per_page: 2 } } + + it 'filters branches' do + result = subject + + expect(result.map(&:name)).to eq(%w(v1.1.0 v1.0.0)) + end + end + end + end + context 'when Gitaly is unavailable' do it 'raises an exception' do expect(Gitlab::GitalyClient).to receive(:call).and_raise(GRPC::Unavailable) diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js index 25ec568e48d..5742dfdc5d2 100644 --- a/spec/frontend/boards/components/board_card_spec.js +++ b/spec/frontend/boards/components/board_card_spec.js @@ -64,12 +64,12 @@ describe('Board card', () => { }; const selectCard = async () => { - wrapper.trigger('mouseup'); + wrapper.trigger('click'); await wrapper.vm.$nextTick(); }; const multiSelectCard = async () => { - wrapper.trigger('mouseup', { ctrlKey: true }); + wrapper.trigger('click', { ctrlKey: true }); await wrapper.vm.$nextTick(); }; diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js index bba8b9ecc15..8fcad99f8a7 100644 --- a/spec/frontend/boards/mock_data.js +++ b/spec/frontend/boards/mock_data.js @@ -615,7 +615,6 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, hasEmoji) icon: 'issues', title: __('Type'), type: 'types', - operators: [{ value: '=', description: 'is' }], token: GlFilteredSearchToken, unique: true, options: [ diff --git a/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap index 7044c1285d8..7044c1285d8 100644 --- a/spec/frontend/registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/__snapshots__/registry_breadcrumb_spec.js.snap diff --git a/spec/frontend/registry/explorer/components/delete_button_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js index 6d7bf528495..6d7bf528495 100644 --- a/spec/frontend/registry/explorer/components/delete_button_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_button_spec.js diff --git a/spec/frontend/registry/explorer/components/delete_image_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js index 620c96e8c9e..620c96e8c9e 100644 --- a/spec/frontend/registry/explorer/components/delete_image_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/delete_image_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap index 5f191ef5561..5f191ef5561 100644 --- a/spec/frontend/registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap diff --git a/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js index e25162f4da5..e25162f4da5 100644 --- a/spec/frontend/registry/explorer/components/details_page/delete_alert_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_alert_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js index 16c9485e69e..16c9485e69e 100644 --- a/spec/frontend/registry/explorer/components/details_page/delete_modal_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/delete_modal_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/details_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js index c44f47a6152..f06300efa29 100644 --- a/spec/frontend/registry/explorer/components/details_page/details_header_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/details_header_spec.js @@ -1,11 +1,11 @@ import { GlDropdownItem, GlIcon } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; +import { GlDropdown } from 'jest/packages_and_registries/container_registry/explorer/stubs'; import { useFakeDate } from 'helpers/fake_date'; import createMockApollo from 'helpers/mock_apollo_helper'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import waitForPromises from 'helpers/wait_for_promises'; -import { GlDropdown } from 'jest/registry/explorer/stubs'; import component from '~/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue'; import { UNSCHEDULED_STATUS, diff --git a/spec/frontend/registry/explorer/components/details_page/empty_state_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/empty_state_spec.js index f14284e9efe..f14284e9efe 100644 --- a/spec/frontend/registry/explorer/components/details_page/empty_state_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/empty_state_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js index 1a27481a828..1a27481a828 100644 --- a/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/partial_cleanup_alert_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/status_alert_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js index a11b102d9a6..a11b102d9a6 100644 --- a/spec/frontend/registry/explorer/components/details_page/status_alert_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/status_alert_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js index 00b1d03b7c2..00b1d03b7c2 100644 --- a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js index 9a42c82d7e0..9a42c82d7e0 100644 --- a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js diff --git a/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js index 060dc9dc5f3..060dc9dc5f3 100644 --- a/spec/frontend/registry/explorer/components/details_page/tags_loader_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_loader_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap index 56579847468..56579847468 100644 --- a/spec/frontend/registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap diff --git a/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap index 46b07b4c2d6..46b07b4c2d6 100644 --- a/spec/frontend/registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap diff --git a/spec/frontend/registry/explorer/components/list_page/cleanup_status_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js index e8ddad2d8ca..e8ddad2d8ca 100644 --- a/spec/frontend/registry/explorer/components/list_page/cleanup_status_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cli_commands_spec.js index 4039fba869b..4039fba869b 100644 --- a/spec/frontend/registry/explorer/components/list_page/cli_commands_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cli_commands_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js index 027cdf732bc..027cdf732bc 100644 --- a/spec/frontend/registry/explorer/components/list_page/group_empty_state_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js index 411bef54e40..411bef54e40 100644 --- a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js index e0119954ed4..e0119954ed4 100644 --- a/spec/frontend/registry/explorer/components/list_page/image_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js index 21748ae2813..21748ae2813 100644 --- a/spec/frontend/registry/explorer/components/list_page/project_empty_state_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/project_empty_state_spec.js diff --git a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js index 92cfeb7633e..92cfeb7633e 100644 --- a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js diff --git a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/registry_breadcrumb_spec.js index e5a8438f23f..e5a8438f23f 100644 --- a/spec/frontend/registry/explorer/components/registry_breadcrumb_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/registry_breadcrumb_spec.js diff --git a/spec/frontend/registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js index 6a835a28807..6a835a28807 100644 --- a/spec/frontend/registry/explorer/mock_data.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js index adc9a64e5c9..adc9a64e5c9 100644 --- a/spec/frontend/registry/explorer/pages/details_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js diff --git a/spec/frontend/registry/explorer/pages/index_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/index_spec.js index 5f4cb8969bc..5f4cb8969bc 100644 --- a/spec/frontend/registry/explorer/pages/index_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/index_spec.js diff --git a/spec/frontend/registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js index 8457b51bf63..051d1e2a169 100644 --- a/spec/frontend/registry/explorer/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js @@ -25,7 +25,7 @@ import Tracking from '~/tracking'; import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; import TitleArea from '~/vue_shared/components/registry/title_area.vue'; -import { $toast } from '../../shared/mocks'; +import { $toast } from 'jest/packages_and_registries/shared/mocks'; import { graphQLImageListMock, graphQLImageDeleteMock, diff --git a/spec/frontend/registry/explorer/stubs.js b/spec/frontend/packages_and_registries/container_registry/explorer/stubs.js index 7d281a53a59..7d281a53a59 100644 --- a/spec/frontend/registry/explorer/stubs.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/stubs.js diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js index c56244a9138..5c9ade7f785 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_dropdown_spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import { GlFormGroup, GlFormSelect } from 'jest/registry/shared/stubs'; +import { GlFormGroup, GlFormSelect } from 'jest/packages_and_registries/shared/stubs'; import component from '~/packages_and_registries/settings/project/components/expiration_dropdown.vue'; describe('ExpirationDropdown', () => { diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js index dd876d1d295..6b681924fcf 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_input_spec.js @@ -1,6 +1,6 @@ import { GlSprintf, GlFormInput, GlLink } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import { GlFormGroup } from 'jest/registry/shared/stubs'; +import { GlFormGroup } from 'jest/packages_and_registries/shared/stubs'; import component from '~/packages_and_registries/settings/project/components/expiration_input.vue'; import { NAME_REGEX_LENGTH } from '~/packages_and_registries/settings/project/constants'; diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js index 854830391c5..94f7783afe7 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_run_text_spec.js @@ -1,6 +1,6 @@ import { GlFormInput } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import { GlFormGroup } from 'jest/registry/shared/stubs'; +import { GlFormGroup } from 'jest/packages_and_registries/shared/stubs'; import component from '~/packages_and_registries/settings/project/components/expiration_run_text.vue'; import { NEXT_CLEANUP_LABEL, diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js index 3a3eb089b43..45039614e49 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/expiration_toggle_spec.js @@ -1,6 +1,6 @@ import { GlToggle, GlSprintf } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import { GlFormGroup } from 'jest/registry/shared/stubs'; +import { GlFormGroup } from 'jest/packages_and_registries/shared/stubs'; import component from '~/packages_and_registries/settings/project/components/expiration_toggle.vue'; import { ENABLED_TOGGLE_DESCRIPTION, diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js index 3a71af94d5a..bc104a25ef9 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js @@ -2,7 +2,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { GlCard, GlLoadingIcon } from 'jest/registry/shared/stubs'; +import { GlCard, GlLoadingIcon } from 'jest/packages_and_registries/shared/stubs'; import component from '~/packages_and_registries/settings/project/components/settings_form.vue'; import { UPDATE_SETTINGS_ERROR_MESSAGE, diff --git a/spec/frontend/registry/shared/mocks.js b/spec/frontend/packages_and_registries/shared/mocks.js index fdef38b6f10..fdef38b6f10 100644 --- a/spec/frontend/registry/shared/mocks.js +++ b/spec/frontend/packages_and_registries/shared/mocks.js diff --git a/spec/frontend/registry/shared/stubs.js b/spec/frontend/packages_and_registries/shared/stubs.js index ad41eb42df4..ad41eb42df4 100644 --- a/spec/frontend/registry/shared/stubs.js +++ b/spec/frontend/packages_and_registries/shared/stubs.js diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb index d3af4590b3a..833de6ae624 100644 --- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb +++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb @@ -174,26 +174,21 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi end describe '#update_latest_wal_location!' do - let(:offset) { '1024' } - before do - allow(duplicate_job).to receive(:pg_wal_lsn_diff).with(:main).and_return(offset) - allow(duplicate_job).to receive(:pg_wal_lsn_diff).with(:ci).and_return(offset) - end + allow(Gitlab::Database).to receive(:database_base_models).and_return( + { main: ::ActiveRecord::Base, + ci: ::ActiveRecord::Base }) - shared_examples 'updates wal location' do - it 'updates a wal location to redis with an offset' do - expect { duplicate_job.update_latest_wal_location! } - .to change { read_range_from_redis(wal_location_key(idempotency_key, :main)) } - .from(existing_wal_with_offset[:main]) - .to(new_wal_with_offset[:main]) - .and change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) } - .from(existing_wal_with_offset[:ci]) - .to(new_wal_with_offset[:ci]) - end + set_idempotency_key(existing_wal_location_key(idempotency_key, :main), existing_wal[:main]) + set_idempotency_key(existing_wal_location_key(idempotency_key, :ci), existing_wal[:ci]) + + # read existing_wal_locations + duplicate_job.check! end context 'when preserve_latest_wal_locations_for_idempotent_jobs feature flag is disabled' do + let(:existing_wal) { {} } + before do stub_feature_flags(preserve_latest_wal_locations_for_idempotent_jobs: false) end @@ -214,42 +209,107 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi end context "when the key doesn't exists in redis" do - include_examples 'updates wal location' do - let(:existing_wal_with_offset) { { main: [], ci: [] } } - let(:new_wal_with_offset) { wal_locations.transform_values { |v| [v, offset] } } + let(:existing_wal) do + { + main: '0/D525E3A0', + ci: 'AB/12340' + } end - end - context "when the key exists in redis" do - let(:existing_offset) { '1023'} - let(:existing_wal_locations) do + let(:new_wal_location_with_offset) do { - main: '0/D525E3NM', - ci: 'AB/111112' + # offset is relative to `existing_wal` + main: ['0/D525E3A8', '8'], + ci: ['AB/12345', '5'] } end + let(:wal_locations) { new_wal_location_with_offset.transform_values(&:first) } + + it 'stores a wal location to redis with an offset relative to existing wal location' do + expect { duplicate_job.update_latest_wal_location! } + .to change { read_range_from_redis(wal_location_key(idempotency_key, :main)) } + .from([]) + .to(new_wal_location_with_offset[:main]) + .and change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) } + .from([]) + .to(new_wal_location_with_offset[:ci]) + end + end + + context "when the key exists in redis" do before do - rpush_to_redis_key(wal_location_key(idempotency_key, :main), existing_wal_locations[:main], existing_offset) - rpush_to_redis_key(wal_location_key(idempotency_key, :ci), existing_wal_locations[:ci], existing_offset) + rpush_to_redis_key(wal_location_key(idempotency_key, :main), *stored_wal_location_with_offset[:main]) + rpush_to_redis_key(wal_location_key(idempotency_key, :ci), *stored_wal_location_with_offset[:ci]) end + let(:wal_locations) { new_wal_location_with_offset.transform_values(&:first) } + context "when the new offset is bigger then the existing one" do - include_examples 'updates wal location' do - let(:existing_wal_with_offset) { existing_wal_locations.transform_values { |v| [v, existing_offset] } } - let(:new_wal_with_offset) { wal_locations.transform_values { |v| [v, offset] } } + let(:existing_wal) do + { + main: '0/D525E3A0', + ci: 'AB/12340' + } + end + + let(:stored_wal_location_with_offset) do + { + # offset is relative to `existing_wal` + main: ['0/D525E3A3', '3'], + ci: ['AB/12342', '2'] + } + end + + let(:new_wal_location_with_offset) do + { + # offset is relative to `existing_wal` + main: ['0/D525E3A8', '8'], + ci: ['AB/12345', '5'] + } + end + + it 'updates a wal location to redis with an offset' do + expect { duplicate_job.update_latest_wal_location! } + .to change { read_range_from_redis(wal_location_key(idempotency_key, :main)) } + .from(stored_wal_location_with_offset[:main]) + .to(new_wal_location_with_offset[:main]) + .and change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) } + .from(stored_wal_location_with_offset[:ci]) + .to(new_wal_location_with_offset[:ci]) end end context "when the old offset is not bigger then the existing one" do - let(:existing_offset) { offset } + let(:existing_wal) do + { + main: '0/D525E3A0', + ci: 'AB/12340' + } + end + + let(:stored_wal_location_with_offset) do + { + # offset is relative to `existing_wal` + main: ['0/D525E3A8', '8'], + ci: ['AB/12345', '5'] + } + end + + let(:new_wal_location_with_offset) do + { + # offset is relative to `existing_wal` + main: ['0/D525E3A2', '2'], + ci: ['AB/12342', '2'] + } + end it "does not update a wal location to redis with an offset" do expect { duplicate_job.update_latest_wal_location! } .to not_change { read_range_from_redis(wal_location_key(idempotency_key, :main)) } - .from([existing_wal_locations[:main], existing_offset]) + .from(stored_wal_location_with_offset[:main]) .and not_change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) } - .from([existing_wal_locations[:ci], existing_offset]) + .from(stored_wal_location_with_offset[:ci]) end end end @@ -619,12 +679,12 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi end end - def existing_wal_location_key(idempotency_key, config_name) - "#{idempotency_key}:#{config_name}:existing_wal_location" + def existing_wal_location_key(idempotency_key, connection_name) + "#{idempotency_key}:#{connection_name}:existing_wal_location" end - def wal_location_key(idempotency_key, config_name) - "#{idempotency_key}:#{config_name}:wal_location" + def wal_location_key(idempotency_key, connection_name) + "#{idempotency_key}:#{connection_name}:wal_location" end def set_idempotency_key(key, value = '1') diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index cf58809f7cd..bb56192a2ff 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -17,6 +17,10 @@ RSpec.describe API::Tags do end describe 'GET /projects/:id/repository/tags' do + before do + stub_feature_flags(tag_list_keyset_pagination: false) + end + shared_examples "get repository tags" do let(:route) { "/projects/#{project_id}/repository/tags" } @@ -143,6 +147,55 @@ RSpec.describe API::Tags do expect(expected_tag['release']['description']).to eq(description) end end + + context 'with keyset pagination on', :aggregate_errors do + before do + stub_feature_flags(tag_list_keyset_pagination: true) + end + + context 'with keyset pagination option' do + let(:base_params) { { pagination: 'keyset' } } + + context 'with gitaly pagination params' do + context 'with high limit' do + let(:params) { base_params.merge(per_page: 100) } + + it 'returns all repository tags' do + get api(route, user), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/tags') + expect(response.headers).not_to include('Link') + tag_names = json_response.map { |x| x['name'] } + expect(tag_names).to match_array(project.repository.tag_names) + end + end + + context 'with low limit' do + let(:params) { base_params.merge(per_page: 2) } + + it 'returns limited repository tags' do + get api(route, user), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/tags') + expect(response.headers).to include('Link') + tag_names = json_response.map { |x| x['name'] } + expect(tag_names).to match_array(%w(v1.1.0 v1.1.1)) + end + end + + context 'with missing page token' do + let(:params) { base_params.merge(page_token: 'unknown') } + + it_behaves_like '422 response' do + let(:request) { get api(route, user), params: params } + let(:message) { 'Invalid page token: refs/tags/unknown' } + end + end + end + end + end end context ":api_caching_tags flag enabled", :use_clean_rails_memory_store_caching do diff --git a/spec/support/database/cross-database-modification-allowlist.yml b/spec/support/database/cross-database-modification-allowlist.yml index e4dc958830f..d05812a64eb 100644 --- a/spec/support/database/cross-database-modification-allowlist.yml +++ b/spec/support/database/cross-database-modification-allowlist.yml @@ -13,7 +13,6 @@ - "./ee/spec/services/ci/subscribe_bridge_service_spec.rb" - "./ee/spec/services/deployments/auto_rollback_service_spec.rb" - "./ee/spec/services/ee/ci/job_artifacts/destroy_all_expired_service_spec.rb" -- "./ee/spec/services/ee/ci/job_artifacts/destroy_batch_service_spec.rb" - "./ee/spec/services/ee/users/destroy_service_spec.rb" - "./ee/spec/services/projects/transfer_service_spec.rb" - "./ee/spec/services/security/security_orchestration_policies/rule_schedule_service_spec.rb" @@ -76,7 +75,6 @@ - "./spec/services/ci/expire_pipeline_cache_service_spec.rb" - "./spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb" - "./spec/services/ci/job_artifacts/destroy_associations_service_spec.rb" -- "./spec/services/ci/job_artifacts/destroy_batch_service_spec.rb" - "./spec/services/ci/pipeline_bridge_status_service_spec.rb" - "./spec/services/ci/pipelines/add_job_service_spec.rb" - "./spec/services/ci/retry_build_service_spec.rb" diff --git a/spec/support/flaky_tests.rb b/spec/support/flaky_tests.rb index 535df64f890..30a064d8705 100644 --- a/spec/support/flaky_tests.rb +++ b/spec/support/flaky_tests.rb @@ -4,7 +4,7 @@ return unless ENV['CI'] return unless ENV['SKIP_FLAKY_TESTS_AUTOMATICALLY'] == "true" return if ENV['CI_MERGE_REQUEST_LABELS'].to_s.include?('pipeline:run-flaky-tests') -require_relative '../tooling/rspec_flaky/report' +require_relative '../../tooling/rspec_flaky/report' RSpec.configure do |config| $flaky_test_example_ids = begin # rubocop:disable Style/GlobalVars diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb index b2d50599264..40843ccbd15 100644 --- a/spec/support/shared_examples/requests/api/status_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb @@ -77,6 +77,24 @@ RSpec.shared_examples '412 response' do end end +RSpec.shared_examples '422 response' do + let(:message) { nil } + + before do + # Fires the request + request + end + + it 'returns 422' do + expect(response).to have_gitlab_http_status(:unprocessable_entity) + expect(json_response).to be_an Object + + if message.present? + expect(json_response['message']).to eq(message) + end + end +end + RSpec.shared_examples '503 response' do before do # Fires the request |