# frozen_string_literal: true module GitlabQuality module TestTooling module TestMeta module Processor class AddToBlockingProcessor < MetaProcessor BLOCKING_METADATA = ", :blocking%{suffix}" BRANCH_PREFIX = 'blocking-promotion' class << self # Creates the merge requests for promoting E2E tests to :blocking # # @param [TestMetaUpdater] context instance of TestMetaUpdater def create_merge_requests(context) @context = context context.processed_commits.each_value do |record| branch, devops_stage, product_group, file, reviewer_id, assignee_handle = extract_data_from_record(record) mr_title = format("%{prefix} %{file}", prefix: '[E2E] PROMOTE TO BLOCKING:', file: file).truncate(72, omission: '') merge_request = context.create_merge_request(mr_title, branch, gitlab_bot_user_id, [reviewer_id]) do merge_request_description(record, devops_stage, product_group) end context.post_note_on_merge_request(maintainer_note_on_merge_request(assignee_handle), merge_request.iid) if merge_request Runtime::Logger.info(" Created MR for promotion to blocking: #{merge_request.web_url}") record[:merge_request] = merge_request end end end # Performs post processing. Posts a list of MRs in a note on report_issue # # @param [TestMetaUpdater] context instance of TestMetaUpdater def post_process(context) web_urls = context.processed_commits.values.map { |value| "- #{value[:merge_request].web_url}\n" }.join return if web_urls.empty? context.post_note_on_issue(<<~ISSUE_NOTE, context.report_issue) The following merge requests have been created to promote stable specs to blocking: #{web_urls} ISSUE_NOTE end private attr_reader :context, :file_path, :file, :file_contents, :example_name, :mr_title, :changed_line_no, :matched_lines # Checks if there is already an MR open # # @return [Boolean] def proceed_with_commit? # rubocop:disable Metrics/AbcSize if changed_line_no.negative? Runtime::Logger.info(" No lines were changed in #{file_path}. Will not proceed with creating MR.") return false elsif context.commit_processed?(file_path, changed_line_no) Runtime::Logger.info(" Record already processed for #{file_path}:#{changed_line_no}. Will not proceed with creating MR.") return false elsif context.quarantined?(matched_lines, file_contents) Runtime::Logger.info(" This test is in quarantine: #{file_path}:#{changed_line_no}. Will not proceed with creating MR.") return false end true end def commit_message <<~COMMIT_MESSAGE Promote end-to-end test to blocking #{"Promote to blocking: #{example_name}".truncate(72)} COMMIT_MESSAGE end def maintainer_note_on_merge_request(assignee_handle) <<~MARKDOWN @#{assignee_handle} Please review this MR, approve and assign it to a maintainer. If you think this MR should not be merged, please close it and add a note of the reason to the blocking report: #{context.report_issue} MARKDOWN end def merge_request_description(record, devops_stage, product_group) <<~MARKDOWN ## What does this MR do? Promotes the following e2e tests to the blocking bucket: #{spec_details_from_commits(record[:commits])} This MR was created based on data from reliable e2e test report: #{context.report_issue} /label ~"Quality" ~"QA" ~"type::maintenance" /label ~"devops::#{devops_stage}" #{context.label_from_product_group(product_group)}
(This MR was automatically generated by [`gitlab_quality-test_tooling`](https://gitlab.com/gitlab-org/ruby/gems/gitlab_quality-test_tooling) at #{Time.now.utc})
MARKDOWN end def extract_data_from_record(record) first_spec = record[:commits].values.first product_group = first_spec["product_group"] devops_stage = first_spec["stage"] reviewer_id, assignee_handle = context.fetch_dri_id(product_group, devops_stage, first_spec["section"]) [record[:branch], devops_stage, product_group, first_spec["file"], reviewer_id, assignee_handle] end def gitlab_bot_user_id context.user_id_for_username(Runtime::Env.gitlab_bot_username) end # Add blocking metadata to the file content and replace it # # @return [Array] first value holds the new content, the second value holds the line number of the test def add_metadata # rubocop:disable Metrics/AbcSize @matched_lines = context.find_example_match_lines(file_contents, example_name) if matched_lines.any? { |line| line[0].include?(':blocking') } Runtime::Logger.info("Example '#{example_name}' is already blocking") return [file_contents, -1] end context.update_matched_line(matched_lines.last, file_contents.dup) do |line| if line.sub(DESCRIPTION_REGEX, '').include?(',') line[line.index(',', end_of_description_index(line))] = format(BLOCKING_METADATA, suffix: ',') else line[line.rindex(' ')] = format(BLOCKING_METADATA, suffix: ' ') end line end end end end end end end end