lib/release_tools/security/merge_requests_merger.rb (97 lines of code) (raw):

# frozen_string_literal: true module ReleaseTools module Security # Merging valid security merge requests class MergeRequestsMerger include ::SemanticLogger::Loggable # @param [ReleaseTools::Security::Client] client def initialize(merge_default: false) @client = ReleaseTools::Security::Client.new @merge_default = merge_default @status = nil end # Processes valid security merge requests: # # 1. Fetches security implementation issues that are ready # to be processed. # 2. Iterates over security implementation issues # 3. If `merge_default`, only the merge request targeting the default branch is processed. # Else, the backports and pending merge requests are processed. def execute security_implementation_issues.each do |security_issue| process_merge_requests(security_issue) end post_security_issues_table update_patch_release_status_metric update_status(:success) send_slack_notification rescue StandardError => ex logger.fatal('There has been an error. Check the logs for which MRs were not processed correctly.', error: ex) update_status(:failed) send_slack_notification raise end private def security_implementation_issues Security::IssueCrawler .new .upcoming_security_issues_and_merge_requests end def process_merge_requests(security_issue) if @merge_default process_mr_targeting_default(security_issue) else process_pending_merge_requests(security_issue) end end # Processes merge request targeting the default branch for GitLab Security # issues by triggering a new pipeline and setting MWPS def process_mr_targeting_default(security_issue) return unless security_issue.allowed_to_early_merge? logger.info('Processing merge request targeting default branch', issue: security_issue.web_url) mr_default = security_issue.merge_request_targeting_default_branch ReleaseTools::Security::MergeWhenPipelineSucceedsService .new(@client, mr_default) .execute end # Processes pending merge requests: # # - For GitLab Security issues, the backports are processed. # - For the rest of the projects, all security merge requests # are processed. def process_pending_merge_requests(security_issue) unless security_issue.default_merge_request_handled? logger.fatal('Issue skipped. Default merge request has not been merged', issue: security_issue.web_url) update_status(:failed) return end logger.info('Merging pending merge_requests', issue: security_issue.web_url) security_issue.pending_merge_requests.each do |merge_request| merge_merge_request(merge_request) end end def merge_merge_request(merge_request) logger.trace(__method__, merge_request: merge_request.web_url) return if SharedStatus.dry_run? || merge_request.state == 'merged' merged_result = @client.accept_merge_request( merge_request.project_id, merge_request.iid, squash: true, should_remove_source_branch: true ) if merged_result.respond_to?(:merge_commit_sha) && merged_result.merge_commit_sha.present? logger.info("Merged security merge request", url: merge_request.web_url) else logger.fatal("Merge request #{merge_request.web_url} couldn't be merged") update_status(:failed) end end def post_security_issues_table IssueTable::Service.new(@client).execute end def update_patch_release_status_metric return if SharedStatus.dry_run? ReleaseTools::Metrics::PatchReleaseStatus.new(status: :closed).execute end def update_status(value) return if @status == :failed @status = value end def send_slack_notification job_type = if @merge_default "Default merge" else "Merge" end ReleaseTools::Slack::ReleaseJobEndNotifier.new( job_type: job_type, status: @status, release_type: :patch ).send_notification end end end end