gitlab_quality-test_tooling 1.29.1 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/exe/post-to-slack +4 -0
- data/lib/gitlab_quality/test_tooling/gitlab_client/repository_files_client.rb +3 -1
- data/lib/gitlab_quality/test_tooling/knapsack_reports/spec_run_time.rb +4 -3
- data/lib/gitlab_quality/test_tooling/knapsack_reports/spec_run_time_report.rb +4 -2
- data/lib/gitlab_quality/test_tooling/report/failed_test_issue.rb +1 -5
- data/lib/gitlab_quality/test_tooling/report/health_problem_reporter.rb +1 -3
- data/lib/gitlab_quality/test_tooling/report/knapsack_report_issue.rb +1 -0
- data/lib/gitlab_quality/test_tooling/report/merge_request_slow_tests_report.rb +2 -2
- data/lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb +2 -2
- data/lib/gitlab_quality/test_tooling/report/report_as_issue.rb +5 -5
- data/lib/gitlab_quality/test_tooling/report/report_results.rb +5 -3
- data/lib/gitlab_quality/test_tooling/runtime/env.rb +1 -4
- data/lib/gitlab_quality/test_tooling/summary_table.rb +3 -0
- data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +14 -2
- data/lib/gitlab_quality/test_tooling/test_result/j_unit_test_result.rb +1 -9
- data/lib/gitlab_quality/test_tooling/test_result/json_test_result.rb +1 -7
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d848eed10080ffc5f609ba56a75e7baf6f60cef5792d66c9c1bf9fdb8dbd2b9
|
4
|
+
data.tar.gz: 5d799f1628b689fda63e0ca68fb70c5f2e6e37d20d867d6ade61e4ff04ea7e57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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
|
@@ -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
|
-
"
|
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,
|
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
|
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:)
|
@@ -25,12 +25,12 @@ module GitlabQuality
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
attr_reader :
|
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:
|
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:
|
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.
|
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
|
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.
|
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.
|
62
|
-
| Description |
|
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
|
-
@
|
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:
|
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.
|
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:
|
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
|
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
|
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
|
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
|
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.
|
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-
|
11
|
+
date: 2024-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|