# frozen_string_literal: true require 'set' module GitlabQuality module TestTooling module Report class ReportAsIssue include Concerns::Utils def initialize(token:, input_files:, project: nil, dry_run: false, **_kwargs) @project = project @gitlab = (dry_run ? GitlabIssueDryClient : GitlabIssueClient).new(token: token, project: project) @files = Array(input_files) end def invoke! validate_input! run! end private attr_reader :gitlab, :files, :project, :issue_type def run! raise NotImplementedError end def failed_test_hash(test) OpenSSL::Digest::SHA256.hexdigest(test.file + test.name) end def new_issue_description(test) <<~DESCRIPTION ### Test metadata (don't modify) | Field | Value | | ------ | ------ | | File | `#{test.file}` | | Description | `#{test.name}` | | Hash | `#{failed_test_hash(test)}` | DESCRIPTION end def new_issue_labels(_test) [] end def validate_input! assert_project! assert_input_files!(files) gitlab.assert_user_permission! end def assert_project! return if project abort "Please provide a valid project ID or path with the `-p/--project` option!" end def assert_input_files!(files) return if Dir.glob(files).any? abort "Please provide valid JUnit report files. No files were found matching `#{files.join(',')}`" end def create_issue(test) issue = gitlab.create_issue( title: title_from_test(test), description: new_issue_description(test), labels: new_issue_labels(test).to_a, issue_type: issue_type ) new_link = issue_type == 'test_case' ? issue.web_url.sub('/issues/', '/quality/test_cases/') : issue.web_url puts "Created new #{issue_type}: #{new_link}" issue end def issue_labels(issue) issue&.labels&.to_set || Set.new end def update_labels(issue, test, new_labels = Set.new) labels = up_to_date_labels(test: test, issue: issue, new_labels: new_labels) return if issue_labels(issue) == labels gitlab.edit_issue(iid: issue.iid, options: { labels: labels.to_a }) end def up_to_date_labels(test:, issue: nil, new_labels: Set.new) labels = issue_labels(issue) labels |= new_labels ee_test?(test) ? labels << 'Enterprise Edition' : labels.delete('Enterprise Edition') if test.quarantine? labels << 'quarantine' labels << "quarantine::#{test.quarantine_type}" else labels.delete_if { |label| label.include?('quarantine') } end labels end def pipeline_name_label case pipeline when 'production' 'found:gitlab.com' when 'canary', 'staging' "found:#{pipeline}.gitlab.com" when 'staging-canary' "found:canary.staging.gitlab.com" when 'preprod' 'found:pre.gitlab.com' when 'nightly', Runtime::Env.default_branch, 'staging-ref', 'release' "found:#{pipeline}" else raise "No `found:*` label for the `#{pipeline}` pipeline!" end end def ee_test?(test) test.file =~ %r{features/ee/(api|browser_ui)} end end end end end