diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-28 15:08:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-28 15:08:19 +0300 |
commit | 3fa33c82f9c49f4b53ddcf017fe77f1bff48a460 (patch) | |
tree | 6b0fb548b09370de722e06f47548c80380ff452d /scripts | |
parent | dba63244c19187d32f1f998403555f1893f5abdb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/pipeline/create_test_failure_issues.rb | 81 |
1 files changed, 60 insertions, 21 deletions
diff --git a/scripts/pipeline/create_test_failure_issues.rb b/scripts/pipeline/create_test_failure_issues.rb index 6312d392760..e4bcabb6223 100755 --- a/scripts/pipeline/create_test_failure_issues.rb +++ b/scripts/pipeline/create_test_failure_issues.rb @@ -24,7 +24,7 @@ class CreateTestFailureIssues puts "[CreateTestFailureIssues] No failed tests!" if failed_tests.empty? failed_tests.each_with_object([]) do |failed_test, existing_issues| - CreateTestFailureIssue.new(options.dup).comment_or_create(failed_test, existing_issues).tap do |issue| + CreateTestFailureIssue.new(options.dup).upsert(failed_test, existing_issues).tap do |issue| existing_issues << issue File.write(File.join(options[:issue_json_folder], "issue-#{issue.iid}.json"), JSON.pretty_generate(issue.to_h)) end @@ -52,14 +52,30 @@ class CreateTestFailureIssue WWW_GITLAB_COM_GROUPS_JSON = "#{WWW_GITLAB_COM_SITE}/groups.json".freeze WWW_GITLAB_COM_CATEGORIES_JSON = "#{WWW_GITLAB_COM_SITE}/categories.json".freeze FEATURE_CATEGORY_METADATA_REGEX = /(?<=feature_category: :)\w+/ - DEFAULT_LABELS = ['type::maintenance', 'failure::flaky-test'].freeze + DEFAULT_LABELS = ['type::maintenance', 'test'].freeze + + def self.server_host + @server_host ||= ENV.fetch('CI_SERVER_HOST', 'gitlab.com') + end + + def self.project_path + @project_path ||= ENV.fetch('CI_PROJECT_PATH', 'gitlab-org/gitlab') + end + + def self.file_base_url + @file_base_url ||= "https://#{server_host}/#{project_path}/-/blob/master/" + end + + def self.report_item_regex + @report_item_regex ||= %r{^1\. \d{4}-\d{2}-\d{2}: https://#{server_host}/#{project_path}/-/jobs/.+$} + end def initialize(options) @project = options.delete(:project) @api_token = options.delete(:api_token) end - def comment_or_create(failed_test, existing_issues = []) + def upsert(failed_test, existing_issues = []) existing_issue = find(failed_test, existing_issues) if existing_issue @@ -70,12 +86,16 @@ class CreateTestFailureIssue end end + private + + attr_reader :project, :api_token + def find(failed_test, existing_issues = []) - failed_test_issue_title = failed_test_issue_title(failed_test) - issue_from_existing_issues = existing_issues.find { |issue| issue.title == failed_test_issue_title } + test_hash = failed_test_hash(failed_test) + issue_from_existing_issues = existing_issues.find { |issue| issue.title.include?(test_hash) } issue_from_issue_tracker = FindIssues .new(project: project, api_token: api_token) - .execute(state: 'opened', search: failed_test_issue_title) + .execute(state: :opened, search: test_hash, in: :title, per_page: 1) .first existing_issue = issue_from_existing_issues || issue_from_issue_tracker @@ -88,10 +108,24 @@ class CreateTestFailureIssue end def update_reports(existing_issue, failed_test) - new_issue_description = "#{existing_issue.description}\n- #{failed_test['job_url']} (#{ENV['CI_PIPELINE_URL']})" + # We count the number of existing reports. + reports_count = existing_issue.description + .scan(self.class.report_item_regex) + .size.to_i + 1 + + # We include the number of reports in the header, for visibility. + issue_description = existing_issue.description.sub(/^### Reports.*$/, "### Reports (#{reports_count})") + + # We add the current failure to the list of reports. + issue_description = "#{issue_description}\n#{report_list_item(failed_test)}" + UpdateIssue .new(project: project, api_token: api_token) - .execute(existing_issue.iid, description: new_issue_description) + .execute( + existing_issue.iid, + description: issue_description, + weight: reports_count + ) puts "[CreateTestFailureIssue] Added a report in '#{existing_issue.title}': #{existing_issue.web_url}!" end @@ -99,7 +133,8 @@ class CreateTestFailureIssue payload = { title: failed_test_issue_title(failed_test), description: failed_test_issue_description(failed_test), - labels: failed_test_issue_labels(failed_test) + labels: failed_test_issue_labels(failed_test), + weight: 1 } CreateIssue.new(project: project, api_token: api_token).execute(payload).tap do |issue| @@ -107,36 +142,40 @@ class CreateTestFailureIssue end end - private - - attr_reader :project, :api_token - - def failed_test_id(failed_test) - Digest::SHA256.hexdigest(search_safe(failed_test['name']))[0...12] + def failed_test_hash(failed_test) + Digest::SHA256.hexdigest(failed_test['file'] + failed_test['name'])[0...12] end def failed_test_issue_title(failed_test) - title = "#{failed_test['file']} - ID: #{failed_test_id(failed_test)}" + title = "#{failed_test['file']} [test-hash:#{failed_test_hash(failed_test)}]" raise "Title is too long!" if title.size > MAX_TITLE_LENGTH title end + def test_file_link(failed_test) + "[`#{failed_test['file']}`](#{self.class.file_base_url}#{failed_test['file']})" + end + + def report_list_item(failed_test) + "1. #{Time.new.utc.strftime('%F')}: #{failed_test['job_url']} (#{ENV['CI_PIPELINE_URL']})" + end + def failed_test_issue_description(failed_test) <<~DESCRIPTION - ### Full description + ### Test description `#{search_safe(failed_test['name'])}` - ### File path + ### Test file path - `#{failed_test['file']}` + #{test_file_link(failed_test)} <!-- Don't add anything after the report list since it's updated automatically --> - ### Reports + ### Reports (1) - - #{failed_test['job_url']} (#{ENV['CI_PIPELINE_URL']}) + #{report_list_item(failed_test)} DESCRIPTION end |