gitlab_quality-test_tooling 1.3.0 → 1.5.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/exe/relate-failure-issue +4 -0
- data/exe/slow-test-issues +4 -0
- data/lib/gitlab_quality/test_tooling/gitlab_issue_dry_client.rb +2 -2
- data/lib/gitlab_quality/test_tooling/report/concerns/utils.rb +4 -1
- data/lib/gitlab_quality/test_tooling/report/generate_test_session.rb +4 -1
- data/lib/gitlab_quality/test_tooling/report/issue_logger.rb +31 -0
- data/lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb +18 -9
- data/lib/gitlab_quality/test_tooling/report/report_as_issue.rb +14 -4
- data/lib/gitlab_quality/test_tooling/report/slow_test_issue.rb +9 -3
- data/lib/gitlab_quality/test_tooling/runtime/env.rb +5 -1
- data/lib/gitlab_quality/test_tooling/test_result/base_test_result.rb +9 -1
- 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 +5 -7
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ac9e211aa370a7163c4173c7a1dec921cbf237fc406d28e1c3c5cfe296e9750
|
|
4
|
+
data.tar.gz: 99a599cdb8f65c74a489210004f9b34918f03c0d3eb54cd47e3e2dc5a1ee01a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '009549cacd5c20ec47ecc157801f272e00a4681decfa5fbf5ae62e252127f8482313857ad328cda1a68327ae7047c771ec7f6d39cfb0fa835834f9b1a53b519a'
|
|
7
|
+
data.tar.gz: 4bc8d5f83edf2c193ff2fadbc4ae525210a9d9c817dfc48ce35bfa9efcabdecd7801e59165e761a10c2a46d382bc276e1567d45e3ba64905649ce8abab530703
|
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.5.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
|
data/exe/relate-failure-issue
CHANGED
|
@@ -27,6 +27,10 @@ options = OptionParser.new do |opts|
|
|
|
27
27
|
params[:token] = token
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
opts.on('-r', '--related-issues-file RELATED_ISSUES_FILE', String, 'The file path for the related issues') do |related_issues_file|
|
|
31
|
+
params[:related_issues_file] = related_issues_file
|
|
32
|
+
end
|
|
33
|
+
|
|
30
34
|
opts.on('--system-log-files SYSTEM_LOG_FILES', String,
|
|
31
35
|
'Include errors from system logs in failure issues') do |system_log_files|
|
|
32
36
|
params[:system_logs] = system_log_files
|
data/exe/slow-test-issues
CHANGED
|
@@ -23,6 +23,10 @@ options = OptionParser.new do |opts|
|
|
|
23
23
|
params[:token] = token
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
opts.on('-r', '--related-issues-file RELATED_ISSUES_FILE', String, 'The file path for the related issues') do |related_issues_file|
|
|
27
|
+
params[:related_issues_file] = related_issues_file
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
opts.on('--dry-run', "Perform a dry-run (don't create issues)") do
|
|
27
31
|
params[:dry_run] = true
|
|
28
32
|
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module GitlabQuality
|
|
4
4
|
module TestTooling
|
|
5
5
|
class GitlabIssueDryClient < GitlabIssueClient
|
|
6
|
-
def create_issue(title:, description:, labels:, issue_type: 'issue')
|
|
7
|
-
attrs = { description: description, labels: labels }
|
|
6
|
+
def create_issue(title:, description:, labels:, issue_type: 'issue', confidential: false)
|
|
7
|
+
attrs = { description: description, labels: labels, confidential: confidential }
|
|
8
8
|
|
|
9
9
|
puts "The following #{issue_type} would have been created:"
|
|
10
10
|
puts "project: #{project}, title: #{title}, attrs: #{attrs}"
|
|
@@ -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
|
|
@@ -137,6 +138,8 @@ module GitlabQuality
|
|
|
137
138
|
growth
|
|
138
139
|
fulfillment
|
|
139
140
|
enablement
|
|
141
|
+
self-managed
|
|
142
|
+
saas
|
|
140
143
|
]
|
|
141
144
|
|
|
142
145
|
tests.sort_by do |test|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitlabQuality
|
|
4
|
+
module TestTooling
|
|
5
|
+
module Report
|
|
6
|
+
class IssueLogger
|
|
7
|
+
def initialize(file_path:)
|
|
8
|
+
@file_path = file_path
|
|
9
|
+
@data = File.exist?(file_path) ? JSON.parse(File.read(file_path)) : Hash.new { |h, k| h[k] = [] }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def collect(test, issues)
|
|
13
|
+
data[test.ci_job_url] += Array(issues).map(&:web_url)
|
|
14
|
+
data[test.ci_job_url].uniq!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def write
|
|
18
|
+
dirname = File.dirname(file_path)
|
|
19
|
+
|
|
20
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
|
21
|
+
|
|
22
|
+
File.write(file_path, JSON.pretty_generate(data))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :file_path, :data
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -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
|
|
@@ -53,15 +55,20 @@ module GitlabQuality
|
|
|
53
55
|
|
|
54
56
|
TestResults::Builder.new(files).test_results_per_file do |test_results|
|
|
55
57
|
puts "=> Reporting #{test_results.count} tests in #{test_results.path}"
|
|
58
|
+
process_test_results(test_results)
|
|
59
|
+
end
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
write_issues_log_file
|
|
62
|
+
end
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
64
|
+
def process_test_results(test_results)
|
|
65
|
+
systemic_failures = systemic_failures_for_test_results(test_results)
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
test_results.each do |test|
|
|
68
|
+
collect_issues(test, relate_failure_to_issue(test)) if should_report?(test, systemic_failures)
|
|
64
69
|
end
|
|
70
|
+
|
|
71
|
+
test_results.write
|
|
65
72
|
end
|
|
66
73
|
|
|
67
74
|
def systemic_failures_for_test_results(test_results)
|
|
@@ -177,9 +184,12 @@ module GitlabQuality
|
|
|
177
184
|
|
|
178
185
|
def full_stacktrace(test)
|
|
179
186
|
test.failures.each do |failure|
|
|
180
|
-
|
|
187
|
+
message = failure['message'] || ""
|
|
188
|
+
message_lines = failure['message_lines'] || []
|
|
189
|
+
|
|
190
|
+
next if IGNORED_FAILURES.any? { |e| message.include?(e) }
|
|
181
191
|
|
|
182
|
-
return
|
|
192
|
+
return message_lines.empty? ? message : message_lines.join("\n")
|
|
183
193
|
end
|
|
184
194
|
end
|
|
185
195
|
|
|
@@ -201,8 +211,7 @@ module GitlabQuality
|
|
|
201
211
|
end
|
|
202
212
|
|
|
203
213
|
def calculate_diff_ratio(stack_trace_first, stack_trace_second)
|
|
204
|
-
|
|
205
|
-
distance = ld.call(stack_trace_first, stack_trace_second)
|
|
214
|
+
distance = Levenshtein.new(stack_trace_first).match(stack_trace_second)
|
|
206
215
|
distance.zero? ? 0.0 : (distance.to_f / stack_trace_first.size).round(3)
|
|
207
216
|
end
|
|
208
217
|
|
|
@@ -8,11 +8,12 @@ module GitlabQuality
|
|
|
8
8
|
class ReportAsIssue
|
|
9
9
|
include Concerns::Utils
|
|
10
10
|
|
|
11
|
-
def initialize(token:, input_files:, project: nil, confidential: false, dry_run: false, **_kwargs)
|
|
11
|
+
def initialize(token:, input_files:, related_issues_file: nil, project: nil, confidential: false, dry_run: false, **_kwargs)
|
|
12
12
|
@project = project
|
|
13
13
|
@gitlab = (dry_run ? GitlabIssueDryClient : GitlabIssueClient).new(token: token, project: project)
|
|
14
14
|
@files = Array(input_files)
|
|
15
15
|
@confidential = confidential
|
|
16
|
+
@issue_logger = IssueLogger.new(file_path: related_issues_file) if related_issues_file.present?
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def invoke!
|
|
@@ -23,14 +24,22 @@ module GitlabQuality
|
|
|
23
24
|
|
|
24
25
|
private
|
|
25
26
|
|
|
26
|
-
attr_reader :gitlab, :files, :project, :issue_type, :confidential
|
|
27
|
+
attr_reader :gitlab, :files, :project, :issue_type, :confidential, :issue_logger
|
|
27
28
|
|
|
28
29
|
def run!
|
|
29
30
|
raise NotImplementedError
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
def collect_issues(test, issues)
|
|
34
|
+
issue_logger.collect(test, issues) if issue_logger.present?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def write_issues_log_file
|
|
38
|
+
issue_logger.write if issue_logger.present?
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
def test_hash(test)
|
|
33
|
-
OpenSSL::Digest
|
|
42
|
+
OpenSSL::Digest.hexdigest('SHA256', "#{test.file}#{test.name}")
|
|
34
43
|
end
|
|
35
44
|
|
|
36
45
|
def new_issue_description(test)
|
|
@@ -131,7 +140,8 @@ module GitlabQuality
|
|
|
131
140
|
|
|
132
141
|
gitlab.find_issues(options: search_options).find_all do |issue|
|
|
133
142
|
issue_title = issue.title.strip
|
|
134
|
-
|
|
143
|
+
test_file_path_found = !test.file.to_s.empty? && issue_title.include?(partial_file_path(test.file))
|
|
144
|
+
issue_title.include?(test.name) || test_file_path_found
|
|
135
145
|
end
|
|
136
146
|
end
|
|
137
147
|
|
|
@@ -30,6 +30,8 @@ module GitlabQuality
|
|
|
30
30
|
create_slow_issue(test) if test.slow_test?
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
write_issues_log_file
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def new_issue_title(test)
|
|
@@ -51,11 +53,15 @@ module GitlabQuality
|
|
|
51
53
|
|
|
52
54
|
issues = find_issues(test, SEARCH_LABELS, state: 'opened')
|
|
53
55
|
|
|
54
|
-
issues.
|
|
55
|
-
|
|
56
|
+
if issues.blank?
|
|
57
|
+
issues << create_issue(test)
|
|
58
|
+
else
|
|
59
|
+
issues.each do |issue|
|
|
60
|
+
puts " => Existing issue link #{issue['web_url']}"
|
|
61
|
+
end
|
|
56
62
|
end
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
collect_issues(test, issues)
|
|
59
65
|
rescue MultipleIssuesFound => e
|
|
60
66
|
warn(e.message)
|
|
61
67
|
end
|
|
@@ -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 stage
|
|
14
|
-
@stage ||= file[%r{(?:api|browser_ui)/(?:(?:\d+_)?(\w+))}, 1]
|
|
14
|
+
@stage ||= file[%r{(?:api|browser_ui)/(?:(?:\d+_)?(\w+))}, 1] || category
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def name
|
|
@@ -22,6 +22,10 @@ module GitlabQuality
|
|
|
22
22
|
raise NotImplementedError
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def category
|
|
26
|
+
raise NotImplementedError
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
def skipped?
|
|
26
30
|
raise NotImplementedError
|
|
27
31
|
end
|
|
@@ -29,6 +33,10 @@ module GitlabQuality
|
|
|
29
33
|
def failures
|
|
30
34
|
raise NotImplementedError
|
|
31
35
|
end
|
|
36
|
+
|
|
37
|
+
def failures?
|
|
38
|
+
failures.any?
|
|
39
|
+
end
|
|
32
40
|
end
|
|
33
41
|
end
|
|
34
42
|
end
|
|
@@ -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
|
|
@@ -90,6 +88,10 @@ module GitlabQuality
|
|
|
90
88
|
report['feature_category']
|
|
91
89
|
end
|
|
92
90
|
|
|
91
|
+
def category
|
|
92
|
+
report['category']
|
|
93
|
+
end
|
|
94
|
+
|
|
93
95
|
def run_time
|
|
94
96
|
report['run_time'].to_f.round(2)
|
|
95
97
|
end
|
|
@@ -132,10 +134,6 @@ module GitlabQuality
|
|
|
132
134
|
end
|
|
133
135
|
end
|
|
134
136
|
|
|
135
|
-
def failures?
|
|
136
|
-
failures.any?
|
|
137
|
-
end
|
|
138
|
-
|
|
139
137
|
def allowed_to_be_slow?
|
|
140
138
|
!!report['allowed_to_be_slow']
|
|
141
139
|
end
|
|
@@ -156,7 +154,7 @@ module GitlabQuality
|
|
|
156
154
|
def test_file_link
|
|
157
155
|
path_prefix = file.start_with?('qa/') ? 'qa/' : ''
|
|
158
156
|
|
|
159
|
-
"[`#{path_prefix}#{file}#L#{line_number}`](#{
|
|
157
|
+
"[`#{path_prefix}#{file}#L#{line_number}`](#{Runtime::Env.file_base_url}#{path_prefix}#{file}#L#{line_number})"
|
|
160
158
|
end
|
|
161
159
|
|
|
162
160
|
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.5.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-
|
|
11
|
+
date: 2023-11-02 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
|
|
@@ -363,6 +377,7 @@ files:
|
|
|
363
377
|
- lib/gitlab_quality/test_tooling/report/concerns/results_reporter.rb
|
|
364
378
|
- lib/gitlab_quality/test_tooling/report/concerns/utils.rb
|
|
365
379
|
- lib/gitlab_quality/test_tooling/report/generate_test_session.rb
|
|
380
|
+
- lib/gitlab_quality/test_tooling/report/issue_logger.rb
|
|
366
381
|
- lib/gitlab_quality/test_tooling/report/merge_request_slow_tests_report.rb
|
|
367
382
|
- lib/gitlab_quality/test_tooling/report/prepare_stage_reports.rb
|
|
368
383
|
- lib/gitlab_quality/test_tooling/report/relate_failure_issue.rb
|