gitlab_quality-test_tooling 1.29.1 → 1.31.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 523cbb3e59a928b4e438ec2f97818c6b756b5120d9d61ede7945bd5904de4b79
4
- data.tar.gz: 750bb848167c76df6f6287d119eb211fa8281abfade44334ca1cb72142b03361
3
+ metadata.gz: 5d848eed10080ffc5f609ba56a75e7baf6f60cef5792d66c9c1bf9fdb8dbd2b9
4
+ data.tar.gz: 5d799f1628b689fda63e0ca68fb70c5f2e6e37d20d867d6ade61e4ff04ea7e57
5
5
  SHA512:
6
- metadata.gz: ab633288538b5343309ed30766925b61c05685f457e1772f5c80113a013fd75910509cf76fa01feb9e9bffdf5d764357f221b8f7f53748f17daed1f60b240464
7
- data.tar.gz: 2dbf75f6310a515c0c9eb43301fd6b669ba96e115cbdeec37a2570fc556cac94daac00ec81638aaf1288e465efd4284af167e7d060657eaff788d65aebb92362
6
+ metadata.gz: 2e881613627b3fb87abf0c00895a8b44919769b222aa1a42c60c81b8f77a79a99232145e60c798f0296d24f53f761cb6a5fd4c7d00d1cb982dcc3c58fd68a833
7
+ data.tar.gz: 90b1345308d5f4abb94ab81f16520bf79870de753f570223c5bc45ade1fdb7d2ca099004d682bdbcfe106c3557ebdd093ce0461b493fd98e6e687bb9930b293e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab_quality-test_tooling (1.29.1)
4
+ gitlab_quality-test_tooling (1.31.0)
5
5
  activesupport (>= 7.0, < 7.2)
6
6
  amatch (~> 0.4.1)
7
7
  gitlab (~> 4.19)
@@ -330,4 +330,4 @@ DEPENDENCIES
330
330
  webmock (= 3.7.0)
331
331
 
332
332
  BUNDLED WITH
333
- 2.5.6
333
+ 2.5.13
data/exe/post-to-slack CHANGED
@@ -47,6 +47,10 @@ options = OptionParser.new do |opts|
47
47
  summary_table_opts[:sort_direction] = sort_direction.downcase.to_sym
48
48
  end
49
49
 
50
+ opts.on('--hide-passed-tests', 'Used with the `--include-summary-table` flag — Hide passed tests from the summary table') do
51
+ summary_table_opts[:hide_passed_tests] = true
52
+ end
53
+
50
54
  opts.on('-t', '--include-summary-table FILES', String, 'Add a test summary table based on RSpec report files (JUnit XML)') do |files|
51
55
  params[:summary_table_files] = files
52
56
  end
@@ -19,7 +19,9 @@ module GitlabQuality
19
19
  end
20
20
 
21
21
  def file_contents_at_line(line_number)
22
- file_contents.lines(chomp: true)[line_number - 1]
22
+ ignore_gitlab_client_exceptions do
23
+ file_contents.lines(chomp: true)[line_number - 1]
24
+ end
23
25
  end
24
26
  end
25
27
  end
@@ -4,13 +4,14 @@ module GitlabQuality
4
4
  module TestTooling
5
5
  module KnapsackReports
6
6
  class SpecRunTime
7
- attr_reader :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration
7
+ attr_reader :project, :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration
8
8
 
9
9
  ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD = 1.5 # actual run time is longer than expected by 50% +
10
10
  SPEC_WEIGHT_PERCENTAGE_TRESHOLD = 15 # a spec file takes 15%+ of the total test suite run time
11
11
  SUITE_DURATION_THRESHOLD = 70 * 60 # if test suite takes more than 70 minutes, job risks timing out
12
12
 
13
- def initialize(file:, expected:, actual:, expected_suite_duration:, actual_suite_duration:)
13
+ def initialize(project:, file:, expected:, actual:, expected_suite_duration:, actual_suite_duration:)
14
+ @project = project
14
15
  @file = file
