class Gitlab::QA::Report::ResultsInIssues
Uses the API to create or update GitLab issues with the results of tests from RSpec report files.
Constants
- RESULTS_SECTION_TEMPLATE
Private Instance Methods
add_issue_to_testcase(testcase, issue)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 129 def add_issue_to_testcase(testcase, issue) results_section = testcase.description.include?(RESULTS_SECTION_TEMPLATE) ? '' : RESULTS_SECTION_TEMPLATE gitlab.edit_issue(iid: testcase.iid, options: { description: (testcase.description + results_section + "\n\n#{issue.web_url}") }) end
create_testcase(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 64 def create_testcase(test) title = title_from_test(test) puts "Creating test case '#{title}' ..." gitlab.create_issue( title: title, description: new_testcase_description(test), labels: new_issue_labels(test), issue_type: 'test_case' ) end
error_and_stack_trace(text)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 219 def error_and_stack_trace(text) text.strip[/Error:(.*)/m, 1].to_s end
failure_summary()
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 203 def failure_summary summary = [":x: ~\"#{pipeline}::failed\""] summary << "~\"quarantine\"" if quarantine_job? summary << "in job `#{Runtime::Env.ci_job_name}` in #{Runtime::Env.ci_job_url}" summary.join(' ') end
find_issue(test, issue_type)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 121 def find_issue(test, issue_type) issues = search_issues(test: test, issue_type: 'issue') warn(%(Too many issues found with the file path "#{test.file}" and name "#{test.name}")) if issues.many? issues.first end
find_issue_by_iid(testcase, test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 109 def find_issue_by_iid(testcase, test) iid = issue_iid_from_testcase(testcase) return unless iid issues = search_issues(test: test, issue_type: 'issue', iid: iid) warn(%(Issue iid "#{iid}" not valid)) if issues.empty? issues.first end
find_or_create_issue(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 96 def find_or_create_issue(test) issue = find_issue(test, 'issue') if issue puts "Found existing issue: #{issue.web_url}" else issue = create_issue(test) puts "Created new issue: #{issue.web_url}" end issue end
find_testcase(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 49 def find_testcase(test) iid = iid_from_testcase_url(test.testcase) testcases = search_issues(test: test, issue_type: 'test_case', iid: iid) if iid && testcases.blank? warn(%(Test case url "#{test.testcase}" not valid)) testcases = search_issues(test: test, issue_type: 'test_case') end warn(%(Too many test cases found with the file path "#{test.file}" and name "#{test.name}")) if testcases&.many? testcases.first end
iid_from_testcase_url(url)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 76 def iid_from_testcase_url(url) return warn(%(\nPlease update #{url} to test case url")) if url&.include?('/-/issues/') url && url.split('/').last.to_i end
issue_iid_from_testcase(testcase)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 86 def issue_iid_from_testcase(testcase) results = testcase.description.partition(RESULTS_SECTION_TEMPLATE).last if testcase.description.include?(RESULTS_SECTION_TEMPLATE) return puts "No issue link found" unless results issue_iid = results.split('/').last issue_iid&.to_i end
new_issue_labels(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 149 def new_issue_labels(test) ['Quality', "devops::#{test.stage}", 'status::automated'] end
new_note_matches_discussion?(note, discussion)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 210 def new_note_matches_discussion?(note, discussion) note_error = error_and_stack_trace(note) discussion_error = error_and_stack_trace(discussion.notes.first['body']) return false if note_error.empty? || discussion_error.empty? note_error == discussion_error end
new_testcase_description(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 82 def new_testcase_description(test) "#{new_issue_description(test)}#{RESULTS_SECTION_TEMPLATE}" end
note_content(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 185 def note_content(test) errors = test.failures.each_with_object([]) do |failure, text| text << <<~TEXT Error: ``` #{failure['message']} ``` Stacktrace: ``` #{failure['stacktrace']} ``` TEXT end.join("\n\n") "#{failure_summary}\n\n#{errors}" end
note_status(issue, test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 170 def note_status(issue, test) return false if test.skipped return false if test.failures.empty? note = note_content(test) gitlab.find_issue_discussions(iid: issue.iid).each do |discussion| return gitlab.add_note_to_issue_discussion_as_thread(iid: issue.iid, discussion_id: discussion.id, body: failure_summary) if new_note_matches_discussion?(note, discussion) end gitlab.create_issue_note(iid: issue.iid, note: note) true end
report_test(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 29 def report_test(test) puts "Reporting test: #{test.file} | #{test.name}" testcase = find_testcase(test) || create_testcase(test) test.testcase ||= testcase.web_url.sub('/issues/', '/quality/test_cases/') issue = find_issue_by_iid(testcase, test) unless issue puts "No valid issue link found" issue = find_or_create_issue(test) add_issue_to_testcase(testcase, issue) puts "Added issue #{issue.web_url} to testcase #{testcase.web_url}" end update_labels(testcase, test) update_issue(issue, test) end
run!()
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 15 def run! puts "Reporting test results in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`." test_results_per_file do |test_results| puts "Reporting tests in #{test_results.path}" test_results.each do |test| report_test(test) unless test.skipped end test_results.write end end
search_issues(test:, issue_type:, iid: nil)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 160 def search_issues(test:, issue_type:, iid: nil) gitlab.find_issues(iid: iid, options: { search: search_term(test) }) do |issue| issue.state == 'opened' && issue.issue_type == issue_type && issue.title.strip == title_from_test(test) end end
search_term(test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 166 def search_term(test) %("#{partial_file_path(test.file)}" "#{search_safe(test.name)}") end
up_to_date_labels(test:, issue: nil, new_labels: Set.new)
click to toggle source
Calls superclass method
Gitlab::QA::Report::ReportAsIssue#up_to_date_labels
# File lib/gitlab/qa/report/results_in_issues.rb, line 153 def up_to_date_labels(test:, issue: nil, new_labels: Set.new) labels = super labels |= new_issue_labels(test).to_set labels.delete_if { |label| label.start_with?("#{pipeline}::") } labels << (test.failures.empty? ? "#{pipeline}::passed" : "#{pipeline}::failed") end
update_issue(issue, test)
click to toggle source
# File lib/gitlab/qa/report/results_in_issues.rb, line 135 def update_issue(issue, test) new_labels = issue_labels(issue) new_labels |= ['Testcase Linked'] labels_updated = update_labels(issue, test, new_labels) note_posted = note_status(issue, test) if labels_updated || note_posted puts "Issue updated." else puts "Test passed, no update needed." end end