gitlab_quality-test_tooling 1.3.0 → 1.4.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 +15 -1
- data/README.md +9 -14
- data/exe/generate-test-session +4 -0
- data/lib/gitlab_quality/test_tooling/report/concerns/utils.rb +4 -1
- data/lib/gitlab_quality/test_tooling/report/generate_test_session.rb +2 -1
- data/lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb +8 -4
- data/lib/gitlab_quality/test_tooling/report/report_as_issue.rb +3 -2
- data/lib/gitlab_quality/test_tooling/runtime/env.rb +5 -1
- data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +4 -0
- data/lib/gitlab_quality/test_tooling/test_result/j_unit_test_result.rb +72 -4
- 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 +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7237e27f052e0d9934df2a8ad8d8d413cb1db81b4bc30fd334458cd05ee23494
|
4
|
+
data.tar.gz: 1775470edd1236836c8f4a2f729d40d642d6e9fde2c40630b79925f84c821e8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d77a24b7561c7d1b194a68290d0334d46e2c10120b3457f0288b53f161421bedccb6ff6c638e519d1a8c788e300b4b7ba543b7b5c45ad59b314ec05867e1be4
|
7
|
+
data.tar.gz: c384fda5b0c98647804c19880d581c0ccdf233dccd82c52b0f1aaf83fd56c729b3fdd33628433b9b278f48073a0e446ced610c5ee04408717dfbe919e9d3e77b
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gitlab_quality-test_tooling (1.
|
4
|
+
gitlab_quality-test_tooling (1.4.0)
|
5
5
|
activesupport (>= 6.1, < 7.2)
|
6
|
+
amatch (~> 0.4.1)
|
6
7
|
gitlab (~> 4.19)
|
7
8
|
http (~> 5.0)
|
8
9
|
nokogiri (~> 1.10)
|
@@ -22,6 +23,9 @@ GEM
|
|
22
23
|
zeitwerk (~> 2.3)
|
23
24
|
addressable (2.8.4)
|
24
25
|
public_suffix (>= 2.0.2, < 6.0)
|
26
|
+
amatch (0.4.1)
|
27
|
+
mize
|
28
|
+
tins (~> 1.0)
|
25
29
|
ast (2.4.2)
|
26
30
|
backport (1.2.0)
|
27
31
|
benchmark (0.2.1)
|
@@ -132,6 +136,8 @@ GEM
|
|
132
136
|
mini_mime (1.1.2)
|
133
137
|
mini_portile2 (2.8.1)
|
134
138
|
minitest (5.18.0)
|
139
|
+
mize (0.4.1)
|
140
|
+
protocol (~> 2.0)
|
135
141
|
multi_xml (0.6.0)
|
136
142
|
nap (1.1.0)
|
137
143
|
nenv (0.3.0)
|
@@ -149,6 +155,8 @@ GEM
|
|
149
155
|
parallel (1.23.0)
|
150
156
|
parser (3.2.2.1)
|
151
157
|
ast (~> 2.4.1)
|
158
|
+
protocol (2.0.0)
|
159
|
+
ruby_parser (~> 3.0)
|
152
160
|
pry (0.14.2)
|
153
161
|
coderay (~> 1.1)
|
154
162
|
method_source (~> 1.0)
|
@@ -207,9 +215,12 @@ GEM
|
|
207
215
|
rubocop-capybara (~> 2.17)
|
208
216
|
ruby-progressbar (1.13.0)
|
209
217
|
ruby2_keywords (0.0.5)
|
218
|
+
ruby_parser (3.20.3)
|
219
|
+
sexp_processor (~> 4.16)
|
210
220
|
sawyer (0.9.2)
|
211
221
|
addressable (>= 2.3.5)
|
212
222
|
faraday (>= 0.17.3, < 3)
|
223
|
+
sexp_processor (4.17.0)
|
213
224
|
shellany (0.0.1)
|
214
225
|
simplecov (0.22.0)
|
215
226
|
docile (~> 1.1)
|
@@ -236,12 +247,15 @@ GEM
|
|
236
247
|
thor (~> 1.0)
|
237
248
|
tilt (~> 2.0)
|
238
249
|
yard (~> 0.9, >= 0.9.24)
|
250
|
+
sync (0.5.0)
|
239
251
|
table_print (1.5.7)
|
240
252
|
terminal-table (3.0.2)
|
241
253
|
unicode-display_width (>= 1.1.1, < 3)
|
242
254
|
thor (1.2.1)
|
243
255
|
tilt (2.1.0)
|
244
256
|
timecop (0.9.6)
|
257
|
+
tins (1.32.1)
|
258
|
+
sync
|
245
259
|
tzinfo (2.0.6)
|
246
260
|
concurrent-ruby (~> 1.0)
|
247
261
|
unf (0.1.4)
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ $ gem install gitlab_quality-test_tooling
|
|
26
26
|
|
27
27
|
The gem provides the following executables.
|
28
28
|
|
29
|
-
### `generate-test-session`
|
29
|
+
### `exe/generate-test-session`
|
30
30
|
|
31
31
|
```shell
|
32
32
|
Purpose: Generate test session report based on RSpec report files (JSON or JUnit XML)
|
@@ -38,15 +38,15 @@ Usage: exe/generate-test-session [options]
|
|
38
38
|
--ci-project-token
|
39
39
|
-f ISSUE_URL_FILE, Output the created test session issue URL
|
40
40
|
--issue-url-file
|
41
|
+
--confidential Makes test session issue confidential
|
41
42
|
--dry-run Perform a dry-run (don't create or update issues or test cases)
|
42
43
|
-v, --version Show the version
|
43
44
|
-h, --help Show the usage
|
44
45
|
```
|
45
46
|
|
46
|
-
### `post-to-slack`
|
47
|
+
### `exe/post-to-slack`
|
47
48
|
|
48
49
|
```shell
|
49
|
-
$ exe/post-to-slack -h
|
50
50
|
Purpose: Post a message to Slack, and optionally add a test summary table based on RSpec report files (JUnit XML)
|
51
51
|
Usage: exe/post-to-slack [options]
|
52
52
|
-w SLACK_WEBHOOK_URL, Slack webhook URL
|
@@ -61,10 +61,9 @@ Usage: exe/post-to-slack [options]
|
|
61
61
|
-h, --help Show the usage
|
62
62
|
```
|
63
63
|
|
64
|
-
### `prepare-stage-reports`
|
64
|
+
### `exe/prepare-stage-reports`
|
65
65
|
|
66
66
|
```shell
|
67
|
-
$ exe/prepare-stage-reports -h
|
68
67
|
Purpose: Prepare separate reports for each DevOps stage from the provided RSpec report files (JUnit XML)
|
69
68
|
Usage: exe/prepare-stage-reports [options]
|
70
69
|
-i, --input-files INPUT_FILES RSpec report files (JUnit XML)
|
@@ -72,10 +71,9 @@ Usage: exe/prepare-stage-reports [options]
|
|
72
71
|
-h, --help Show the usage
|
73
72
|
```
|
74
73
|
|
75
|
-
### `relate-failure-issue`
|
74
|
+
### `exe/relate-failure-issue`
|
76
75
|
|
77
76
|
```shell
|
78
|
-
$ exe/relate-failure-issue -h
|
79
77
|
Purpose: Relate test failures to failure issues from RSpec report files (JSON or JUnit XML)
|
80
78
|
Usage: exe/relate-failure-issue [options]
|
81
79
|
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
@@ -93,10 +91,9 @@ Usage: exe/relate-failure-issue [options]
|
|
93
91
|
-h, --help Show the usage
|
94
92
|
```
|
95
93
|
|
96
|
-
### `report-results`
|
94
|
+
### `exe/report-results`
|
97
95
|
|
98
96
|
```shell
|
99
|
-
$ exe/report-results -h
|
100
97
|
Purpose: Report test results from RSpec report files (JSON or JUnit XML) in GitLab test cases and result issues
|
101
98
|
Usage: exe/report-results [options]
|
102
99
|
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
@@ -113,10 +110,9 @@ Usage: exe/report-results [options]
|
|
113
110
|
-h, --help Show the usage
|
114
111
|
```
|
115
112
|
|
116
|
-
### `update-screenshot-paths`
|
113
|
+
### `exe/update-screenshot-paths`
|
117
114
|
|
118
115
|
```shell
|
119
|
-
$ exe/update-screenshot-paths -h
|
120
116
|
Purpose: Update the path to screenshots to container's host from RSpec report files (JSON or JUnit XML)
|
121
117
|
Usage: exe/update-screenshot-paths [options]
|
122
118
|
-i, --input-files INPUT_FILES RSpec report files (JSON or JUnit XML)
|
@@ -124,7 +120,7 @@ Usage: exe/update-screenshot-paths [options]
|
|
124
120
|
-h, --help Show the usage
|
125
121
|
```
|
126
122
|
|
127
|
-
### `slow-test-issues`
|
123
|
+
### `exe/slow-test-issues`
|
128
124
|
|
129
125
|
```shell
|
130
126
|
Purpose: Create slow test issues from JSON RSpec report files
|
@@ -137,10 +133,9 @@ Usage: exe/slow-test-issue [options]
|
|
137
133
|
-h, --help Show the usage
|
138
134
|
```
|
139
135
|
|
140
|
-
### `slow-test-merge-request-report-note`
|
136
|
+
### `exe/slow-test-merge-request-report-note`
|
141
137
|
|
142
138
|
```shell
|
143
|
-
$ exe/slow-test-merge-request-report-note -h
|
144
139
|
Purpose: Create slow test note on merge requests from JSON RSpec report files
|
145
140
|
Usage: exe/slow-test-merge-request-report-note [options]
|
146
141
|
-i, --input-files INPUT_FILES JSON RSpec report files JSON
|
data/exe/generate-test-session
CHANGED
@@ -31,6 +31,10 @@ options = OptionParser.new do |opts|
|
|
31
31
|
params[:issue_url_file] = issue_url_file
|
32
32
|
end
|
33
33
|
|
34
|
+
opts.on('--confidential', "Makes test session issue confidential") do
|
35
|
+
params[:confidential] = true
|
36
|
+
end
|
37
|
+
|
34
38
|
opts.on('--dry-run', "Perform a dry-run (don't create or update issues or test cases)") do
|
35
39
|
params[:dry_run] = true
|
36
40
|
end
|
@@ -20,7 +20,10 @@ module GitlabQuality
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def partial_file_path(path)
|
23
|
-
path
|
23
|
+
matched = path&.match(%r{(?<partial_path>(?:spec|ee|api|browser_ui)/.*)}i)
|
24
|
+
return matched[:partial_path] if matched
|
25
|
+
|
26
|
+
path
|
24
27
|
end
|
25
28
|
|
26
29
|
def search_safe(value)
|
@@ -30,7 +30,8 @@ module GitlabQuality
|
|
30
30
|
issue = gitlab.create_issue(
|
31
31
|
title: "#{Time.now.strftime('%Y-%m-%d')} Test session report | #{Runtime::Env.qa_run_type}",
|
32
32
|
description: generate_description(tests),
|
33
|
-
labels: ['Quality', 'QA', 'triage report', pipeline_name_label]
|
33
|
+
labels: ['Quality', 'QA', 'triage report', pipeline_name_label],
|
34
|
+
confidential: confidential
|
34
35
|
)
|
35
36
|
|
36
37
|
# Workaround for https://gitlab.com/gitlab-org/gitlab/-/issues/295493
|
@@ -4,6 +4,7 @@ require 'nokogiri'
|
|
4
4
|
require 'active_support/core_ext/enumerable'
|
5
5
|
require 'rubygems/text'
|
6
6
|
require 'active_support/core_ext/integer/time'
|
7
|
+
require 'amatch'
|
7
8
|
|
8
9
|
module GitlabQuality
|
9
10
|
module TestTooling
|
@@ -17,6 +18,7 @@ module GitlabQuality
|
|
17
18
|
class RelateFailureIssue < ReportAsIssue
|
18
19
|
include Concerns::FindSetDri
|
19
20
|
include Concerns::GroupAndCategoryLabels
|
21
|
+
include Amatch
|
20
22
|
|
21
23
|
DEFAULT_MAX_DIFF_RATIO_FOR_DETECTION = 0.15
|
22
24
|
SYSTEMIC_EXCEPTIONS_THRESHOLD = 10
|
@@ -177,9 +179,12 @@ module GitlabQuality
|
|
177
179
|
|
178
180
|
def full_stacktrace(test)
|
179
181
|
test.failures.each do |failure|
|
180
|
-
|
182
|
+
message = failure['message'] || ""
|
183
|
+
message_lines = failure['message_lines'] || []
|
181
184
|
|
182
|
-
|
185
|
+
next if IGNORED_FAILURES.any? { |e| message.include?(e) }
|
186
|
+
|
187
|
+
return message_lines.empty? ? message : message_lines.join("\n")
|
183
188
|
end
|
184
189
|
end
|
185
190
|
|
@@ -201,8 +206,7 @@ module GitlabQuality
|
|
201
206
|
end
|
202
207
|
|
203
208
|
def calculate_diff_ratio(stack_trace_first, stack_trace_second)
|
204
|
-
|
205
|
-
distance = ld.call(stack_trace_first, stack_trace_second)
|
209
|
+
distance = Levenshtein.new(stack_trace_first).match(stack_trace_second)
|
206
210
|
distance.zero? ? 0.0 : (distance.to_f / stack_trace_first.size).round(3)
|
207
211
|
end
|
208
212
|
|
@@ -30,7 +30,7 @@ module GitlabQuality
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_hash(test)
|
33
|
-
OpenSSL::Digest
|
33
|
+
OpenSSL::Digest.hexdigest('SHA256', "#{test.file}#{test.name}")
|
34
34
|
end
|
35
35
|
|
36
36
|
def new_issue_description(test)
|
@@ -131,7 +131,8 @@ module GitlabQuality
|
|
131
131
|
|
132
132
|
gitlab.find_issues(options: search_options).find_all do |issue|
|
133
133
|
issue_title = issue.title.strip
|
134
|
-
|
134
|
+
test_file_path_found = !test.file.to_s.empty? && issue_title.include?(partial_file_path(test.file))
|
135
|
+
issue_title.include?(test.name) || test_file_path_found
|
135
136
|
end
|
136
137
|
end
|
137
138
|
|
@@ -50,7 +50,7 @@ module GitlabQuality
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def pipeline_from_project_name
|
53
|
-
ci_project_name.to_s.start_with?(
|
53
|
+
%w[gitlab gitaly].any? { |str| ci_project_name.to_s.start_with?(str) } ? default_branch : ci_project_name
|
54
54
|
end
|
55
55
|
|
56
56
|
def run_id
|
@@ -88,6 +88,10 @@ module GitlabQuality
|
|
88
88
|
"#{ci_project_name}-#{test_subset}"
|
89
89
|
end
|
90
90
|
|
91
|
+
def file_base_url
|
92
|
+
env_var_value_if_defined('FILE_BASE_URL') || "https://gitlab.com/gitlab-org/gitlab/-/blob/master/"
|
93
|
+
end
|
94
|
+
|
91
95
|
private
|
92
96
|
|
93
97
|
def enabled?(value, default: true)
|
@@ -11,7 +11,7 @@ module GitlabQuality
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def file
|
14
|
-
report['file']
|
14
|
+
report['file']&.delete_prefix('./')
|
15
15
|
end
|
16
16
|
|
17
17
|
def skipped?
|
@@ -25,17 +25,85 @@ module GitlabQuality
|
|
25
25
|
failures.map do |exception|
|
26
26
|
trace = exception.content.split("\n").map(&:strip)
|
27
27
|
spec_file_first_index = trace.rindex do |line|
|
28
|
-
line.include?(File.basename(report['file']))
|
28
|
+
report['file'] && line.include?(File.basename(report['file']))
|
29
29
|
end
|
30
30
|
|
31
31
|
exception['message'].gsub!(/(private_token=)[\w-]+/, '********')
|
32
|
-
|
32
|
+
exception.content = exception.content.gsub(/(private_token=)[\w-]+/, '********')
|
33
33
|
{
|
34
34
|
'message' => "#{exception['type']}: #{exception['message']}",
|
35
|
-
'stacktrace' => trace.slice(0..spec_file_first_index).join("\n")
|
35
|
+
'stacktrace' => trace.slice(0..spec_file_first_index).join("\n"),
|
36
|
+
'message_lines' => trace.slice(0..spec_file_first_index)
|
36
37
|
}
|
37
38
|
end
|
38
39
|
end
|
40
|
+
|
41
|
+
def quarantine
|
42
|
+
!report['quarantine'].nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def quarantine?
|
46
|
+
# The value for 'quarantine' could be nil, a hash, a string,
|
47
|
+
# or true (if the test just has the :quarantine tag)
|
48
|
+
# But any non-nil or false value should means the test is in quarantine
|
49
|
+
!!quarantine
|
50
|
+
end
|
51
|
+
|
52
|
+
def line_number
|
53
|
+
report['line_number']
|
54
|
+
end
|
55
|
+
|
56
|
+
def level
|
57
|
+
report['level']
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_time
|
61
|
+
report['run_time'].to_f.round(2)
|
62
|
+
end
|
63
|
+
|
64
|
+
def screenshot
|
65
|
+
report['screenshot']
|
66
|
+
end
|
67
|
+
|
68
|
+
def screenshot?
|
69
|
+
!!screenshot
|
70
|
+
end
|
71
|
+
|
72
|
+
def max_duration_for_test
|
73
|
+
""
|
74
|
+
end
|
75
|
+
|
76
|
+
def ci_job_url
|
77
|
+
ENV.fetch('CI_JOB_URL', '')
|
78
|
+
end
|
79
|
+
|
80
|
+
def product_group
|
81
|
+
report['product_group'].to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def product_group?
|
85
|
+
product_group != ''
|
86
|
+
end
|
87
|
+
|
88
|
+
def feature_category
|
89
|
+
report['feature_category']
|
90
|
+
end
|
91
|
+
|
92
|
+
def failure_issue
|
93
|
+
report['failure_issue']
|
94
|
+
end
|
95
|
+
|
96
|
+
def failure_issue=(new_failure_issue)
|
97
|
+
report['failure_issue'] = new_failure_issue
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_file_link
|
101
|
+
return "" if file.nil?
|
102
|
+
|
103
|
+
path_prefix = file.start_with?('qa/') ? 'qa/' : ''
|
104
|
+
|
105
|
+
"[`#{path_prefix}#{file}#L#{line_number}`](#{Runtime::Env.file_base_url}#{path_prefix}#{file}#L#{line_number})"
|
106
|
+
end
|
39
107
|
end
|
40
108
|
end
|
41
109
|
end
|
@@ -4,8 +4,6 @@ module GitlabQuality
|
|
4
4
|
module TestTooling
|
5
5
|
module TestResult
|
6
6
|
class JsonTestResult < BaseTestResult
|
7
|
-
FILE_BASE_URL = "https://gitlab.com/gitlab-org/gitlab/-/blob/master/"
|
8
|
-
|
9
7
|
PRIVATE_TOKEN_REGEX = /(private_token=)[\w-]+/
|
10
8
|
|
11
9
|
OTHER_TESTS_MAX_DURATION = 45.40 # seconds
|
@@ -132,10 +130,6 @@ module GitlabQuality
|
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
135
|
-
def failures?
|
136
|
-
failures.any?
|
137
|
-
end
|
138
|
-
|
139
133
|
def allowed_to_be_slow?
|
140
134
|
!!report['allowed_to_be_slow']
|
141
135
|
end
|
@@ -156,7 +150,7 @@ module GitlabQuality
|
|
156
150
|
def test_file_link
|
157
151
|
path_prefix = file.start_with?('qa/') ? 'qa/' : ''
|
158
152
|
|
159
|
-
"[`#{path_prefix}#{file}#L#{line_number}`](#{
|
153
|
+
"[`#{path_prefix}#{file}#L#{line_number}`](#{Runtime::Env.file_base_url}#{path_prefix}#{file}#L#{line_number})"
|
160
154
|
end
|
161
155
|
|
162
156
|
private
|
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.4.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: 2023-10-
|
11
|
+
date: 2023-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: climate_control
|
@@ -198,6 +198,20 @@ dependencies:
|
|
198
198
|
- - "<"
|
199
199
|
- !ruby/object:Gem::Version
|
200
200
|
version: '7.2'
|
201
|
+
- !ruby/object:Gem::Dependency
|
202
|
+
name: amatch
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - "~>"
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: 0.4.1
|
208
|
+
type: :runtime
|
209
|
+
prerelease: false
|
210
|
+
version_requirements: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - "~>"
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: 0.4.1
|
201
215
|
- !ruby/object:Gem::Dependency
|
202
216
|
name: gitlab
|
203
217
|
requirement: !ruby/object:Gem::Requirement
|