summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-27 18:15:54 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-27 18:15:54 +0000
commitc478950af927edd3cdafbdab68cb98601be2ee8c (patch)
treeb55785ff8bb709d3e6af6f475cc9fd484237f10e /scripts
parente77cb2465fa34b8883987206a42648603d5bf073 (diff)
downloadgitlab-ce-c478950af927edd3cdafbdab68cb98601be2ee8c.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/pipeline/create_test_failure_issues.rb67
1 files changed, 47 insertions, 20 deletions
diff --git a/scripts/pipeline/create_test_failure_issues.rb b/scripts/pipeline/create_test_failure_issues.rb
index 6312d392760..efe86984fc9 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,18 @@ 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
+ PROJECT_PATH = ENV.fetch('CI_PROJECT_PATH', 'gitlab-org/gitlab')
+ JOB_BASE_URL = "https://gitlab.com/#{PROJECT_PATH}/-/jobs/".freeze
+ FILE_BASE_URL = "https://gitlab.com/#{PROJECT_PATH}/-/blob/master/".freeze
+ REPORT_ITEM_REGEX = %r{^1\. \d{4}-\d{2}-\d{2}: #{JOB_BASE_URL}.+$}
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 +74,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_id = failed_test_id(failed_test)
+ issue_from_existing_issues = existing_issues.find { |issue| issue.title.include?(test_id) }
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_id, in: :title, per_page: 1)
.first
existing_issue = issue_from_existing_issues || issue_from_issue_tracker
@@ -88,10 +96,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(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 +121,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 +130,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]
+ 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_id(failed_test)}]"
raise "Title is too long!" if title.size > MAX_TITLE_LENGTH
title
end
+ def test_file_link(failed_test)
+ "[`#{failed_test['file']}`](#{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