diff options
Diffstat (limited to 'qa/qa/specs/features/api/1_manage')
18 files changed, 362 insertions, 99 deletions
diff --git a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb index 7d3916641aa..bf95a215c8e 100644 --- a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb @@ -40,9 +40,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' } - ]) + commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }]) end end.not_to raise_error end diff --git a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb index df34bf32421..c3e41e9298b 100644 --- a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb @@ -3,7 +3,7 @@ module QA # Spec uses real github.com, which means outage of github.com can actually block deployment # Keep spec in reliable bucket but don't run in blocking pipelines - RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin do + RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin, product_group: :import do describe 'Project import', issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353583' do let!(:api_client) { Runtime::API::Client.as_admin } let!(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } @@ -20,7 +20,9 @@ module QA project.group = group project.github_personal_access_token = Runtime::Env.github_access_token project.github_repository_path = 'gitlab-qa-github/import-test' - project.api_client = api_client + project.api_client = Runtime::API::Client.new(user: user) + project.issue_events_import = true + project.full_notes_import = true end end @@ -41,6 +43,7 @@ module QA aggregate_failures do verify_status_data verify_repository_import + verify_protected_branches_import verify_commits_import verify_labels_import verify_issues_import @@ -53,7 +56,7 @@ module QA def verify_status_data stats = imported_project.project_import_status.dig(:stats, :imported) expect(stats).to include( - # issue: 2, + issue: 1, label: 9, milestone: 1, note: 3, @@ -69,6 +72,21 @@ module QA expect(imported_project.api_response[:import_error]).to be_nil end + def verify_protected_branches_import + branches = imported_project.protected_branches.map do |branch| + branch.slice(:name, :allow_force_push, :code_owner_approval_required) + end + expect(branches.first).to include( + { + name: 'main' + # TODO: Add validation once https://gitlab.com/groups/gitlab-org/-/epics/8585 is closed + # At the moment both options are always set to false regardless of state in github + # allow_force_push: true, + # code_owner_approval_required: true + } + ) + end + def verify_commits_import expect(imported_project.commits.length).to eq(2) end @@ -122,7 +140,7 @@ module QA mr.iid = merge_requests.first[:iid] mr.api_client = api_client end.reload! - mr_comments = merge_request.comments.map { |comment| comment[:body] } # rubocop:disable Rails/Pluck + mr_comments = merge_request.comments.map { |comment| comment[:body] } expect(merge_requests.length).to eq(1) expect(merge_request.api_resource).to include( diff --git a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb index e6b60a5b090..5acf15dd2b4 100644 --- a/qa/qa/specs/features/api/1_manage/import_large_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb @@ -1,21 +1,82 @@ # frozen_string_literal: true +require "etc" + # Lifesize project import test executed from https://gitlab.com/gitlab-org/manage/import/import-metrics # rubocop:disable Rails/Pluck module QA RSpec.describe 'Manage', :github, requires_admin: 'creates users', only: { job: 'large-github-import' } do - describe 'Project import' do + describe 'Project import', product_group: :import do # rubocop:disable RSpec/MultipleMemoizedHelpers + let(:github_repo) { ENV['QA_LARGE_IMPORT_REPO'] || 'rspec/rspec-core' } + let(:import_max_duration) { ENV['QA_LARGE_IMPORT_DURATION']&.to_i || 7200 } let(:logger) { Runtime::Logger.logger } let(:differ) { RSpec::Support::Differ.new(color: true) } - let(:gitlab_address) { QA::Runtime::Scenario.gitlab_address } + let(:gitlab_address) { QA::Runtime::Scenario.gitlab_address.chomp("/") } let(:dummy_url) { "https://example.com" } + let(:api_request_params) { { auto_paginate: true, attempts: 2 } } let(:created_by_pattern) { /\*Created by: \S+\*\n\n/ } let(:suggestion_pattern) { /suggestion:-\d+\+\d+/ } let(:gh_link_pattern) { %r{https://github.com/#{github_repo}/(issues|pull)} } let(:gl_link_pattern) { %r{#{gitlab_address}/#{imported_project.path_with_namespace}/-/(issues|merge_requests)} } - let(:event_pattern) { %r{(un)?assigned( to)? @\S+|mentioned in (issue|merge request) [!#]\d+|changed title from \*\*.*\*\* to \*\*.*\*\*} } # rubocop:disable Layout/LineLength + # rubocop:disable Lint/MixedRegexpCaptureTypes + let(:event_pattern) do + Regexp.union( + [ + /(?<event>(un)?assigned)( to)? @\S+/, + /(?<event>mentioned) in (issue|merge request) [!#]\d+/, + /(?<event>changed title) from \*\*.*\*\* to \*\*.*\*\*/, + /(?<event>requested review) from @\w+/, + /\*(?<event>Merged) by:/, + /\*\*(Review):\*\*/ + ] + ) + end + # rubocop:enable Lint/MixedRegexpCaptureTypes + + # mapping from gitlab to github names + let(:event_mapping) do + { + "label_add" => "labeled", + "label_remove" => "unlabeled", + "milestone_add" => "milestoned", + "milestone_remove" => "demilestoned", + "assigned" => "assigned", + "unassigned" => "unassigned", + "changed title" => "renamed", + "requested review" => "review_requested", + "Merged" => "merged" + } + end + + # github events that are not migrated or are not correctly mapable in gitlab + let(:unsupported_events) do + [ + "head_ref_deleted", + "head_ref_force_pushed", + "head_ref_restored", + "base_ref_force_pushed", + "base_ref_changed", + "review_request_removed", + "review_dismissed", + "auto_squash_enabled", + "auto_merge_disabled", + "comment_deleted", + "convert_to_draft", + "ready_for_review", + "subscribed", + "unsubscribed", + "transferred", + "locked", + "unlocked", + # mentions are supported but they can be reported differently on gitlab's side + # for example mention of issue creation in pr will be reported in the issue on gitlab side + # or referenced in github will still create a 'mentioned in' comment in gitlab + "referenced", + "mentioned" + ] + end let(:api_client) { Runtime::API::Client.as_admin } @@ -25,79 +86,105 @@ module QA end end - let(:github_repo) { ENV['QA_LARGE_IMPORT_REPO'] || 'rspec/rspec-core' } - let(:import_max_duration) { ENV['QA_LARGE_IMPORT_DURATION'] ? ENV['QA_LARGE_IMPORT_DURATION'].to_i : 7200 } let(:github_client) do Octokit::Client.new( access_token: ENV['QA_LARGE_IMPORT_GH_TOKEN'] || Runtime::Env.github_access_token, - auto_paginate: true + auto_paginate: true, + middleware: Faraday::RackBuilder.new do |builder| + builder.use(Faraday::Retry::Middleware, exceptions: [Octokit::InternalServerError, Octokit::ServerError]) + end ) end let(:gh_repo) { github_client.repository(github_repo) } let(:gh_branches) do - logger.debug("= Fetching branches =") + logger.info("= Fetching branches =") github_client.branches(github_repo).map(&:name) end let(:gh_commits) do - logger.debug("= Fetching commits =") + logger.info("= Fetching commits =") github_client.commits(github_repo).map(&:sha) end let(:gh_labels) do - logger.debug("= Fetching labels =") + logger.info("= Fetching labels =") github_client.labels(github_repo).map { |label| { name: label.name, color: "##{label.color}" } } end let(:gh_milestones) do - logger.debug("= Fetching milestones =") + logger.info("= Fetching milestones =") github_client .list_milestones(github_repo, state: 'all') .map { |ms| { title: ms.title, description: ms.description } } end - let(:gh_all_issues) do - logger.debug("= Fetching issues and prs =") - github_client.list_issues(github_repo, state: 'all') - end - let(:gh_prs) do gh_all_issues.select(&:pull_request).each_with_object({}) do |pr, hash| - hash[pr.number] = { + id = pr.number + hash[id] = { url: pr.html_url, title: pr.title, body: pr.body || '', - comments: [*gh_pr_comments[pr.html_url], *gh_issue_comments[pr.html_url]].compact + comments: [*gh_pr_comments[id], *gh_issue_comments[id]].compact, + events: gh_pr_events[id].reject { |event| unsupported_events.include?(event) } } end end let(:gh_issues) do gh_all_issues.reject(&:pull_request).each_with_object({}) do |issue, hash| - hash[issue.number] = { + id = issue.number + hash[id] = { url: issue.html_url, title: issue.title, body: issue.body || '', - comments: gh_issue_comments[issue.html_url] + comments: gh_issue_comments[id], + events: gh_issue_events[id].reject { |event| unsupported_events.include?(event) } } end end + let(:gh_all_issues) do + logger.info("= Fetching issues and prs =") + github_client.list_issues(github_repo, state: 'all') + end + + let(:gh_all_events) do + logger.info("- Fetching issue and pr events -") + github_client.repository_issue_events(github_repo).map do |event| + { name: event[:event], **(event[:issue] || {}) } # some events don't have issue object at all + end + end + + let(:gh_issue_events) do + gh_all_events.each_with_object(Hash.new { |h, k| h[k] = [] }) do |event, hash| + next if event[:pull_request] || !event[:number] + + hash[event[:number]] << event[:name] + end + end + + let(:gh_pr_events) do + gh_all_events.each_with_object(Hash.new { |h, k| h[k] = [] }) do |event, hash| + next unless event[:pull_request] + + hash[event[:number]] << event[:name] + end + end + let(:gh_issue_comments) do - logger.debug("= Fetching issue comments =") + logger.info("- Fetching issue comments -") github_client.issues_comments(github_repo).each_with_object(Hash.new { |h, k| h[k] = [] }) do |c, hash| - # use base html url as key - hash[c.html_url.gsub(/\#\S+/, "")] << c.body&.gsub(gh_link_pattern, dummy_url) + hash[id_from_url(c.html_url)] << c.body&.gsub(gh_link_pattern, dummy_url) end end let(:gh_pr_comments) do - logger.debug("= Fetching pr comments =") + logger.info("- Fetching pr comments -") github_client.pull_requests_comments(github_repo).each_with_object(Hash.new { |h, k| h[k] = [] }) do |c, hash| - # use base html url as key - hash[c.html_url.gsub(/\#\S+/, "")] << c.body + hash[id_from_url(c.html_url)] << c.body # some suggestions can contain extra whitespaces which gitlab will remove &.gsub(/suggestion\s+\r/, "suggestion\r") &.gsub(gh_link_pattern, dummy_url) @@ -111,11 +198,12 @@ module QA project.github_personal_access_token = Runtime::Env.github_access_token project.github_repository_path = github_repo project.personal_namespace = user.username - project.api_client = api_client + project.api_client = Runtime::API::Client.new(user: user) + project.issue_events_import = true + project.full_notes_import = true end end - # rubocop:disable RSpec/InstanceVariable after do |example| next unless defined?(@import_time) @@ -138,8 +226,10 @@ module QA milestones: gh_milestones.length, mrs: gh_prs.length, mr_comments: gh_prs.sum { |_k, v| v[:comments].length }, + mr_events: gh_prs.sum { |_k, v| v[:events].length }, issues: gh_issues.length, - issue_comments: gh_issues.sum { |_k, v| v[:comments].length } + issue_comments: gh_issues.sum { |_k, v| v[:comments].length }, + issue_events: gh_issues.sum { |_k, v| v[:events].length } } }, target: { @@ -153,8 +243,10 @@ module QA milestones: gl_milestones.length, mrs: mrs.length, mr_comments: mrs.sum { |_k, v| v[:comments].length }, + mr_events: mrs.sum { |_k, v| v[:events].length }, issues: gl_issues.length, - issue_comments: gl_issues.sum { |_k, v| v[:comments].length } + issue_comments: gl_issues.sum { |_k, v| v[:comments].length }, + issue_events: gl_issues.sum { |_k, v| v[:events].length } } }, not_imported: { @@ -164,7 +256,6 @@ module QA } ) end - # rubocop:enable RSpec/InstanceVariable it( 'imports large Github repo via api', @@ -172,8 +263,9 @@ module QA ) do start = Time.now - # import the project and log gitlab path - logger.info("== Importing project '#{github_repo}' in to '#{imported_project.reload!.full_path}' ==") + # trigger import and log project paths + logger.info("== Triggering import of project '#{github_repo}' in to '#{imported_project.reload!.full_path}' ==") + # fetch all objects right after import has started fetch_github_objects @@ -182,7 +274,7 @@ module QA @stats = status.dig(:stats, :imported) # fail fast if import explicitly failed - raise "Import of '#{imported_project.name}' failed!" if status[:import_status] == 'failed' + raise "Import of '#{imported_project.full_path}' failed!" if status[:import_status] == 'failed' status[:import_status] end @@ -276,25 +368,26 @@ module QA count_msg = "Expected to contain same amount of #{type}s. Gitlab: #{expected.length}, Github: #{actual.length}" expect(expected.length).to eq(actual.length), count_msg - missing_comments = verify_comments(type, actual, expected) + missing_objects = (actual.keys - expected.keys).map { |it| actual[it].slice(:title, :url) } + missing_content = verify_comments_and_events(type, actual, expected) { - "#{type}s": (actual.keys - expected.keys).map { |it| actual[it].slice(:title, :url) }, - "#{type}_comments": missing_comments - } + "#{type}s": missing_objects.empty? ? nil : missing_objects, + "#{type}_content": missing_content.empty? ? nil : missing_content + }.compact end - # Verify imported comments + # Verify imported comments and events # # @param [String] type verification object, 'mrs' or 'issues' # @param [Hash] actual # @param [Hash] expected # @return [Hash] - def verify_comments(type, actual, expected) - actual.each_with_object([]) do |(key, actual_item), missing_comments| + def verify_comments_and_events(type, actual, expected) + actual.each_with_object([]) do |(key, actual_item), missing_content| expected_item = expected[key] title = actual_item[:title] - msg = "expected #{type} with title '#{title}' to have" + msg = "expected #{type} with iid '#{key}' to have" # Print title in the error message to see which object is missing # @@ -320,17 +413,27 @@ module QA expect(expected_comments.length).to eq(actual_comments.length), comment_count_msg expect(expected_comments).to match_array(actual_comments) - # Save missing comments + expected_events = expected_item[:events] + actual_events = actual_item[:events] + event_count_msg = <<~MSG + #{msg} same amount of events. Gitlab: #{expected_events.length}, Github: #{actual_events.length} + MSG + expect(expected_events.length).to eq(actual_events.length), event_count_msg + expect(expected_events).to match_array(actual_events) + + # Save missing comments and events # comment_diff = actual_comments - expected_comments - next if comment_diff.empty? + event_diff = actual_events - expected_events + next if comment_diff.empty? && event_diff.empty? - missing_comments << { + missing_content << { title: title, github_url: actual_item[:url], gitlab_url: expected_item[:url], - missing_comments: comment_diff - } + missing_comments: comment_diff.empty? ? nil : comment_diff, + missing_events: event_diff.empty? ? nil : event_diff + }.compact end end @@ -380,26 +483,27 @@ module QA def mrs @mrs ||= begin logger.debug("= Fetching merge requests =") - imported_mrs = imported_project.merge_requests(auto_paginate: true, attempts: 2) + imported_mrs = imported_project.merge_requests(**api_request_params) logger.debug("= Fetching merge request comments =") - Parallel.map(imported_mrs, in_threads: 4) do |mr| + Parallel.map(imported_mrs, in_threads: Etc.nprocessors) do |mr| resource = Resource::MergeRequest.init do |resource| resource.project = imported_project resource.iid = mr[:iid] resource.api_client = api_client end - logger.debug("Fetching comments for mr '#{mr[:title]}'") - comments = resource - .comments(auto_paginate: true, attempts: 2) - .reject { |c| c[:system] || c[:body].match?(/^(\*\*Review:\*\*)|(\*Merged by:).*/) } + logger.debug("Fetching events and comments for mr '!#{mr[:iid]}'") + comments = resource.comments(**api_request_params) + label_events = resource.label_events(**api_request_params) + state_events = resource.state_events(**api_request_params) + milestone_events = resource.milestone_events(**api_request_params) [mr[:iid], { url: mr[:web_url], title: mr[:title], body: sanitize_description(mr[:description]) || '', - events: events(comments), + events: events(comments, label_events, state_events, milestone_events), comments: non_event_comments(comments) }] end.to_h @@ -412,48 +516,59 @@ module QA def gl_issues @gl_issues ||= begin logger.debug("= Fetching issues =") - imported_issues = imported_project.issues(auto_paginate: true, attempts: 2) + imported_issues = imported_project.issues(**api_request_params) logger.debug("= Fetching issue comments =") - Parallel.map(imported_issues, in_threads: 4) do |issue| + Parallel.map(imported_issues, in_threads: Etc.nprocessors) do |issue| resource = Resource::Issue.init do |issue_resource| issue_resource.project = imported_project issue_resource.iid = issue[:iid] issue_resource.api_client = api_client end - logger.debug("Fetching comments for issue '#{issue[:title]}'") - comments = resource.comments(auto_paginate: true, attempts: 2) + logger.debug("Fetching events and comments for issue '!#{issue[:iid]}'") + comments = resource.comments(**api_request_params) + label_events = resource.label_events(**api_request_params) + state_events = resource.state_events(**api_request_params) + milestone_events = resource.milestone_events(**api_request_params) [issue[:iid], { url: issue[:web_url], title: issue[:title], body: sanitize_description(issue[:description]) || '', - events: events(comments), + events: events(comments, label_events, state_events, milestone_events), comments: non_event_comments(comments) }] end.to_h end end - # Fetch comments without events + # Filter out event comments # # @param [Array] comments # @return [Array] def non_event_comments(comments) comments - .reject { |c| c[:body].match?(event_pattern) } + .reject { |c| c[:system] || c[:body].match?(event_pattern) } .map { |c| sanitize_comment(c[:body]) } end # Events # # @param [Array] comments + # @param [Array] label_events + # @param [Array] state_events + # @param [Array] milestone_events # @return [Array] - def events(comments) - comments - .select { |c| c[:body].match?(event_pattern) } - .map { |c| c[:body] } + def events(comments, label_events, state_events, milestone_events) + mapped_label_events = label_events.map { |event| event_mapping["label_#{event[:action]}"] } + mapped_milestone_events = milestone_events.map { |event| event_mapping["milestone_#{event[:action]}"] } + mapped_state_event = state_events.map { |event| event[:state] } + mapped_comment_events = comments.map do |c| + event_mapping[c[:body].match(event_pattern)&.named_captures&.fetch("event", nil)] + end + + [*mapped_label_events, *mapped_milestone_events, *mapped_state_event, *mapped_comment_events].compact end # Normalize comments and make them directly comparable @@ -489,6 +604,16 @@ module QA def save_json(name, json) File.open("tmp/#{name}.json", "w") { |file| file.write(JSON.pretty_generate(json)) } end + + # Extract id number from web url of issue or pull request + # + # Some endpoints don't return object id as separate parameter so web url can be used as a workaround + # + # @param [String] url + # @return [Integer] + def id_from_url(url) + url.match(%r{(?<type>issues|pull)/(?<id>\d+)})&.named_captures&.fetch("id", nil).to_i + end end end end diff --git a/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb new file mode 100644 index 00000000000..a2d66ffe8d3 --- /dev/null +++ b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Manage' do + describe 'WebHooks integration', :requires_admin, :integrations, :orchestrated, product_group: :integrations do + before(:context) do + toggle_local_requests(true) + end + + after(:context) do + Vendor::Smocker::SmockerApi.teardown! + end + + let(:session) { SecureRandom.hex(5) } + + it 'sends a push event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348945' do + setup_webhook(push: true) do |webhook, smocker| + Resource::Repository::ProjectPush.fabricate! do |project_push| + project_push.project = webhook.project + end + + wait_until do + !smocker.history(session).empty? + end + + events = smocker.history(session).map(&:as_hook_event) + aggregate_failures do + expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}" + expect(events[0].project_name).to eql(webhook.project.name) + expect(events[0].push?).to be(true), "Not push event: \n#{events[0].raw}" + end + end + end + + it 'sends a merge request event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349720' do + setup_webhook(merge_requests: true) do |webhook, smocker| + Resource::MergeRequest.fabricate_via_api! do |merge_request| + merge_request.project = webhook.project + end + + wait_until do + !smocker.history(session).empty? + end + + events = smocker.history(session).map(&:as_hook_event) + aggregate_failures do + expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}" + expect(events[0].project_name).to eql(webhook.project.name) + expect(events[0].mr?).to be(true), "Not MR event: \n#{events[0].raw}" + end + end + end + + it 'sends a wiki page event', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349722' do + setup_webhook(wiki_page: true) do |webhook, smocker| + Resource::Wiki::ProjectPage.fabricate_via_api! do |page| + page.project = webhook.project + end + + wait_until do + !smocker.history(session).empty? + end + + events = smocker.history(session).map(&:as_hook_event) + aggregate_failures do + expect(events.size).to be(1), "Should have 1 event: \n#{events.map(&:raw).join("\n")}" + expect(events[0].project_name).to eql(webhook.project.name) + expect(events[0].wiki?).to be(true), "Not wiki event: \n#{events[0].raw}" + end + end + end + + it 'sends an issues and note event', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do + setup_webhook(issues: true, note: true) do |webhook, smocker| + issue = Resource::Issue.fabricate_via_api! do |issue_init| + issue_init.project = webhook.project + end + + Resource::ProjectIssueNote.fabricate_via_api! do |note| + note.project = issue.project + note.issue = issue + end + + wait_until do + smocker.history(session).size > 1 + end + + events = smocker.history(session).map(&:as_hook_event) + aggregate_failures do + issue_event = events.find(&:issue?) + note_event = events.find(&:note?) + + expect(events.size).to be(2), "Should have 2 events: \n#{events.map(&:raw).join("\n")}" + expect(issue_event).not_to be(nil), "Not issue event: \n#{events[0].raw}" + expect(note_event).not_to be(nil), "Not note event: \n#{events[1].raw}" + end + end + end + + private + + def setup_webhook(**event_args) + Vendor::Smocker::SmockerApi.init(wait: 10) do |smocker| + smocker.register(session: session) + + webhook = Resource::ProjectWebHook.fabricate_via_api! do |hook| + hook.url = smocker.url + + event_args.each do |event, bool| + hook.send("#{event}_events=", bool) + end + end + + yield(webhook, smocker) + + smocker.reset + end + end + + def toggle_local_requests(on) + Runtime::ApplicationSettings.set_application_settings(allow_local_requests_from_web_hooks_and_services: on) + end + + def wait_until(timeout = 120, &block) + Support::Waiter.wait_until(max_duration: timeout, reload_page: false, raise_on_failure: false, &block) + end + end + end +end diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb index f721b3326a0..e17e12cdaf3 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Manage', :reliable, :requires_admin do + RSpec.describe 'Manage', :reliable, :requires_admin, product_group: :import do describe 'Gitlab migration' do let(:import_wait_duration) { { max_duration: 300, sleep_interval: 2 } } let(:admin_api_client) { Runtime::API::Client.as_admin } diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb index 74a00e1c74c..c1f11b15068 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' let!(:source_issue) do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb index 83cc44f9958..5689fa169ce 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb @@ -5,7 +5,7 @@ # rubocop:disable Rails/Pluck, Layout/LineLength, RSpec/MultipleMemoizedHelpers module QA RSpec.describe "Manage", requires_admin: 'creates users', only: { job: 'large-gitlab-import' } do - describe "Gitlab migration" do + describe "Gitlab migration", product_group: :import do let(:logger) { Runtime::Logger.logger } let(:differ) { RSpec::Support::Differ.new(color: true) } let(:gitlab_group) { ENV['QA_LARGE_IMPORT_GROUP'] || 'gitlab-migration' } diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb index 704325d9235..aa4d3becbe7 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' let(:member) do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb index d656ea4dea5..92cba005832 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' context 'with merge request' do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb index 484c32956e3..3db4ff4351e 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' context 'with ci pipeline' do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb index 421dbe56a99..3e0df3d1e13 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' context 'with uninitialized project' do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb index 6910b6a7fa2..91dcfe6a1a3 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb @@ -4,7 +4,7 @@ require_relative 'gitlab_project_migration_common' module QA RSpec.describe 'Manage' do - describe 'Gitlab migration' do + describe 'Gitlab migration', product_group: :import do include_context 'with gitlab project migration' context 'with release' do diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb index 3581ad3d207..9c80c088917 100644 --- a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb +++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true module QA - # Disable on live envs until bulk_import_projects toggle is on by default - # Otherwise tests running in parallel can disable feature in the middle of other test RSpec.shared_context 'with gitlab project migration', requires_admin: 'creates a user via API', + quarantine: { + type: :flaky, + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/364839' + }, feature_flag: { name: 'bulk_import_projects', scope: :global diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb index 539da92f471..c4be90d3759 100644 --- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb +++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb @@ -33,9 +33,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = @project_access_token.project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' } - ]) + commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }]) end end.not_to raise_error end @@ -67,9 +65,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = @different_project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' } - ]) + commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }]) end end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/) end diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb index 874626e01f1..24088057abc 100644 --- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb +++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do - describe 'rate limits', :reliable do + describe 'rate limits', :reliable, product_group: :integrations do let(:rate_limited_user) { Resource::User.fabricate_via_api! } let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) } let!(:request) { Runtime::API::Request.new(api_client, '/users') } diff --git a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb index e518bbfc6f7..28c20344b29 100644 --- a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb +++ b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb @@ -69,9 +69,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = @project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: 'test.txt', content: 'new file' } - ]) + commit.add_files([{ file_path: 'test.txt', content: 'new file' }]) end end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/) end diff --git a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb index 9f0e2664213..16d4fd35b69 100644 --- a/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb +++ b/qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Manage' do - describe 'User', :requires_admin do + describe 'User', :requires_admin, product_group: :workspace do let(:admin_api_client) { Runtime::API::Client.as_admin } let!(:sub_group) do @@ -85,9 +85,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = sub_group_project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: 'test.txt', content: 'new file' } - ]) + commit.add_files([{ file_path: 'test.txt', content: 'new file' }]) end end.not_to raise_error end @@ -167,9 +165,7 @@ module QA commit.branch = "new_branch_#{SecureRandom.hex(8)}" commit.start_branch = parent_group_project.default_branch commit.commit_message = 'Add new file' - commit.add_files([ - { file_path: 'test.txt', content: 'new file' } - ]) + commit.add_files([{ file_path: 'test.txt', content: 'new file' }]) end end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/) diff --git a/qa/qa/specs/features/api/1_manage/users_spec.rb b/qa/qa/specs/features/api/1_manage/users_spec.rb index 531419e8d0f..ff036c18671 100644 --- a/qa/qa/specs/features/api/1_manage/users_spec.rb +++ b/qa/qa/specs/features/api/1_manage/users_spec.rb @@ -4,7 +4,7 @@ require 'airborne' module QA RSpec.describe 'Manage' do - describe 'Users API', :reliable do + describe 'Users API', :reliable, product_group: :workspace do let(:api_client) { Runtime::API::Client.new(:gitlab) } let(:request) { Runtime::API::Request.new(api_client, '/users') } |