gitlab_quality-test_tooling 1.39.0 → 2.1.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/.rubocop_todo.yml +50 -11
- data/.ruby-version +1 -1
- data/.tool-versions +2 -1
- data/Gemfile.lock +124 -116
- data/README.md +14 -0
- data/exe/existing-test-health-issue +59 -0
- data/lib/gitlab_quality/test_tooling/report/failed_test_issue.rb +84 -6
- data/lib/gitlab_quality/test_tooling/report/flaky_test_issue.rb +1 -1
- data/lib/gitlab_quality/test_tooling/report/health_problem_reporter.rb +27 -77
- data/lib/gitlab_quality/test_tooling/report/slow_test_issue.rb +1 -1
- data/lib/gitlab_quality/test_tooling/report/test_health_issue_finder.rb +79 -0
- data/lib/gitlab_quality/test_tooling/version.rb +1 -1
- metadata +30 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69b4478a8c7af86d2dae63c79d0924037feb673486f1ae6f15d5617121a0b9f4
|
|
4
|
+
data.tar.gz: 9a7f797d54687a515d834cfe0585bca7b87f5a28cd33000d5c06ebea292de56e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50206a9f212b2d78ab38b8433ffb5f22864e8a322b6065b6492a9023104e2caf0097042c8935c913f7d16de982fd3fb04a8438d294865f61caac84eee60d943e
|
|
7
|
+
data.tar.gz: 1267891667d8bf81617843d65ea6cd9bee2aef24007a2dc53ba92d970529f771dcbf8b8209aba7d59531f40ffac2e2c549444441dcae123c8e70bac1c0d417e7
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2024-10-10 06:12:01 UTC using RuboCop version 1.62.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count: 1
|
|
10
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
-
Cop/CustomErrorClass:
|
|
12
|
-
Exclude:
|
|
13
|
-
- 'lib/gitlab_quality/test_tooling.rb'
|
|
14
|
-
|
|
15
9
|
# Offense count: 1
|
|
16
10
|
# This cop supports safe autocorrection (--autocorrect).
|
|
17
11
|
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
|
|
@@ -20,9 +14,54 @@ Gemspec/OrderedDependencies:
|
|
|
20
14
|
Exclude:
|
|
21
15
|
- 'gitlab_quality-test_tooling.gemspec'
|
|
22
16
|
|
|
17
|
+
# Offense count: 3
|
|
18
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
19
|
+
# Configuration parameters: Categories, ExpectedOrder.
|
|
20
|
+
# ExpectedOrder: module_inclusion, constants, public_class_methods, initializer, public_methods, protected_methods, private_methods
|
|
21
|
+
Layout/ClassStructure:
|
|
22
|
+
Exclude:
|
|
23
|
+
- 'lib/gitlab_quality/test_tooling/labels_inference.rb'
|
|
24
|
+
- 'lib/gitlab_quality/test_tooling/report/concerns/issue_reports.rb'
|
|
25
|
+
- 'lib/gitlab_quality/test_tooling/report/update_screenshot_path.rb'
|
|
26
|
+
|
|
27
|
+
# Offense count: 6
|
|
28
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
29
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
30
|
+
# SupportedStyles: aligned, indented
|
|
31
|
+
Layout/LineEndStringConcatenationIndentation:
|
|
32
|
+
Exclude:
|
|
33
|
+
- 'lib/gitlab_quality/test_tooling/gitlab_client/merge_requests_dry_client.rb'
|
|
34
|
+
- 'lib/gitlab_quality/test_tooling/report/report_results.rb'
|
|
35
|
+
- 'spec/gitlab_quality/test_tooling/gitlab_client/issues_client_spec.rb'
|
|
36
|
+
- 'spec/gitlab_quality/test_tooling/report/failed_test_issue_spec.rb'
|
|
37
|
+
- 'spec/gitlab_quality/test_tooling/report/slow_test_issue_spec.rb'
|
|
38
|
+
|
|
39
|
+
# Offense count: 200
|
|
40
|
+
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
|
|
41
|
+
# SupportedStyles: always, named_only
|
|
42
|
+
RSpec/NamedSubject:
|
|
43
|
+
Enabled: false
|
|
44
|
+
|
|
45
|
+
# Offense count: 2
|
|
46
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
47
|
+
# Configuration parameters: AllowOnlyRestArgument, UseAnonymousForwarding, RedundantRestArgumentNames, RedundantKeywordRestArgumentNames, RedundantBlockArgumentNames.
|
|
48
|
+
# RedundantRestArgumentNames: args, arguments
|
|
49
|
+
# RedundantKeywordRestArgumentNames: kwargs, options, opts
|
|
50
|
+
# RedundantBlockArgumentNames: blk, block, proc
|
|
51
|
+
Style/ArgumentsForwarding:
|
|
52
|
+
Exclude:
|
|
53
|
+
- 'lib/gitlab_quality/test_tooling/test_results/base_test_results.rb'
|
|
54
|
+
|
|
55
|
+
# Offense count: 2
|
|
56
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
57
|
+
# Configuration parameters: AllowMultipleReturnValues.
|
|
58
|
+
Style/RedundantReturn:
|
|
59
|
+
Exclude:
|
|
60
|
+
- 'lib/gitlab_quality/test_tooling/runtime/env.rb'
|
|
61
|
+
|
|
23
62
|
# Offense count: 1
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
|
|
63
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
64
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
65
|
+
Style/ReturnNilInPredicateMethodDefinition:
|
|
27
66
|
Exclude:
|
|
28
|
-
- 'gitlab_quality
|
|
67
|
+
- 'lib/gitlab_quality/test_tooling/knapsack_reports/spec_run_time.rb'
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.2.
|
|
1
|
+
3.2.5
|
data/.tool-versions
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
ruby 3.
|
|
1
|
+
ruby 3.2.5
|
|
2
|
+
lefthook 1.7.14
|
data/Gemfile.lock
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gitlab_quality-test_tooling (1.
|
|
4
|
+
gitlab_quality-test_tooling (2.1.0)
|
|
5
5
|
activesupport (>= 7.0, < 7.2)
|
|
6
6
|
amatch (~> 0.4.1)
|
|
7
7
|
fog-google (~> 1.24, >= 1.24.1)
|
|
8
|
-
gitlab (
|
|
8
|
+
gitlab (>= 4.19, < 6.0)
|
|
9
9
|
http (~> 5.0)
|
|
10
10
|
influxdb-client (~> 3.1)
|
|
11
11
|
nokogiri (~> 1.10)
|
|
@@ -18,7 +18,7 @@ PATH
|
|
|
18
18
|
GEM
|
|
19
19
|
remote: https://rubygems.org/
|
|
20
20
|
specs:
|
|
21
|
-
activesupport (7.1.
|
|
21
|
+
activesupport (7.1.4)
|
|
22
22
|
base64
|
|
23
23
|
bigdecimal
|
|
24
24
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
@@ -28,8 +28,8 @@ GEM
|
|
|
28
28
|
minitest (>= 5.1)
|
|
29
29
|
mutex_m
|
|
30
30
|
tzinfo (~> 2.0)
|
|
31
|
-
addressable (2.8.
|
|
32
|
-
public_suffix (>= 2.0.2, <
|
|
31
|
+
addressable (2.8.7)
|
|
32
|
+
public_suffix (>= 2.0.2, < 7.0)
|
|
33
33
|
amatch (0.4.1)
|
|
34
34
|
mize
|
|
35
35
|
tins (~> 1.0)
|
|
@@ -38,8 +38,8 @@ GEM
|
|
|
38
38
|
base64 (0.2.0)
|
|
39
39
|
benchmark (0.3.0)
|
|
40
40
|
bigdecimal (3.1.8)
|
|
41
|
-
binding_of_caller (1.0.
|
|
42
|
-
debug_inspector (>=
|
|
41
|
+
binding_of_caller (1.0.1)
|
|
42
|
+
debug_inspector (>= 1.2.0)
|
|
43
43
|
builder (3.3.0)
|
|
44
44
|
byebug (11.1.3)
|
|
45
45
|
claide (1.1.0)
|
|
@@ -50,13 +50,15 @@ GEM
|
|
|
50
50
|
climate_control (1.2.0)
|
|
51
51
|
coderay (1.1.3)
|
|
52
52
|
colored2 (3.1.2)
|
|
53
|
-
concurrent-ruby (1.
|
|
53
|
+
concurrent-ruby (1.3.4)
|
|
54
54
|
connection_pool (2.4.1)
|
|
55
55
|
cork (0.3.0)
|
|
56
56
|
colored2 (~> 3.1)
|
|
57
|
-
crack (0.
|
|
57
|
+
crack (1.0.0)
|
|
58
|
+
bigdecimal
|
|
58
59
|
rexml
|
|
59
|
-
|
|
60
|
+
csv (3.3.0)
|
|
61
|
+
danger (9.5.0)
|
|
60
62
|
claide (~> 1.0)
|
|
61
63
|
claide-plugins (>= 0.9.2)
|
|
62
64
|
colored2 (~> 3.1)
|
|
@@ -66,29 +68,30 @@ GEM
|
|
|
66
68
|
git (~> 1.13)
|
|
67
69
|
kramdown (~> 2.3)
|
|
68
70
|
kramdown-parser-gfm (~> 1.0)
|
|
69
|
-
no_proxy_fix
|
|
70
71
|
octokit (>= 4.0)
|
|
71
72
|
terminal-table (>= 1, < 4)
|
|
72
|
-
danger-gitlab (
|
|
73
|
+
danger-gitlab (9.0.0)
|
|
73
74
|
danger
|
|
74
|
-
gitlab (~>
|
|
75
|
+
gitlab (~> 5.0)
|
|
75
76
|
debug_inspector (1.2.0)
|
|
76
77
|
declarative (0.0.20)
|
|
77
|
-
diff-lcs (1.5.
|
|
78
|
-
docile (1.4.
|
|
78
|
+
diff-lcs (1.5.1)
|
|
79
|
+
docile (1.4.1)
|
|
79
80
|
domain_name (0.6.20240107)
|
|
80
81
|
drb (2.2.1)
|
|
81
82
|
e2mmap (0.1.0)
|
|
82
|
-
excon (0.
|
|
83
|
-
faraday (2.
|
|
84
|
-
faraday-net_http (>= 2.0, < 3.
|
|
83
|
+
excon (0.112.0)
|
|
84
|
+
faraday (2.12.0)
|
|
85
|
+
faraday-net_http (>= 2.0, < 3.4)
|
|
86
|
+
json
|
|
87
|
+
logger
|
|
85
88
|
faraday-http-cache (2.5.1)
|
|
86
89
|
faraday (>= 0.8)
|
|
87
|
-
faraday-net_http (3.
|
|
90
|
+
faraday-net_http (3.3.0)
|
|
88
91
|
net-http
|
|
89
|
-
ffi (1.
|
|
90
|
-
ffi-compiler (1.
|
|
91
|
-
ffi (>= 1.
|
|
92
|
+
ffi (1.17.0)
|
|
93
|
+
ffi-compiler (1.3.2)
|
|
94
|
+
ffi (>= 1.15.5)
|
|
92
95
|
rake
|
|
93
96
|
fog-core (2.4.0)
|
|
94
97
|
builder
|
|
@@ -118,44 +121,45 @@ GEM
|
|
|
118
121
|
git (1.19.1)
|
|
119
122
|
addressable (~> 2.8)
|
|
120
123
|
rchardet (~> 1.8)
|
|
121
|
-
gitlab (
|
|
124
|
+
gitlab (5.0.0)
|
|
122
125
|
httparty (~> 0.20)
|
|
123
126
|
terminal-table (>= 1.5.1)
|
|
124
127
|
gitlab-dangerfiles (3.13.0)
|
|
125
128
|
danger (>= 8.4.5)
|
|
126
129
|
danger-gitlab (>= 8.0.0)
|
|
127
130
|
rake
|
|
128
|
-
gitlab-styles (
|
|
129
|
-
rubocop (~> 1.
|
|
130
|
-
rubocop-
|
|
131
|
-
rubocop-
|
|
132
|
-
rubocop-
|
|
133
|
-
rubocop-
|
|
134
|
-
|
|
131
|
+
gitlab-styles (12.0.1)
|
|
132
|
+
rubocop (~> 1.62.1)
|
|
133
|
+
rubocop-factory_bot (~> 2.25.1)
|
|
134
|
+
rubocop-graphql (~> 1.5.0)
|
|
135
|
+
rubocop-performance (~> 1.20.2)
|
|
136
|
+
rubocop-rails (~> 2.24.0)
|
|
137
|
+
rubocop-rspec (~> 2.27.1)
|
|
138
|
+
google-apis-compute_v1 (0.108.0)
|
|
135
139
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
136
|
-
google-apis-core (0.15.
|
|
140
|
+
google-apis-core (0.15.1)
|
|
137
141
|
addressable (~> 2.5, >= 2.5.1)
|
|
138
142
|
googleauth (~> 1.9)
|
|
139
|
-
httpclient (>= 2.8.
|
|
143
|
+
httpclient (>= 2.8.3, < 3.a)
|
|
140
144
|
mini_mime (~> 1.0)
|
|
145
|
+
mutex_m
|
|
141
146
|
representable (~> 3.0)
|
|
142
147
|
retriable (>= 2.0, < 4.a)
|
|
143
|
-
rexml
|
|
144
148
|
google-apis-dns_v1 (0.44.0)
|
|
145
149
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
146
150
|
google-apis-iamcredentials_v1 (0.21.0)
|
|
147
151
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
148
|
-
google-apis-monitoring_v3 (0.
|
|
152
|
+
google-apis-monitoring_v3 (0.69.0)
|
|
149
153
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
150
|
-
google-apis-pubsub_v1 (0.
|
|
154
|
+
google-apis-pubsub_v1 (0.56.0)
|
|
151
155
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
152
156
|
google-apis-sqladmin_v1beta4 (0.74.0)
|
|
153
157
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
154
|
-
google-apis-storage_v1 (0.
|
|
158
|
+
google-apis-storage_v1 (0.46.0)
|
|
155
159
|
google-apis-core (>= 0.15.0, < 2.a)
|
|
156
|
-
google-cloud-env (2.
|
|
160
|
+
google-cloud-env (2.2.1)
|
|
157
161
|
faraday (>= 1.0, < 3.a)
|
|
158
|
-
googleauth (1.11.
|
|
162
|
+
googleauth (1.11.1)
|
|
159
163
|
faraday (>= 1.0, < 3.a)
|
|
160
164
|
google-cloud-env (~> 2.1)
|
|
161
165
|
jwt (>= 1.4, < 3.0)
|
|
@@ -176,93 +180,95 @@ GEM
|
|
|
176
180
|
guard (~> 2.1)
|
|
177
181
|
guard-compat (~> 1.1)
|
|
178
182
|
rspec (>= 2.99.0, < 4.0)
|
|
179
|
-
hashdiff (1.1.
|
|
180
|
-
http (5.
|
|
183
|
+
hashdiff (1.1.1)
|
|
184
|
+
http (5.2.0)
|
|
181
185
|
addressable (~> 2.8)
|
|
186
|
+
base64 (~> 0.1)
|
|
182
187
|
http-cookie (~> 1.0)
|
|
183
188
|
http-form_data (~> 2.2)
|
|
184
|
-
llhttp-ffi (~> 0.
|
|
185
|
-
http-cookie (1.0.
|
|
189
|
+
llhttp-ffi (~> 0.5.0)
|
|
190
|
+
http-cookie (1.0.7)
|
|
186
191
|
domain_name (~> 0.5)
|
|
187
192
|
http-form_data (2.3.0)
|
|
188
|
-
httparty (0.
|
|
193
|
+
httparty (0.22.0)
|
|
194
|
+
csv
|
|
189
195
|
mini_mime (>= 1.0.0)
|
|
190
196
|
multi_xml (>= 0.5.2)
|
|
191
197
|
httpclient (2.8.3)
|
|
192
|
-
i18n (1.14.
|
|
198
|
+
i18n (1.14.6)
|
|
193
199
|
concurrent-ruby (~> 1.0)
|
|
194
200
|
influxdb-client (3.1.0)
|
|
195
|
-
jaro_winkler (1.
|
|
196
|
-
json (2.7.
|
|
197
|
-
jwt (2.
|
|
201
|
+
jaro_winkler (1.6.0)
|
|
202
|
+
json (2.7.2)
|
|
203
|
+
jwt (2.9.3)
|
|
198
204
|
base64
|
|
199
205
|
kramdown (2.4.0)
|
|
200
206
|
rexml
|
|
201
207
|
kramdown-parser-gfm (1.1.0)
|
|
202
208
|
kramdown (~> 2.0)
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
language_server-protocol (3.17.0.3)
|
|
210
|
+
lefthook (1.7.18)
|
|
211
|
+
listen (3.9.0)
|
|
205
212
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
206
213
|
rb-inotify (~> 0.9, >= 0.9.10)
|
|
207
|
-
llhttp-ffi (0.
|
|
214
|
+
llhttp-ffi (0.5.0)
|
|
208
215
|
ffi-compiler (~> 1.0)
|
|
209
216
|
rake (~> 13.0)
|
|
217
|
+
logger (1.6.1)
|
|
210
218
|
lumberjack (1.2.10)
|
|
211
|
-
method_source (1.
|
|
212
|
-
mime-types (3.
|
|
219
|
+
method_source (1.1.0)
|
|
220
|
+
mime-types (3.6.0)
|
|
221
|
+
logger
|
|
213
222
|
mime-types-data (~> 3.2015)
|
|
214
|
-
mime-types-data (3.2024.
|
|
223
|
+
mime-types-data (3.2024.1001)
|
|
215
224
|
mini_mime (1.1.5)
|
|
216
|
-
mini_portile2 (2.8.
|
|
217
|
-
minitest (5.
|
|
218
|
-
mize (0.
|
|
219
|
-
protocol (~> 2.0)
|
|
225
|
+
mini_portile2 (2.8.7)
|
|
226
|
+
minitest (5.25.1)
|
|
227
|
+
mize (0.6.0)
|
|
220
228
|
multi_json (1.15.0)
|
|
221
|
-
multi_xml (0.
|
|
229
|
+
multi_xml (0.7.1)
|
|
230
|
+
bigdecimal (~> 3.1)
|
|
222
231
|
mutex_m (0.2.0)
|
|
223
232
|
nap (1.1.0)
|
|
224
233
|
nenv (0.3.0)
|
|
225
234
|
net-http (0.4.1)
|
|
226
235
|
uri
|
|
227
|
-
|
|
228
|
-
nokogiri (1.16.0)
|
|
236
|
+
nokogiri (1.16.7)
|
|
229
237
|
mini_portile2 (~> 2.8.2)
|
|
230
238
|
racc (~> 1.4)
|
|
231
239
|
notiffany (0.1.3)
|
|
232
240
|
nenv (~> 0.1)
|
|
233
241
|
shellany (~> 0.0)
|
|
234
|
-
octokit (
|
|
242
|
+
octokit (9.1.0)
|
|
235
243
|
faraday (>= 1, < 3)
|
|
236
244
|
sawyer (~> 0.9)
|
|
237
245
|
open4 (1.3.4)
|
|
238
246
|
os (1.1.4)
|
|
239
|
-
parallel (1.
|
|
240
|
-
parser (3.3.0
|
|
247
|
+
parallel (1.26.3)
|
|
248
|
+
parser (3.3.5.0)
|
|
241
249
|
ast (~> 2.4.1)
|
|
242
250
|
racc
|
|
243
|
-
proc_to_ast (0.
|
|
244
|
-
coderay
|
|
251
|
+
proc_to_ast (0.2.0)
|
|
245
252
|
parser
|
|
253
|
+
rouge
|
|
246
254
|
unparser
|
|
247
|
-
protocol (2.0.0)
|
|
248
|
-
ruby_parser (~> 3.0)
|
|
249
255
|
pry (0.14.2)
|
|
250
256
|
coderay (~> 1.1)
|
|
251
257
|
method_source (~> 1.0)
|
|
252
258
|
pry-byebug (3.10.1)
|
|
253
259
|
byebug (~> 11.0)
|
|
254
260
|
pry (>= 0.13, < 0.15)
|
|
255
|
-
public_suffix (
|
|
256
|
-
racc (1.
|
|
257
|
-
rack (3.
|
|
261
|
+
public_suffix (6.0.1)
|
|
262
|
+
racc (1.8.1)
|
|
263
|
+
rack (3.1.7)
|
|
258
264
|
rainbow (3.1.1)
|
|
259
|
-
rake (13.1
|
|
265
|
+
rake (13.2.1)
|
|
260
266
|
rb-fsevent (0.11.2)
|
|
261
|
-
rb-inotify (0.
|
|
267
|
+
rb-inotify (0.11.1)
|
|
262
268
|
ffi (~> 1.0)
|
|
263
269
|
rbs (2.8.4)
|
|
264
270
|
rchardet (1.8.0)
|
|
265
|
-
regexp_parser (2.9.
|
|
271
|
+
regexp_parser (2.9.2)
|
|
266
272
|
representable (3.2.0)
|
|
267
273
|
declarative (< 0.1.0)
|
|
268
274
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
|
@@ -270,69 +276,69 @@ GEM
|
|
|
270
276
|
retriable (3.1.2)
|
|
271
277
|
reverse_markdown (2.1.1)
|
|
272
278
|
nokogiri
|
|
273
|
-
rexml (3.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
rspec-
|
|
277
|
-
rspec-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
rexml (3.3.8)
|
|
280
|
+
rouge (4.4.0)
|
|
281
|
+
rspec (3.13.0)
|
|
282
|
+
rspec-core (~> 3.13.0)
|
|
283
|
+
rspec-expectations (~> 3.13.0)
|
|
284
|
+
rspec-mocks (~> 3.13.0)
|
|
285
|
+
rspec-core (3.13.1)
|
|
286
|
+
rspec-support (~> 3.13.0)
|
|
287
|
+
rspec-expectations (3.13.3)
|
|
281
288
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
282
|
-
rspec-support (~> 3.
|
|
283
|
-
rspec-mocks (3.
|
|
289
|
+
rspec-support (~> 3.13.0)
|
|
290
|
+
rspec-mocks (3.13.2)
|
|
284
291
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
285
|
-
rspec-support (~> 3.
|
|
286
|
-
rspec-parameterized (1.0.
|
|
292
|
+
rspec-support (~> 3.13.0)
|
|
293
|
+
rspec-parameterized (1.0.2)
|
|
287
294
|
rspec-parameterized-core (< 2)
|
|
288
295
|
rspec-parameterized-table_syntax (< 2)
|
|
289
|
-
rspec-parameterized-core (1.0.
|
|
296
|
+
rspec-parameterized-core (1.0.1)
|
|
290
297
|
parser
|
|
291
|
-
proc_to_ast
|
|
298
|
+
proc_to_ast (>= 0.2.0)
|
|
292
299
|
rspec (>= 2.13, < 4)
|
|
293
300
|
unparser
|
|
294
301
|
rspec-parameterized-table_syntax (1.0.1)
|
|
295
302
|
binding_of_caller
|
|
296
303
|
rspec-parameterized-core (< 2)
|
|
297
|
-
rspec-support (3.
|
|
298
|
-
|
|
304
|
+
rspec-support (3.13.1)
|
|
305
|
+
rspec_junit_formatter (0.6.0)
|
|
306
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
|
307
|
+
rubocop (1.62.1)
|
|
299
308
|
json (~> 2.3)
|
|
309
|
+
language_server-protocol (>= 3.17.0)
|
|
300
310
|
parallel (~> 1.10)
|
|
301
|
-
parser (>= 3.
|
|
311
|
+
parser (>= 3.3.0.2)
|
|
302
312
|
rainbow (>= 2.2.2, < 4.0)
|
|
303
313
|
regexp_parser (>= 1.8, < 3.0)
|
|
304
314
|
rexml (>= 3.2.5, < 4.0)
|
|
305
|
-
rubocop-ast (>= 1.
|
|
315
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
|
306
316
|
ruby-progressbar (~> 1.7)
|
|
307
317
|
unicode-display_width (>= 2.4.0, < 3.0)
|
|
308
|
-
rubocop-ast (1.
|
|
309
|
-
parser (>= 3.
|
|
310
|
-
rubocop-capybara (2.
|
|
318
|
+
rubocop-ast (1.32.3)
|
|
319
|
+
parser (>= 3.3.1.0)
|
|
320
|
+
rubocop-capybara (2.21.0)
|
|
311
321
|
rubocop (~> 1.41)
|
|
312
322
|
rubocop-factory_bot (2.25.1)
|
|
313
323
|
rubocop (~> 1.41)
|
|
314
|
-
rubocop-graphql (
|
|
315
|
-
rubocop (>=
|
|
324
|
+
rubocop-graphql (1.5.4)
|
|
325
|
+
rubocop (>= 1.50, < 2)
|
|
316
326
|
rubocop-performance (1.20.2)
|
|
317
327
|
rubocop (>= 1.48.1, < 2.0)
|
|
318
328
|
rubocop-ast (>= 1.30.0, < 2.0)
|
|
319
|
-
rubocop-rails (2.
|
|
329
|
+
rubocop-rails (2.24.1)
|
|
320
330
|
activesupport (>= 4.2.0)
|
|
321
331
|
rack (>= 1.1)
|
|
322
332
|
rubocop (>= 1.33.0, < 2.0)
|
|
323
|
-
rubocop-ast (>= 1.
|
|
324
|
-
rubocop-rspec (2.
|
|
333
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
|
334
|
+
rubocop-rspec (2.27.1)
|
|
325
335
|
rubocop (~> 1.40)
|
|
326
336
|
rubocop-capybara (~> 2.17)
|
|
327
337
|
rubocop-factory_bot (~> 2.22)
|
|
328
338
|
ruby-progressbar (1.13.0)
|
|
329
|
-
ruby_parser (3.21.0)
|
|
330
|
-
racc (~> 1.5)
|
|
331
|
-
sexp_processor (~> 4.16)
|
|
332
339
|
sawyer (0.9.2)
|
|
333
340
|
addressable (>= 2.3.5)
|
|
334
341
|
faraday (>= 0.17.3, < 3)
|
|
335
|
-
sexp_processor (4.17.1)
|
|
336
342
|
shellany (0.0.1)
|
|
337
343
|
signet (0.19.0)
|
|
338
344
|
addressable (~> 2.8)
|
|
@@ -346,7 +352,7 @@ GEM
|
|
|
346
352
|
simplecov-cobertura (2.1.0)
|
|
347
353
|
rexml
|
|
348
354
|
simplecov (~> 0.19)
|
|
349
|
-
simplecov-html (0.
|
|
355
|
+
simplecov-html (0.13.1)
|
|
350
356
|
simplecov_json_formatter (0.1.4)
|
|
351
357
|
solargraph (0.50.0)
|
|
352
358
|
backport (~> 1.2)
|
|
@@ -368,26 +374,27 @@ GEM
|
|
|
368
374
|
table_print (1.5.7)
|
|
369
375
|
terminal-table (3.0.2)
|
|
370
376
|
unicode-display_width (>= 1.1.1, < 3)
|
|
371
|
-
thor (1.3.
|
|
372
|
-
tilt (2.
|
|
373
|
-
timecop (0.9.
|
|
374
|
-
tins (1.
|
|
377
|
+
thor (1.3.2)
|
|
378
|
+
tilt (2.4.0)
|
|
379
|
+
timecop (0.9.10)
|
|
380
|
+
tins (1.34.0)
|
|
381
|
+
bigdecimal
|
|
375
382
|
sync
|
|
376
383
|
trailblazer-option (0.1.2)
|
|
377
384
|
tzinfo (2.0.6)
|
|
378
385
|
concurrent-ruby (~> 1.0)
|
|
379
386
|
uber (0.1.0)
|
|
380
|
-
unicode-display_width (2.
|
|
381
|
-
unparser (0.6.
|
|
387
|
+
unicode-display_width (2.6.0)
|
|
388
|
+
unparser (0.6.15)
|
|
382
389
|
diff-lcs (~> 1.3)
|
|
383
|
-
parser (>= 3.
|
|
384
|
-
uri (0.13.
|
|
390
|
+
parser (>= 3.3.0)
|
|
391
|
+
uri (0.13.1)
|
|
385
392
|
webmock (3.7.0)
|
|
386
393
|
addressable (>= 2.3.6)
|
|
387
394
|
crack (>= 0.3.2)
|
|
388
395
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
389
|
-
yard (0.9.
|
|
390
|
-
zeitwerk (2.6.
|
|
396
|
+
yard (0.9.37)
|
|
397
|
+
zeitwerk (2.6.18)
|
|
391
398
|
|
|
392
399
|
PLATFORMS
|
|
393
400
|
ruby
|
|
@@ -395,13 +402,14 @@ PLATFORMS
|
|
|
395
402
|
DEPENDENCIES
|
|
396
403
|
climate_control (~> 1.2)
|
|
397
404
|
gitlab-dangerfiles (~> 3.8)
|
|
398
|
-
gitlab-styles (~>
|
|
405
|
+
gitlab-styles (~> 12.0)
|
|
399
406
|
gitlab_quality-test_tooling!
|
|
400
407
|
guard-rspec (~> 4.7)
|
|
401
408
|
lefthook (~> 1.3)
|
|
402
409
|
pry-byebug (= 3.10.1)
|
|
403
410
|
rake (~> 13.0)
|
|
404
411
|
rspec (~> 3.12)
|
|
412
|
+
rspec_junit_formatter (~> 0.6.0)
|
|
405
413
|
simplecov (~> 0.22)
|
|
406
414
|
simplecov-cobertura (~> 2.1)
|
|
407
415
|
solargraph (~> 0.41)
|
|
@@ -409,4 +417,4 @@ DEPENDENCIES
|
|
|
409
417
|
webmock (= 3.7.0)
|
|
410
418
|
|
|
411
419
|
BUNDLED WITH
|
|
412
|
-
2.5.
|
|
420
|
+
2.5.19
|
data/README.md
CHANGED
|
@@ -177,6 +177,20 @@ Usage: exe/failed-test-issues [options]
|
|
|
177
177
|
-h, --help Show the usage
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
+
### `exe/existing-test-health-issue`
|
|
181
|
+
|
|
182
|
+
```shell
|
|
183
|
+
Purpose: Checks whether tests coming from the rspec JSON report files has an existing test health issue opened.
|
|
184
|
+
Usage: exe/existing-test-health-issue [options]
|
|
185
|
+
-i, --input-files INPUT_FILES JSON rspec-retry report files
|
|
186
|
+
-p, --project PROJECT Can be an integer or a group/project string
|
|
187
|
+
-t, --token TOKEN A valid access token with `api` scope and Maintainer permission in PROJECT
|
|
188
|
+
--health-problem-type PROBLEM_TYPE
|
|
189
|
+
Look for the given health problem type (failures, pass-after-retry, slow)
|
|
190
|
+
-v, --version Show the version
|
|
191
|
+
-h, --help Show the usage
|
|
192
|
+
```
|
|
193
|
+
|
|
180
194
|
### `exe/flaky-test-issues`
|
|
181
195
|
|
|
182
196
|
```shell
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "optparse"
|
|
6
|
+
|
|
7
|
+
require_relative "../lib/gitlab_quality/test_tooling"
|
|
8
|
+
|
|
9
|
+
params = {}
|
|
10
|
+
HEALTH_PROBLEM_TYPES = GitlabQuality::TestTooling::Report::TestHealthIssueFinder::HEALTH_PROBLEM_TYPE_TO_LABEL.keys
|
|
11
|
+
|
|
12
|
+
options = OptionParser.new do |opts|
|
|
13
|
+
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
|
14
|
+
|
|
15
|
+
opts.on('-i', '--input-files INPUT_FILES', String, 'JSON rspec-retry report files') do |input_files|
|
|
16
|
+
params[:input_files] = input_files
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
opts.on('-p', '--project PROJECT', String, 'Can be an integer or a group/project string') do |project|
|
|
20
|
+
params[:project] = project
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
opts.on('-t', '--token TOKEN', String, 'A valid access token with `api` scope and Maintainer permission in PROJECT') do |token|
|
|
24
|
+
params[:token] = token
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
opts.on("--health-problem-type PROBLEM_TYPE", String, "Look for the given health problem type (#{HEALTH_PROBLEM_TYPES.join(', ')})") do |value|
|
|
28
|
+
raise ArgumentError, "Invalid health problem type: #{value}. Valid options are: #{HEALTH_PROBLEM_TYPES.join(', ')}" unless HEALTH_PROBLEM_TYPES.include?(value)
|
|
29
|
+
|
|
30
|
+
params[:health_problem_type] = value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
opts.on_tail('-v', '--version', 'Show the version') do
|
|
34
|
+
require_relative "../lib/gitlab_quality/test_tooling/version"
|
|
35
|
+
puts "#{$PROGRAM_NAME} : #{GitlabQuality::TestTooling::VERSION}"
|
|
36
|
+
exit
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
opts.on_tail('-h', '--help', 'Show the usage') do
|
|
40
|
+
puts "Purpose: Checks whether tests coming from the rspec JSON report files has an existing test health issue opened."
|
|
41
|
+
puts opts
|
|
42
|
+
exit
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
opts.parse(ARGV)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if params.any?
|
|
49
|
+
raise ArgumentError, "No health problem type given. Valid options are: #{HEALTH_PROBLEM_TYPES.join(', ')}" unless params.key?(:health_problem_type)
|
|
50
|
+
|
|
51
|
+
if GitlabQuality::TestTooling::Report::TestHealthIssueFinder.new(**params).found_existing_unhealthy_test_issue?
|
|
52
|
+
exit 0
|
|
53
|
+
else
|
|
54
|
+
exit 1
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
puts options
|
|
58
|
+
exit 1
|
|
59
|
+
end
|
|
@@ -29,6 +29,17 @@ module GitlabQuality
|
|
|
29
29
|
@max_diff_ratio = max_diff_ratio.to_f
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
def most_recent_report_date_for_issue(issue_iid:)
|
|
33
|
+
reports_discussion = existing_reports_discussion(issue_iid: issue_iid)
|
|
34
|
+
return unless reports_discussion
|
|
35
|
+
|
|
36
|
+
# We're skipping the first note of the discussion as this is the "non-collapsible note", aka
|
|
37
|
+
# the "header note", which doesn't contain any stack trace.
|
|
38
|
+
reports_discussion.notes[1..].filter_map do |reports_note|
|
|
39
|
+
most_recent_report_from_reports_note(reports_note)&.report_date
|
|
40
|
+
end.max
|
|
41
|
+
end
|
|
42
|
+
|
|
32
43
|
private
|
|
33
44
|
|
|
34
45
|
attr_reader :base_issue_labels, :max_diff_ratio
|
|
@@ -37,12 +48,57 @@ module GitlabQuality
|
|
|
37
48
|
'failed'
|
|
38
49
|
end
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
# We redefine this method, because we are reporting failed tests in a discussion instead of a comment.
|
|
52
|
+
#
|
|
53
|
+
# We do this because a test could fail for many different reasons, so we report
|
|
54
|
+
# different test failures in the same discussion, under different threads.
|
|
55
|
+
def add_report_to_issue(issue:, test:, related_issues:)
|
|
56
|
+
reports_discussion = find_or_create_reports_discussion(issue_iid: issue.iid)
|
|
57
|
+
current_reports_note = find_failure_discussion_note(issue: issue, test: test, reports_discussion: reports_discussion)
|
|
58
|
+
|
|
59
|
+
new_reports_list = new_reports_list(current_reports_note: current_reports_note, test: test)
|
|
60
|
+
note_body = new_note_body(
|
|
61
|
+
new_reports_list: new_reports_list,
|
|
62
|
+
related_issues: related_issues,
|
|
63
|
+
options: {
|
|
64
|
+
reports_discussion: reports_discussion,
|
|
65
|
+
test: test
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if current_reports_note
|
|
70
|
+
gitlab.edit_issue_note(
|
|
71
|
+
issue_iid: issue.iid,
|
|
72
|
+
note_id: current_reports_note.id,
|
|
73
|
+
note: note_body
|
|
74
|
+
)
|
|
75
|
+
else
|
|
76
|
+
gitlab.add_note_to_issue_discussion_as_thread(
|
|
77
|
+
iid: issue.iid,
|
|
78
|
+
discussion_id: reports_discussion.id,
|
|
79
|
+
note: note_body
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def find_or_create_reports_discussion(issue_iid:)
|
|
85
|
+
reports_discussion = existing_reports_discussion(issue_iid: issue_iid)
|
|
86
|
+
return reports_discussion if reports_discussion
|
|
87
|
+
|
|
88
|
+
gitlab.create_issue_discussion(iid: issue_iid, note: report_section_header)
|
|
42
89
|
end
|
|
43
90
|
|
|
44
|
-
def
|
|
45
|
-
|
|
91
|
+
def existing_reports_discussion(issue_iid:)
|
|
92
|
+
gitlab.find_issue_discussions(iid: issue_iid).find do |discussion|
|
|
93
|
+
next if discussion.individual_note
|
|
94
|
+
next unless discussion.notes.first
|
|
95
|
+
|
|
96
|
+
discussion.notes.first.body.start_with?(report_section_header)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_is_applicable?(test)
|
|
101
|
+
test.status == 'failed'
|
|
46
102
|
end
|
|
47
103
|
|
|
48
104
|
def identity_labels
|
|
@@ -57,8 +113,30 @@ module GitlabQuality
|
|
|
57
113
|
"##### Stack trace\n\n```\n#{test.full_stacktrace}\n```"
|
|
58
114
|
end
|
|
59
115
|
|
|
60
|
-
def health_problem_status_label_quick_action(reports_list)
|
|
61
|
-
|
|
116
|
+
def health_problem_status_label_quick_action(reports_list, options: {})
|
|
117
|
+
quick_actions = []
|
|
118
|
+
quick_actions << '/label ~"priority::1" ~"severity::1"' if reports_list.spiked_in_short_period?
|
|
119
|
+
|
|
120
|
+
# We can have several kinds of failures for a single test.
|
|
121
|
+
# We want to count all the failures that are reported for a test.
|
|
122
|
+
reports_notes = options[:reports_discussion].notes[1..] || []
|
|
123
|
+
all_reports_count = reports_notes.sum do |report_note|
|
|
124
|
+
new_reports_list(current_reports_note: report_note, test: options[:test]).reports_count
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
quick_actions <<
|
|
128
|
+
case all_reports_count
|
|
129
|
+
when 149..Float::INFINITY
|
|
130
|
+
'/label ~"failed-tests::1"'
|
|
131
|
+
when 137..148
|
|
132
|
+
'/label ~"failed-tests::2"'
|
|
133
|
+
when 130..136
|
|
134
|
+
'/label ~"failed-tests::3"'
|
|
135
|
+
else
|
|
136
|
+
'/label ~"failed-tests::4"'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
quick_actions.join("\n")
|
|
62
140
|
end
|
|
63
141
|
|
|
64
142
|
def up_to_date_labels(test:, issue: nil, new_labels: Set.new)
|
|
@@ -52,7 +52,7 @@ module GitlabQuality
|
|
|
52
52
|
REPORTS_DOCUMENTATION
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def health_problem_status_label_quick_action(reports_list)
|
|
55
|
+
def health_problem_status_label_quick_action(reports_list, **)
|
|
56
56
|
case reports_list.reports_count
|
|
57
57
|
when 399..Float::INFINITY
|
|
58
58
|
'/label ~"flakiness::1"'
|
|
@@ -11,7 +11,7 @@ module GitlabQuality
|
|
|
11
11
|
# - Takes a project where flaky test issues should be created
|
|
12
12
|
# - For every passed test in the report:
|
|
13
13
|
# - Find issue by test hash or create a new issue if no issue was found
|
|
14
|
-
# - Add a
|
|
14
|
+
# - Add a Failures/Flakiness/Slowness/... report in the "<Failures/Flakiness/Slowness/...> reports" note
|
|
15
15
|
class HealthProblemReporter < ReportAsIssue
|
|
16
16
|
include Concerns::GroupAndCategoryLabels
|
|
17
17
|
include Concerns::IssueReports
|
|
@@ -25,11 +25,10 @@ module GitlabQuality
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def most_recent_report_date_for_issue(issue_iid:)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
end
|
|
28
|
+
reports_note = existing_reports_note(issue_iid: issue_iid)
|
|
29
|
+
return unless reports_note
|
|
30
|
+
|
|
31
|
+
most_recent_report_from_reports_note(reports_note)&.report_date
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
private
|
|
@@ -42,10 +41,6 @@ module GitlabQuality
|
|
|
42
41
|
false
|
|
43
42
|
end
|
|
44
43
|
|
|
45
|
-
def report_in_discussion?
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
|
|
49
44
|
def identity_labels
|
|
50
45
|
[]
|
|
51
46
|
end
|
|
@@ -58,15 +53,11 @@ module GitlabQuality
|
|
|
58
53
|
''
|
|
59
54
|
end
|
|
60
55
|
|
|
61
|
-
def find_failure_discussion_note(_issue:, _test:, _reports_discussion:)
|
|
62
|
-
nil
|
|
63
|
-
end
|
|
64
|
-
|
|
65
56
|
def reports_extra_content(_test)
|
|
66
57
|
''
|
|
67
58
|
end
|
|
68
59
|
|
|
69
|
-
def health_problem_status_label_quick_action(
|
|
60
|
+
def health_problem_status_label_quick_action(*)
|
|
70
61
|
''
|
|
71
62
|
end
|
|
72
63
|
|
|
@@ -74,24 +65,6 @@ module GitlabQuality
|
|
|
74
65
|
found_label
|
|
75
66
|
end
|
|
76
67
|
|
|
77
|
-
def most_recent_report_from_discussion(issue_iid:)
|
|
78
|
-
reports_discussion = existing_reports_discussion(issue_iid: issue_iid)
|
|
79
|
-
return unless reports_discussion
|
|
80
|
-
|
|
81
|
-
# We're skipping the first note of the discussion as this is the "non-collapsible note", aka
|
|
82
|
-
# the "header note", which doesn't contain any stack trace.
|
|
83
|
-
reports_discussion.notes[1..].filter_map do |reports_note|
|
|
84
|
-
most_recent_report_from_reports_note(reports_note)&.report_date
|
|
85
|
-
end.max
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def most_recent_report_from_note(issue_iid:)
|
|
89
|
-
reports_note = existing_reports_note(issue_iid: issue_iid)
|
|
90
|
-
return unless reports_note
|
|
91
|
-
|
|
92
|
-
most_recent_report_from_reports_note(reports_note)&.report_date
|
|
93
|
-
end
|
|
94
|
-
|
|
95
68
|
def most_recent_report_from_reports_note(reports_note)
|
|
96
69
|
@most_recent_report_from_reports_note ||= report_lines(reports_note&.body.to_s).first
|
|
97
70
|
end
|
|
@@ -138,24 +111,11 @@ module GitlabQuality
|
|
|
138
111
|
end
|
|
139
112
|
end
|
|
140
113
|
|
|
141
|
-
def add_report_to_issue(issue:, test:, related_issues:)
|
|
142
|
-
current_reports_note =
|
|
143
|
-
if report_in_discussion?
|
|
144
|
-
reports_discussion = find_or_create_reports_discussion(issue_iid: issue.iid)
|
|
145
|
-
|
|
146
|
-
find_failure_discussion_note(issue: issue, test: test, reports_discussion: reports_discussion)
|
|
147
|
-
else
|
|
148
|
-
existing_reports_note(issue_iid: issue.iid)
|
|
149
|
-
end
|
|
114
|
+
def add_report_to_issue(issue:, test:, related_issues:)
|
|
115
|
+
current_reports_note = existing_reports_note(issue_iid: issue.iid)
|
|
150
116
|
|
|
151
|
-
new_reports_list =
|
|
152
|
-
|
|
153
|
-
note_body = [
|
|
154
|
-
new_reports_list.to_s,
|
|
155
|
-
health_problem_status_label_quick_action(new_reports_list),
|
|
156
|
-
identity_labels_quick_action,
|
|
157
|
-
relate_issues_quick_actions(related_issues)
|
|
158
|
-
].join("\n")
|
|
117
|
+
new_reports_list = new_reports_list(current_reports_note: current_reports_note, test: test)
|
|
118
|
+
note_body = new_note_body(new_reports_list: new_reports_list, related_issues: related_issues)
|
|
159
119
|
|
|
160
120
|
if current_reports_note
|
|
161
121
|
gitlab.edit_issue_note(
|
|
@@ -163,31 +123,31 @@ module GitlabQuality
|
|
|
163
123
|
note_id: current_reports_note.id,
|
|
164
124
|
note: note_body
|
|
165
125
|
)
|
|
166
|
-
elsif report_in_discussion?
|
|
167
|
-
gitlab.add_note_to_issue_discussion_as_thread(
|
|
168
|
-
iid: issue.iid,
|
|
169
|
-
discussion_id: reports_discussion.id,
|
|
170
|
-
note: note_body
|
|
171
|
-
)
|
|
172
126
|
else
|
|
173
127
|
gitlab.create_issue_note(iid: issue.iid, note: note_body)
|
|
174
128
|
end
|
|
175
129
|
end
|
|
176
130
|
|
|
177
|
-
def
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
131
|
+
def new_reports_list(current_reports_note:, test:)
|
|
132
|
+
increment_reports(
|
|
133
|
+
current_reports_content: current_reports_note&.body.to_s,
|
|
134
|
+
test: test,
|
|
135
|
+
reports_section_header: report_section_header,
|
|
136
|
+
item_extra_content: item_extra_content(test),
|
|
137
|
+
reports_extra_content: reports_extra_content(test)
|
|
138
|
+
)
|
|
182
139
|
end
|
|
183
140
|
|
|
184
|
-
def
|
|
185
|
-
|
|
186
|
-
next if discussion.individual_note
|
|
187
|
-
next unless discussion.notes.first
|
|
141
|
+
def new_note_body(new_reports_list:, related_issues:, options: {})
|
|
142
|
+
report = new_reports_list
|
|
188
143
|
|
|
189
|
-
|
|
190
|
-
|
|
144
|
+
quick_actions = [
|
|
145
|
+
health_problem_status_label_quick_action(new_reports_list, options: options),
|
|
146
|
+
identity_labels_quick_action,
|
|
147
|
+
relate_issues_quick_actions(related_issues)
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
quick_actions.unshift(report).join("\n")
|
|
191
151
|
end
|
|
192
152
|
|
|
193
153
|
def existing_reports_note(issue_iid:)
|
|
@@ -196,16 +156,6 @@ module GitlabQuality
|
|
|
196
156
|
end
|
|
197
157
|
end
|
|
198
158
|
|
|
199
|
-
def add_report_for_test(current_reports_content:, test:)
|
|
200
|
-
increment_reports(
|
|
201
|
-
current_reports_content: current_reports_content,
|
|
202
|
-
test: test,
|
|
203
|
-
reports_section_header: report_section_header,
|
|
204
|
-
item_extra_content: item_extra_content(test),
|
|
205
|
-
reports_extra_content: reports_extra_content(test)
|
|
206
|
-
)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
159
|
def found_label
|
|
210
160
|
if ENV.key?('CI_MERGE_REQUEST_IID')
|
|
211
161
|
FOUND_IN_MR_LABEL
|
|
@@ -42,7 +42,7 @@ module GitlabQuality
|
|
|
42
42
|
REPORTS_DOCUMENTATION
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
def health_problem_status_label_quick_action(reports_list)
|
|
45
|
+
def health_problem_status_label_quick_action(reports_list, **)
|
|
46
46
|
case reports_list.reports_count
|
|
47
47
|
when 6099..Float::INFINITY
|
|
48
48
|
'/label ~"slowness::1"'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'http'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module GitlabQuality
|
|
7
|
+
module TestTooling
|
|
8
|
+
module Report
|
|
9
|
+
class TestHealthIssueFinder < ReportAsIssue
|
|
10
|
+
HEALTH_PROBLEM_TYPE_TO_LABEL = {
|
|
11
|
+
'pass-after-retry' => 'test-health:pass-after-retry',
|
|
12
|
+
'slow' => 'test-health:slow',
|
|
13
|
+
'failures' => 'test-health:failures'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
def initialize(health_problem_type: [], **kwargs)
|
|
17
|
+
super(**kwargs)
|
|
18
|
+
|
|
19
|
+
@health_problem_type = health_problem_type
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def found_existing_unhealthy_test_issue?
|
|
23
|
+
issue_url = invoke!
|
|
24
|
+
|
|
25
|
+
!issue_url.nil? && !issue_url.empty?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run!
|
|
29
|
+
existing_issue_found = nil
|
|
30
|
+
|
|
31
|
+
applicable_tests.each do |test|
|
|
32
|
+
issues = find_issues_by_hash(test_hash(test), state: 'opened', labels: search_labels)
|
|
33
|
+
next if issues.empty?
|
|
34
|
+
|
|
35
|
+
existing_issue_found = issues.first.web_url
|
|
36
|
+
puts "Found an existing test health issue of type #{health_problem_type} for test #{test.file}:#{test.line_number}: #{existing_issue_found}."
|
|
37
|
+
break
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
puts "Did not find an existing test health issue of type #{health_problem_type}." unless existing_issue_found
|
|
41
|
+
|
|
42
|
+
existing_issue_found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def applicable_tests
|
|
46
|
+
applicable_tests = []
|
|
47
|
+
|
|
48
|
+
TestResults::Builder.new(file_glob: files, token: token, project: project).test_results_per_file do |test_results|
|
|
49
|
+
applicable_tests = test_results.select { |test| test_is_applicable?(test) }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
applicable_tests
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
attr_reader :health_problem_type
|
|
58
|
+
|
|
59
|
+
# Be mindful about the number of tests this method would return,
|
|
60
|
+
# as we will make at least one API request per test.
|
|
61
|
+
def test_is_applicable?(test)
|
|
62
|
+
expected_test_status =
|
|
63
|
+
case health_problem_type
|
|
64
|
+
when 'failures'
|
|
65
|
+
'failed'
|
|
66
|
+
else
|
|
67
|
+
'passed'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
test.status == expected_test_status
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def search_labels
|
|
74
|
+
['test', HEALTH_PROBLEM_TYPE_TO_LABEL[health_problem_type]]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
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.
|
|
4
|
+
version: 2.1.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-10-
|
|
11
|
+
date: 2024-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '12.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '12.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: guard-rspec
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -192,6 +192,20 @@ dependencies:
|
|
|
192
192
|
- - '='
|
|
193
193
|
- !ruby/object:Gem::Version
|
|
194
194
|
version: 3.7.0
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: rspec_junit_formatter
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: 0.6.0
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: 0.6.0
|
|
195
209
|
- !ruby/object:Gem::Dependency
|
|
196
210
|
name: activesupport
|
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -230,16 +244,22 @@ dependencies:
|
|
|
230
244
|
name: gitlab
|
|
231
245
|
requirement: !ruby/object:Gem::Requirement
|
|
232
246
|
requirements:
|
|
233
|
-
- - "
|
|
247
|
+
- - ">="
|
|
234
248
|
- !ruby/object:Gem::Version
|
|
235
249
|
version: '4.19'
|
|
250
|
+
- - "<"
|
|
251
|
+
- !ruby/object:Gem::Version
|
|
252
|
+
version: '6.0'
|
|
236
253
|
type: :runtime
|
|
237
254
|
prerelease: false
|
|
238
255
|
version_requirements: !ruby/object:Gem::Requirement
|
|
239
256
|
requirements:
|
|
240
|
-
- - "
|
|
257
|
+
- - ">="
|
|
241
258
|
- !ruby/object:Gem::Version
|
|
242
259
|
version: '4.19'
|
|
260
|
+
- - "<"
|
|
261
|
+
- !ruby/object:Gem::Version
|
|
262
|
+
version: '6.0'
|
|
243
263
|
- !ruby/object:Gem::Dependency
|
|
244
264
|
name: http
|
|
245
265
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -394,6 +414,7 @@ description: A collection of test-related tools.
|
|
|
394
414
|
email:
|
|
395
415
|
- quality@gitlab.com
|
|
396
416
|
executables:
|
|
417
|
+
- existing-test-health-issue
|
|
397
418
|
- failed-test-issues
|
|
398
419
|
- flaky-test-issues
|
|
399
420
|
- generate-test-session
|
|
@@ -423,6 +444,7 @@ files:
|
|
|
423
444
|
- LICENSE.txt
|
|
424
445
|
- README.md
|
|
425
446
|
- Rakefile
|
|
447
|
+
- exe/existing-test-health-issue
|
|
426
448
|
- exe/failed-test-issues
|
|
427
449
|
- exe/flaky-test-issues
|
|
428
450
|
- exe/generate-test-session
|
|
@@ -471,6 +493,7 @@ files:
|
|
|
471
493
|
- lib/gitlab_quality/test_tooling/report/results_in_issues.rb
|
|
472
494
|
- lib/gitlab_quality/test_tooling/report/results_in_test_cases.rb
|
|
473
495
|
- lib/gitlab_quality/test_tooling/report/slow_test_issue.rb
|
|
496
|
+
- lib/gitlab_quality/test_tooling/report/test_health_issue_finder.rb
|
|
474
497
|
- lib/gitlab_quality/test_tooling/report/update_screenshot_path.rb
|
|
475
498
|
- lib/gitlab_quality/test_tooling/runtime/env.rb
|
|
476
499
|
- lib/gitlab_quality/test_tooling/runtime/logger.rb
|
|
@@ -527,7 +550,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
527
550
|
requirements:
|
|
528
551
|
- - ">="
|
|
529
552
|
- !ruby/object:Gem::Version
|
|
530
|
-
version:
|
|
553
|
+
version: 3.1.0
|
|
531
554
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
532
555
|
requirements:
|
|
533
556
|
- - ">="
|