15
16
  @expected = expected.to_f
16
17
  @actual = actual.to_f
@@ -77,7 +78,7 @@ module GitlabQuality
77
78
  end
78
79
 
79
80
  def file_link
80
- "#{Runtime::Env.file_base_url}#{file}"
81
+ "https://gitlab.com/#{project}/-/blob/#{Runtime::Env.ci_commit_ref_name}/#{file}"
81
82
  end
82
83
  end
83
84
  end
@@ -6,9 +6,10 @@ module GitlabQuality
6
6
  module TestTooling
7
7
  module KnapsackReports
8
8
  class SpecRunTimeReport
9
- attr_reader :expected_report, :actual_report
9
+ attr_reader :project, :expected_report, :actual_report
10
10
 
11
- def initialize(expected_report_path:, actual_report_path:)
11
+ def initialize(project:, expected_report_path:, actual_report_path:)
12
+ @project = project
12
13
  @expected_report = parse(expected_report_path)
13
14
  @actual_report = parse(actual_report_path)
14
15
  end
@@ -24,6 +25,7 @@ module GitlabQuality
24
25
  end
25
26
 
26
27
  spec_run_time = SpecRunTime.new(
28
+ project: project,
27
29
  file: spec_file,
28
30
  expected: expected_run_time,
29
31
  actual: actual_run_time,
@@ -19,8 +19,6 @@ module GitlabQuality
19
19
  ISSUE_STACKTRACE_REGEX = /##### Stack trace\s*(```)#{FAILURE_STACKTRACE_REGEX}(```)\n*/m
20
20
  DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION = 0.15
21
21
 
22
- MultipleNotesFound = Class.new(StandardError)
23
-
24
22
  def initialize(
25
23
  base_issue_labels: nil,
26
24
  max_diff_ratio: DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION,
@@ -73,9 +71,7 @@ module GitlabQuality
73
71
  relevant_notes = find_relevant_failure_discussion_note(issue: issue, test: test, reports_discussion: reports_discussion)
74
72
  return if relevant_notes.empty?
75
73
 
76
- best_matching_note, smaller_diff_ratio = relevant_notes.min_by { |_, diff_ratio| diff_ratio }
77
-
78
- raise(MultipleNotesFound, %(Too many issues found for test '#{test.name}' (`#{test.file}`)!)) unless relevant_notes.values.count(smaller_diff_ratio) == 1
74
+ best_matching_note, _ = relevant_notes.min_by { |_, diff_ratio| diff_ratio }
79
75
 
80
76
  # Re-instantiate a `Gitlab::ObjectifiedHash` object after having converted it to a hash in #find_relevant_failure_issues above.
81
77
  best_matching_note = Gitlab::ObjectifiedHash.new(best_matching_note)
@@ -16,7 +16,7 @@ module GitlabQuality
16
16
  include Concerns::GroupAndCategoryLabels
17
17
  include Concerns::IssueReports
18
18
 
19
- BASE_SEARCH_LABELS = ['test'].freeze
19
+ BASE_SEARCH_LABELS = ['test'].freeze
20
20
  FOUND_IN_MR_LABEL = '~"found:in MR"'
21
21
  FOUND_IN_MASTER_LABEL = '~"found:master"'
22
22
 
@@ -133,8 +133,6 @@ module GitlabQuality
133
133
  else
134
134
  gitlab.create_issue_note(iid: issue.iid, note: note_body)
135
135
  end
136
- rescue MultipleNotesFound => e
137
- warn(e.message)
138
136
  end
139
137
 
140
138
  def find_or_create_reports_discussion(issue:)
@@ -36,6 +36,7 @@ module GitlabQuality
36
36
 
37
37
  def search_and_create_issue
38
38
  filtered_report = KnapsackReports::SpecRunTimeReport.new(
39
+ project: project,
39
40
  expected_report_path: expected_report_path,
40
41
  actual_report_path: actual_report_path
41
42
  ).filtered_report
@@ -25,12 +25,12 @@ module GitlabQuality
25
25
 
26
26
  private
27
27
 
28
- attr_reader :gitlab_merge_request, :files, :project, :merge_request_iid, :slow_tests
28
+ attr_reader :token, :project, :gitlab_merge_request, :files, :merge_request_iid, :slow_tests
29
29
 
30
30
  def run!
31
31
  puts "Reporting slow tests in MR #{merge_request_iid}"
32
32
 
33
- TestResults::Builder.new(token: @token, project: @project, file_glob: files).test_results_per_file do |test_results|
33
+ TestResults::Builder.new(token: token, project: project, file_glob: files).test_results_per_file do |test_results|
34
34
  puts "=> Reporting #{test_results.count} tests in #{test_results.path}"
35
35
 
36
36
  @slow_tests += slow_related_tests(find_slow_tests(test_results))
@@ -52,7 +52,7 @@ module GitlabQuality
52
52
  def run!
53
53
  puts "Reporting test failures in `#{files.join(',')}` as issues in project `#{project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
54
54
 
55
- TestResults::Builder.new(token: @token, project: @project, file_glob: files).test_results_per_file do |test_results|
55
+ TestResults::Builder.new(token: token, project: project, file_glob: files).test_results_per_file do |test_results|
56
56
  puts "=> Reporting #{test_results.count} tests in #{test_results.path}"
57
57
  process_test_results(test_results)
58
58
  end
@@ -259,7 +259,7 @@ module GitlabQuality
259
259
 
260
260
  best_matching_issue, smaller_diff_ratio = relevant_issues.min_by { |_, diff_ratio| diff_ratio }
261
261
 
262
- raise(MultipleIssuesFound, %(Too many issues found for test '#{test.name}' (`#{test.file}`)!)) unless relevant_issues.values.count(smaller_diff_ratio) == 1
262
+ raise(MultipleIssuesFound, %(Too many issues found for test '#{test.name}' (`#{test.relative_file}`)!)) unless relevant_issues.values.count(smaller_diff_ratio) == 1
263
263
 
264
264
  # Re-instantiate a `Gitlab::ObjectifiedHash` object after having converted it to a hash in #find_relevant_failure_issues above.
265
265
  best_matching_issue = Gitlab::ObjectifiedHash.new(best_matching_issue)
@@ -9,8 +9,8 @@ module GitlabQuality
9
9
  include Concerns::Utils
10
10
 
11
11
  def initialize(token:, input_files:, related_issues_file: nil, project: nil, confidential: false, dry_run: false, **_kwargs)
12
- @project = project
13
12
  @token = token
13
+ @project = project
14
14
  @gitlab = (dry_run ? GitlabClient::IssuesDryClient : GitlabClient::IssuesClient).new(token: token, project: project)
15
15
  @files = Array(input_files)
16
16
  @confidential = confidential
@@ -29,7 +29,7 @@ module GitlabQuality
29
29
 
30
30
  private
31
31
 
32
- attr_reader :gitlab, :files, :project, :issue_type, :confidential, :issue_logger, :token
32
+ attr_reader :token, :gitlab, :files, :project, :issue_type, :confidential, :issue_logger
33
33
 
34
34
  def run!
35
35
  raise NotImplementedError
@@ -47,7 +47,7 @@ module GitlabQuality
47
47
  # Should not be more than 50 characters if we want it indexed.
48
48
  #
49
49
  # See https://gitlab.com/gitlab-org/ruby/gems/gitlab_quality-test_tooling/-/issues/27#note_1607276486
50
- OpenSSL::Digest.hexdigest('SHA256', "#{test.file}#{test.name}")[..40]
50
+ OpenSSL::Digest.hexdigest('SHA256', "#{test.relative_file}#{test.name}")[..40]
51
51
  end
52
52
 
53
53
  def new_issue_description(test)
@@ -58,8 +58,8 @@ module GitlabQuality
58
58
  | Field | Value |
59
59
  | ------ | ------ |
60
60
  | File URL | #{test.test_file_link} |
61
- | Filename | `#{test.file}` |
62
- | Description | `#{test.name}` |
61
+ | Filename | `#{test.relative_file}` |
62
+ | Description | `` #{test.name} `` |
63
63
  | Test level | `#{test.level}` |
64
64
  | Hash | `#{test_hash(test)}` |
65
65
  | Max expected duration | < #{test.max_duration_for_test} seconds |
@@ -14,7 +14,7 @@ module GitlabQuality
14
14
  def initialize(
15
15
  test_case_project_token:, results_issue_project_token:, input_files:, test_case_project: nil, results_issue_project: nil, dry_run: false,
16
16
  **kwargs)
17
- @results_issue_project_token = results_issue_project_token
17
+ @test_case_project_token = test_case_project_token
18
18
  @testcase_project_reporter = GitlabQuality::TestTooling::Report::ResultsInTestCases.new(
19
19
  token: test_case_project_token, input_files: input_files, project: test_case_project, dry_run: dry_run, **kwargs)
20
20
  @results_issue_project_reporter = GitlabQuality::TestTooling::Report::ResultsInIssues.new(
@@ -32,18 +32,20 @@ module GitlabQuality
32
32
 
33
33
  private
34
34
 
35
+ attr_reader :test_case_project_token
36
+
35
37
  # rubocop:disable Metrics/AbcSize
36
38
  def run!
37
39
  puts "Reporting test results in `#{files.join(',')}` as test cases in project `#{test_case_project}` " \
38
40
  "and issues in project `#{results_issue_project}` via the API at `#{Runtime::Env.gitlab_api_base}`."
39
41
 
40
- TestResults::Builder.new(token: @results_issue_project_token, project: @results_issue_project, file_glob: files).test_results_per_file do |test_results|
42
+ TestResults::Builder.new(token: test_case_project_token, project: test_case_project, file_glob: files).test_results_per_file do |test_results|
41
43
  puts "Reporting tests in #{test_results.path}"
42
44
 
43
45
  test_results.each do |test|
44
46
  next if test.file.include?('/features/sanity/') || test.skipped?
45
47
 
46
- puts "Reporting test: #{test.file} | #{test.name}\n"
48
+ puts "Reporting test: #{test.relative_file} | #{test.name}\n"
47
49
 
48
50
  report_test(test)
49
51
  end
@@ -17,6 +17,7 @@ module GitlabQuality
17
17
  'CI_JOB_URL' => :ci_job_url,
18
18
  'CI_PROJECT_ID' => :ci_project_id,
19
19
  'CI_PROJECT_NAME' => :ci_project_name,
20
+ 'CI_PROJECT_PATH' => :ci_project_path,
20
21
  'CI_PIPELINE_ID' => :ci_pipeline_id,
21
22
  'CI_PIPELINE_URL' => :ci_pipeline_url,
22
23
  'SLACK_QA_CHANNEL' => :slack_qa_channel,
@@ -90,10 +91,6 @@ module GitlabQuality
90
91
  "#{ci_project_name}-#{test_subset}"
91
92
  end
92
93
 
93
- def file_base_url
94
- env_var_value_if_defined('FILE_BASE_URL') || "https://gitlab.com/gitlab-org/gitlab/-/blob/master/"
95
- end
96
-
97
94
  private
98
95
 
99
96
  def enabled?(value, default: true)
@@ -14,6 +14,7 @@ module GitlabQuality
14
14
  def self.collect_results(input_files, **options)
15
15
  sort_by = options[:sort_by]
16
16
  sort_direction = options[:sort_direction]
17
+ hide_passed_tests = options[:hide_passed_tests]
17
18
 
18
19
  stage_wise_results = Dir.glob(input_files).each_with_object([]) do |report_file, stage_wise_results|
19
20
  stage_hash = {}
@@ -21,6 +22,8 @@ module GitlabQuality
21
22
 
22
23
  report_stats = Nokogiri::XML(File.open(report_file)).children[0].attributes
23
24
 
25
+ next if hide_passed_tests && report_stats["failures"].value.to_i.zero? && report_stats["errors"].value.to_i.zero?
26
+
24
27
  stage_hash["Total"] = report_stats["tests"].value
25
28
  stage_hash["Failures"] = report_stats["failures"].value
26
29
  stage_hash["Errors"] = report_stats["errors"].value
@@ -13,7 +13,7 @@ module GitlabQuality
13
13
 
14
14
  attr_reader :report
15
15
 
16
- def initialize(report:, token: nil, project: nil, ref: 'master')
16
+ def initialize(report:, token: '', project: Runtime::Env.ci_project_path, ref: Runtime::Env.ci_commit_ref_name)
17
17
  @report = report
18
18
  @token = token
19
19
  @project = project
@@ -28,7 +28,7 @@ module GitlabQuality
28
28
  raise NotImplementedError
29
29
  end
30
30
 
31
- def file
31
+ def relative_file
32
32
  raise NotImplementedError
33
33
  end
34
34
 
@@ -56,6 +56,18 @@ module GitlabQuality
56
56
  failures.any?
57
57
  end
58
58
 
59
+ def file
60
+ @file ||= relative_file.start_with?('qa/') ? "qa/#{relative_file}" : relative_file
61
+ end
62
+
63
+ def file_base_url
64
+ @file_base_url ||= "https://gitlab.com/#{project}/-/blob/#{ref}/"
65
+ end
66
+
67
+ def test_file_link
68
+ "[`#{file}#L#{line_number}`](#{file_base_url}#{file}#L#{line_number})"
69
+ end
70
+
59
71
  def full_stacktrace
60
72
  failures.each do |failure|
61
73
  message = failure['message'] || ""
@@ -10,7 +10,7 @@ module GitlabQuality
10
10
  report['name']
11
11
  end
12
12
 
13
- def file
13
+ def relative_file
14
14
  report['file']&.delete_prefix('./')
15
15
  end
16
16
 
@@ -98,14 +98,6 @@ module GitlabQuality
98
98
  def failure_issue=(new_failure_issue)
99
99
  report['failure_issue'] = new_failure_issue
100
100
  end
101
-
102
- def test_file_link
103
- return "" if file.nil?
104
-
105
- path_prefix = file.start_with?('qa/') ? 'qa/' : ''
106
-
107
- "[`#{path_prefix}#{file}#L#{line_number}`](#{Runtime::Env.file_base_url}#{path_prefix}#{file}#L#{line_number})"
108
- end
109
101
  end
110
102
  end
111
103
  end
@@ -40,7 +40,7 @@ module GitlabQuality
40
40
  report.fetch('full_description').split('#<').first
41
41
  end
42
42
 
43
- def file
43
+ def relative_file
44
44
  report.fetch('file_path').delete_prefix('./')
45
45
  end
46
46
 
@@ -178,12 +178,6 @@ module GitlabQuality
178
178
  test_level_specification.max_duration
179
179
  end
180
180
 
181
- def test_file_link
182
- path_prefix = file.start_with?('qa/') ? 'qa/' : ''
183
-
184
- "[`#{path_prefix}#{file}#L#{line_number}`](#{Runtime::Env.file_base_url}#{path_prefix}#{file}#L#{line_number})"
185
- end
186
-
187
181
  private
188
182
 
189
183
  def quarantine
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GitlabQuality
4
4
  module TestTooling
5
- VERSION = "1.29.1"
5
+ VERSION = "1.31.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab_quality-test_tooling
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.29.1
4
+ version: 1.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab Quality
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-21 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: climate_control