From 44d033747da39826bcf6e50adc26e7130159f90b Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 31 Mar 2023 19:27:02 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-10-stable-ee --- .gitlab/ci/notify.gitlab-ci.yml | 12 ++++ .gitlab/ci/rules.gitlab-ci.yml | 7 ++ danger/stable_branch_patch/Dangerfile | 2 +- scripts/api/create_merge_request_discussion.rb | 33 +++++++++ scripts/api/get_package_and_test_job.rb | 39 +++++++++++ .../generate-failed-package-and-test-mr-message.rb | 79 ++++++++++++++++++++++ .../api/create_merge_request_discussion_spec.rb | 40 +++++++++++ spec/scripts/api/get_package_and_test_job_spec.rb | 47 +++++++++++++ ...rate_failed_package_and_test_mr_message_spec.rb | 79 ++++++++++++++++++++++ spec/tooling/danger/stable_branch_spec.rb | 2 +- tooling/danger/stable_branch.rb | 10 +-- 11 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 scripts/api/create_merge_request_discussion.rb create mode 100644 scripts/api/get_package_and_test_job.rb create mode 100755 scripts/generate-failed-package-and-test-mr-message.rb create mode 100644 spec/scripts/api/create_merge_request_discussion_spec.rb create mode 100644 spec/scripts/api/get_package_and_test_job_spec.rb create mode 100644 spec/scripts/generate_failed_package_and_test_mr_message_spec.rb diff --git a/.gitlab/ci/notify.gitlab-ci.yml b/.gitlab/ci/notify.gitlab-ci.yml index 795a0cd6439..90ae1813e5f 100644 --- a/.gitlab/ci/notify.gitlab-ci.yml +++ b/.gitlab/ci/notify.gitlab-ci.yml @@ -95,3 +95,15 @@ create-issues-for-failing-tests: - ${FAILING_ISSUE_JSON_DIR}/ when: always expire_in: 2 days + +notify-package-and-test-failure: + extends: + - .notify-defaults + - .notify:rules:notify-package-and-test-failure + image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION} + before_script: + - source scripts/utils.sh + - apt-get update + - install_gitlab_gem + script: + - scripts/generate-failed-package-and-test-mr-message.rb diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index b4301c72347..eb00fb9ced4 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -1140,6 +1140,13 @@ when: on_failure allow_failure: true +.notify:rules:notify-package-and-test-failure: + rules: + - <<: *if-not-canonical-namespace + when: never + - <<: *if-merge-request-targeting-stable-branch + when: on_failure + ############### # Pages rules # ############### diff --git a/danger/stable_branch_patch/Dangerfile b/danger/stable_branch_patch/Dangerfile index 2ac1b14c91f..a4b557c1eaa 100644 --- a/danger/stable_branch_patch/Dangerfile +++ b/danger/stable_branch_patch/Dangerfile @@ -2,7 +2,7 @@ if stable_branch.encourage_package_and_qa_execution? markdown(<<~MARKDOWN) - ## QA `e2e:package-and-test` + ## QA `e2e:package-and-test-ee` **@#{helper.mr_author}, the `package-and-test` job must complete before merging this merge request.*** diff --git a/scripts/api/create_merge_request_discussion.rb b/scripts/api/create_merge_request_discussion.rb new file mode 100644 index 00000000000..2b380d2e216 --- /dev/null +++ b/scripts/api/create_merge_request_discussion.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'gitlab' +require_relative 'default_options' + +class CreateMergeRequestDiscussion + def initialize(options) + @merge_request = options.fetch(:merge_request) + @project = options.fetch(:project) + + # If api_token is nil, it's set to '' to allow unauthenticated requests (for forks). + api_token = options.fetch(:api_token, '') + + warn "No API token given." if api_token.empty? + + @client = Gitlab.client( + endpoint: options.fetch(:endpoint, API::DEFAULT_OPTIONS[:endpoint]), + private_token: api_token + ) + end + + def execute(content) + client.create_merge_request_discussion( + project, + merge_request.fetch('iid'), + body: content + ) + end + + private + + attr_reader :merge_request, :client, :project +end diff --git a/scripts/api/get_package_and_test_job.rb b/scripts/api/get_package_and_test_job.rb new file mode 100644 index 00000000000..dbc29f754d0 --- /dev/null +++ b/scripts/api/get_package_and_test_job.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'gitlab' + +require_relative 'default_options' + +class GetPackageAndTestJob + def initialize(options) + @project = options.fetch(:project) + @pipeline_id = options.fetch(:pipeline_id) + + # If api_token is nil, it's set to '' to allow unauthenticated requests (for forks). + api_token = options.fetch(:api_token, '') + + warn "No API token given." if api_token.empty? + + @client = Gitlab.client( + endpoint: options.fetch(:endpoint) || API::DEFAULT_OPTIONS[:endpoint], + private_token: api_token + ) + end + + def execute + package_and_test_job = nil + + client.pipeline_bridges(project, pipeline_id, scope: 'failed', per_page: 100).auto_paginate do |job| + if job['name'].include?('package-and-test') + package_and_test_job = job + break + end + end + + package_and_test_job + end + + private + + attr_reader :project, :pipeline_id, :exclude_allowed_to_fail_jobs, :client +end diff --git a/scripts/generate-failed-package-and-test-mr-message.rb b/scripts/generate-failed-package-and-test-mr-message.rb new file mode 100755 index 00000000000..a53b393498c --- /dev/null +++ b/scripts/generate-failed-package-and-test-mr-message.rb @@ -0,0 +1,79 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +require 'optparse' +require 'json' + +require_relative 'api/create_merge_request_discussion' +require_relative 'api/commit_merge_requests' +require_relative 'api/get_package_and_test_job' + +class GenerateFailedPackageAndTestMrMessage + DEFAULT_OPTIONS = { + project: nil + }.freeze + + def initialize(options) + @project = options.fetch(:project) + end + + def execute + return unless failed_package_and_test_job + + add_discussion_to_mr + end + + private + + attr_reader :project + + def add_discussion_to_mr + CreateMergeRequestDiscussion.new( + API::DEFAULT_OPTIONS.merge(merge_request: merge_request) + ).execute(content) + end + + def failed_package_and_test_job + @failed_package_and_test_job ||= GetPackageAndTestJob.new(API::DEFAULT_OPTIONS).execute + end + + def merge_request + @merge_request ||= CommitMergeRequests.new( + API::DEFAULT_OPTIONS.merge(sha: ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA']) + ).execute.first + end + + def content + <<~MARKDOWN + :warning: @#{author_username} The `e2e:package-and-test-ee` job has failed. + + - Pipeline: #{pipeline_link} + - `package-and-test` pipeline: #{failed_package_and_test_job['web_url']} + + Ping your team's associated Software Engineer in Test (SET) to confirm the failures are unrelated to the merge request. + If there's no SET assigned, ask for assistance on the `#quality` Slack channel. + MARKDOWN + end + + def author_username + merge_request['author']['username'] if merge_request + end + + def pipeline_link + "[##{ENV['CI_PIPELINE_ID']}](#{ENV['CI_PIPELINE_URL']})" + end +end + +if $PROGRAM_NAME == __FILE__ + options = GenerateFailedPackageAndTestMrMessage::DEFAULT_OPTIONS.dup + + OptionParser.new do |opts| + opts.on("-h", "--help", "Prints this help") do + puts opts + exit + end + end.parse! + + GenerateFailedPackageAndTestMrMessage.new(options).execute +end diff --git a/spec/scripts/api/create_merge_request_discussion_spec.rb b/spec/scripts/api/create_merge_request_discussion_spec.rb new file mode 100644 index 00000000000..3867f6532a9 --- /dev/null +++ b/spec/scripts/api/create_merge_request_discussion_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative '../../../scripts/api/create_merge_request_discussion' + +RSpec.describe CreateMergeRequestDiscussion, feature_category: :tooling do + describe '#execute' do + let(:project_id) { 12345 } + let(:iid) { 1 } + let(:content) { 'test123' } + + let(:options) do + { + api_token: 'token', + endpoint: 'https://example.gitlab.com', + project: project_id, + merge_request: { + 'iid' => iid + } + } + end + + subject { described_class.new(options).execute(content) } + + it 'requests commit_merge_requests from the gitlab client' do + expected_result = true + client = double('Gitlab::Client') # rubocop:disable RSpec/VerifiedDoubles + + expect(Gitlab).to receive(:client) + .with(endpoint: options[:endpoint], private_token: options[:api_token]) + .and_return(client) + + expect(client).to receive(:create_merge_request_discussion).with( + project_id, iid, body: content + ).and_return(expected_result) + + expect(subject).to eq(expected_result) + end + end +end diff --git a/spec/scripts/api/get_package_and_test_job_spec.rb b/spec/scripts/api/get_package_and_test_job_spec.rb new file mode 100644 index 00000000000..60bb26cbcaf --- /dev/null +++ b/spec/scripts/api/get_package_and_test_job_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative '../../../scripts/api/get_package_and_test_job' + +RSpec.describe GetPackageAndTestJob, feature_category: :tooling do + describe '#execute' do + let(:project) { 12345 } + let(:pipeline_id) { 1 } + + let(:options) do + { + api_token: 'token', + endpoint: 'https://example.gitlab.com', + project: project, + pipeline_id: pipeline_id + } + end + + subject { described_class.new(options).execute } + + it 'requests commit_merge_requests from the gitlab client' do + client_result = [ + { 'name' => 'foo' }, + { 'name' => 'e2e:package-and-test-ee' }, + { 'name' => 'bar' } + ] + client = double('Gitlab::Client') # rubocop:disable RSpec/VerifiedDoubles + client_response = double('Gitlab::ClientResponse') # rubocop:disable RSpec/VerifiedDoubles + + expect(Gitlab).to receive(:client) + .with(endpoint: options[:endpoint], private_token: options[:api_token]) + .and_return(client) + + expect(client).to receive(:pipeline_bridges).with( + project, pipeline_id, scope: 'failed', per_page: 100 + ).and_return(client_response) + + expect(client_response).to receive(:auto_paginate) + .and_yield(client_result[0]) + .and_yield(client_result[1]) + .and_yield(client_result[2]) + + expect(subject).to eq(client_result[1]) + end + end +end diff --git a/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb b/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb new file mode 100644 index 00000000000..79e63c95f65 --- /dev/null +++ b/spec/scripts/generate_failed_package_and_test_mr_message_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative '../../scripts/generate-failed-package-and-test-mr-message' +require_relative '../support/helpers/stub_env' + +RSpec.describe GenerateFailedPackageAndTestMrMessage, feature_category: :tooling do + include StubENV + + describe '#execute' do + let(:options) do + { + project: 1234, + api_token: 'asdf1234' + } + end + + let(:commit_merge_request) do + { + 'author' => { + 'id' => '2', + 'username' => 'test_user' + } + } + end + + let(:package_and_test_job) do + { 'web_url' => 'http://example.com' } + end + + let(:merge_request) { instance_double(CommitMergeRequests, execute: [commit_merge_request]) } + let(:content) { /The `e2e:package-and-test-ee` job has failed./ } + let(:merge_request_discussion_client) { instance_double(CreateMergeRequestDiscussion, execute: true) } + let(:package_and_test_job_client) { instance_double(GetPackageAndTestJob, execute: package_and_test_job) } + + subject { described_class.new(options).execute } + + before do + stub_env( + 'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257', + 'CI_PROJECT_ID' => '13083', + 'CI_PIPELINE_ID' => '1234567', + 'CI_PIPELINE_URL' => 'https://gitlab.com/gitlab-org/gitlab/-/pipelines/1234567', + 'PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE' => 'asdf1234' + ) + + allow(GetPackageAndTestJob).to receive(:new) + .with(API::DEFAULT_OPTIONS) + .and_return(package_and_test_job_client) + end + + context 'when package-and-test fails' do + before do + allow(CommitMergeRequests).to receive(:new) + .with(API::DEFAULT_OPTIONS.merge(sha: ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'])) + .and_return(merge_request) + end + + it 'successfully creates a discussion' do + expect(CreateMergeRequestDiscussion).to receive(:new) + .with(API::DEFAULT_OPTIONS.merge(merge_request: commit_merge_request)) + .and_return(merge_request_discussion_client) + + expect(merge_request_discussion_client).to receive(:execute).with(content) + + expect(subject).to eq(true) + end + end + + context 'when package-and-test is did not fail' do + let(:package_and_test_job_client) { instance_double(GetPackageAndTestJob, execute: nil) } + + it 'does not add a discussion' do + expect(CreateMergeRequestDiscussion).not_to receive(:new) + expect(subject).to eq(nil) + end + end + end +end diff --git a/spec/tooling/danger/stable_branch_spec.rb b/spec/tooling/danger/stable_branch_spec.rb index b6ec4ad8895..b0a8ab3c132 100644 --- a/spec/tooling/danger/stable_branch_spec.rb +++ b/spec/tooling/danger/stable_branch_spec.rb @@ -197,7 +197,7 @@ RSpec.describe Tooling::Danger::StableBranch, feature_category: :delivery do let(:pipeline_bridges_response) do [ { - 'name' => 'e2e:package-and-test', + 'name' => 'e2e:package-and-test-ee', 'status' => pipeline_bridge_state, 'downstream_pipeline' => nil } diff --git a/tooling/danger/stable_branch.rb b/tooling/danger/stable_branch.rb index be668731cb4..2751a6f0191 100644 --- a/tooling/danger/stable_branch.rb +++ b/tooling/danger/stable_branch.rb @@ -42,18 +42,18 @@ module Tooling MSG PIPELINE_EXPEDITE_ERROR_MESSAGE = <<~MSG - ~"pipeline:expedite" is not allowed on stable branches because it causes the `e2e:package-and-test` job to be skipped. + ~"pipeline:expedite" is not allowed on stable branches because it causes the `e2e:package-and-test-ee` job to be skipped. MSG NEEDS_PACKAGE_AND_TEST_MESSAGE = <<~MSG - The `e2e:package-and-test` job is not present, has been canceled, or needs to be automatically triggered. + The `e2e:package-and-test-ee` job is not present, has been canceled, or needs to be automatically triggered. Please ensure the job is present in the latest pipeline, if necessary, retry the `danger-review` job. - Read the "QA e2e:package-and-test" section for more details. + Read the "QA e2e:package-and-test-ee" section for more details. MSG WARN_PACKAGE_AND_TEST_MESSAGE = <<~MSG - **The `e2e:package-and-test` job needs to succeed or have approval from a Software Engineer in Test.** - Read the "QA e2e:package-and-test" section for more details. + **The `e2e:package-and-test-ee` job needs to succeed or have approval from a Software Engineer in Test.** + Read the "QA e2e:package-and-test-ee" section for more details. MSG # rubocop:disable Style/SignalException -- cgit v1.2.1