dri 0.7.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab/merge_request_templates/Release.md +28 -0
- data/.gitlab-ci.yml +3 -3
- data/.ruby-version +1 -1
- data/.tool-versions +1 -1
- data/Gemfile.lock +45 -36
- data/README.md +10 -1
- data/dri.gemspec +6 -5
- data/lib/dri/api_client.rb +88 -20
- data/lib/dri/commands/analyze/stack_traces.rb +4 -2
- data/lib/dri/commands/fetch/failures.rb +15 -12
- data/lib/dri/commands/fetch/featureflags.rb +2 -2
- data/lib/dri/commands/fetch/pipelines.rb +2 -1
- data/lib/dri/commands/fetch/quarantines.rb +3 -1
- data/lib/dri/commands/fetch/runbooks.rb +62 -0
- data/lib/dri/commands/fetch/triaged.rb +6 -4
- data/lib/dri/commands/fetch.rb +11 -0
- data/lib/dri/commands/incidents.rb +4 -2
- data/lib/dri/commands/publish/report.rb +28 -10
- data/lib/dri/commands/publish.rb +3 -0
- data/lib/dri/commands/rm/emoji.rb +1 -1
- data/lib/dri/feature_flag_report.rb +2 -2
- data/lib/dri/report.rb +16 -14
- data/lib/dri/utils/constants.rb +34 -0
- data/lib/dri/version.rb +1 -1
- metadata +28 -13
- data/lib/dri/utils/feature_flag_consts.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b398cef45fa101592e0abecf4d014969e4e26dac5b5e3fd9f7f774b6108618f
|
4
|
+
data.tar.gz: 96a6b402d7dfcccf9fe2e69e01a4ece8af13d56be0213dc8ffa3824ea9a5ed2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d94573de9142a648b643819381244382a65fedd7c180ae5b78013ea2738204e54e543e43ed5ad6209c2a3ae5a3af4cd1ecb2a7937afa5607b3c04435ce5a2a2
|
7
|
+
data.tar.gz: 48e010a476d8b1a2b48b3b74ba485e7a9c533aa17f96e4639eead23e486f2a309a8f60fed3c282a9b85ec38154cc2bb0b26fdbf28d3389981d1bf26578336b87
|
@@ -0,0 +1,28 @@
|
|
1
|
+
## Diff
|
2
|
+
<!-- Replace `v0.9.0` with the previous DRI release, and `6a9c4fcc150741d578ec75141d3706891b6694bc` with the latest commit from https://gitlab.com/gitlab-org/quality/dri/-/commits/master that will be included in the release -->
|
3
|
+
https://gitlab.com/gitlab-org/quality/dri/-/compare/v0.9.0...6a9c4fcc150741d578ec75141d3706891b6694bc
|
4
|
+
|
5
|
+
## Release Notes
|
6
|
+
|
7
|
+
```markdown
|
8
|
+
### Features
|
9
|
+
- !aaa <Title of the aaa MR>
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
- !bbb <Title of the bbb MR>
|
13
|
+
|
14
|
+
### Maintenance
|
15
|
+
- !ccc <Title of the ccc MR>
|
16
|
+
```
|
17
|
+
|
18
|
+
## Checklists
|
19
|
+
|
20
|
+
### Before merging:
|
21
|
+
- [ ] MR title is set to `Bump version to <version>`, where `<version>` is the new version, according to [SemVer](https://semver.org/).
|
22
|
+
- [ ] Diff link is up-to-date.
|
23
|
+
- [ ] Release notes are accurate.
|
24
|
+
- [ ] `lib/dri/version.rb` is updated with the new version number.
|
25
|
+
- [ ] `bundle update` was run to update `Gemfile.lock` with the new version number.
|
26
|
+
|
27
|
+
### After merging:
|
28
|
+
- [ ] Update the release notes for the [newly created tag](https://gitlab.com/gitlab-org/quality/dri/-/tags) with the release notes from this MR.
|
data/.gitlab-ci.yml
CHANGED
@@ -15,18 +15,18 @@
|
|
15
15
|
- vendor/bundle
|
16
16
|
policy: pull
|
17
17
|
rules:
|
18
|
-
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
18
|
+
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
19
19
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
20
20
|
|
21
21
|
include:
|
22
22
|
- project: gitlab-org/quality/pipeline-common
|
23
|
-
ref:
|
23
|
+
ref: 1.2.3
|
24
24
|
file:
|
25
25
|
- /ci/gem-release.yml
|
26
26
|
- /ci/ref-update.gitlab-ci.yml
|
27
27
|
|
28
28
|
variables:
|
29
|
-
RUBY_VERSION: "
|
29
|
+
RUBY_VERSION: "3.0"
|
30
30
|
|
31
31
|
stages:
|
32
32
|
- build
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0.
|
1
|
+
3.0.5
|
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 3.0.
|
1
|
+
ruby 3.0.5
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dri (0.
|
4
|
+
dri (0.9.0)
|
5
5
|
amatch (~> 0.4.1)
|
6
|
-
gitlab (~> 4.
|
7
|
-
httparty (~> 0.
|
6
|
+
gitlab (~> 4.19)
|
7
|
+
httparty (~> 0.21.0)
|
8
8
|
json (~> 2.6.1)
|
9
9
|
markdown-tables (~> 1.1.1)
|
10
10
|
pastel (~> 0.8.0)
|
11
|
-
thor (~> 1.0
|
11
|
+
thor (~> 1.2.0)
|
12
12
|
tty-box (~> 0.7.0)
|
13
|
-
tty-config (~> 0.
|
14
|
-
tty-editor (~> 0.
|
13
|
+
tty-config (~> 0.6.0)
|
14
|
+
tty-editor (~> 0.7)
|
15
15
|
tty-font (~> 0.5)
|
16
16
|
tty-logger (~> 0.6.0)
|
17
|
+
tty-markdown (~> 0.7.0)
|
17
18
|
tty-prompt (~> 0.23.1)
|
18
19
|
tty-spinner (~> 0.9)
|
19
20
|
tty-table (~> 0.12.0)
|
@@ -21,19 +22,19 @@ PATH
|
|
21
22
|
GEM
|
22
23
|
remote: https://rubygems.org/
|
23
24
|
specs:
|
24
|
-
activesupport (7.0.2
|
25
|
+
activesupport (7.0.4.2)
|
25
26
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
27
|
i18n (>= 1.6, < 2)
|
27
28
|
minitest (>= 5.1)
|
28
29
|
tzinfo (~> 2.0)
|
29
|
-
addressable (2.8.
|
30
|
-
public_suffix (>= 2.0.2, <
|
30
|
+
addressable (2.8.1)
|
31
|
+
public_suffix (>= 2.0.2, < 6.0)
|
31
32
|
amatch (0.4.1)
|
32
33
|
mize
|
33
34
|
tins (~> 1.0)
|
34
35
|
ast (2.4.2)
|
35
36
|
coderay (1.1.3)
|
36
|
-
concurrent-ruby (1.
|
37
|
+
concurrent-ruby (1.2.2)
|
37
38
|
crack (0.4.5)
|
38
39
|
rexml
|
39
40
|
diff-lcs (1.5.0)
|
@@ -48,37 +49,38 @@ GEM
|
|
48
49
|
rubocop-rails (~> 2.9)
|
49
50
|
rubocop-rspec (~> 1.44)
|
50
51
|
hashdiff (1.0.1)
|
51
|
-
httparty (0.
|
52
|
-
|
52
|
+
httparty (0.21.0)
|
53
|
+
mini_mime (>= 1.0.0)
|
53
54
|
multi_xml (>= 0.5.2)
|
54
|
-
i18n (1.
|
55
|
+
i18n (1.12.0)
|
55
56
|
concurrent-ruby (~> 1.0)
|
56
|
-
json (2.6.
|
57
|
+
json (2.6.3)
|
58
|
+
kramdown (2.4.0)
|
59
|
+
rexml
|
57
60
|
markdown-tables (1.1.1)
|
58
61
|
method_source (1.0.0)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
minitest (5.15.0)
|
63
|
-
mize (0.4.0)
|
62
|
+
mini_mime (1.1.2)
|
63
|
+
minitest (5.18.0)
|
64
|
+
mize (0.4.1)
|
64
65
|
protocol (~> 2.0)
|
65
66
|
multi_xml (0.6.0)
|
66
67
|
parallel (1.22.1)
|
67
|
-
parser (3.
|
68
|
+
parser (3.2.1.0)
|
68
69
|
ast (~> 2.4.1)
|
69
70
|
pastel (0.8.0)
|
70
71
|
tty-color (~> 0.5)
|
71
72
|
protocol (2.0.0)
|
72
73
|
ruby_parser (~> 3.0)
|
73
|
-
pry (0.14.
|
74
|
+
pry (0.14.2)
|
74
75
|
coderay (~> 1.1)
|
75
76
|
method_source (~> 1.0)
|
76
|
-
public_suffix (
|
77
|
-
rack (
|
77
|
+
public_suffix (5.0.1)
|
78
|
+
rack (3.0.4.2)
|
78
79
|
rainbow (3.1.1)
|
79
80
|
rake (13.0.6)
|
80
|
-
regexp_parser (2.
|
81
|
+
regexp_parser (2.7.0)
|
81
82
|
rexml (3.2.5)
|
83
|
+
rouge (3.30.0)
|
82
84
|
rspec (3.10.0)
|
83
85
|
rspec-core (~> 3.10.0)
|
84
86
|
rspec-expectations (~> 3.10.0)
|
@@ -101,11 +103,11 @@ GEM
|
|
101
103
|
rubocop-ast (>= 0.6.0)
|
102
104
|
ruby-progressbar (~> 1.7)
|
103
105
|
unicode-display_width (>= 1.4.0, < 2.0)
|
104
|
-
rubocop-ast (1.
|
105
|
-
parser (>= 3.
|
106
|
+
rubocop-ast (1.27.0)
|
107
|
+
parser (>= 3.2.1.0)
|
106
108
|
rubocop-gitlab-security (0.1.1)
|
107
109
|
rubocop (>= 0.51)
|
108
|
-
rubocop-graphql (0.
|
110
|
+
rubocop-graphql (0.19.0)
|
109
111
|
rubocop (>= 0.87, < 2)
|
110
112
|
rubocop-performance (1.9.2)
|
111
113
|
rubocop (>= 0.90.0, < 2.0)
|
@@ -117,8 +119,8 @@ GEM
|
|
117
119
|
rubocop-rspec (1.44.1)
|
118
120
|
rubocop (~> 0.87)
|
119
121
|
rubocop-ast (>= 0.7.1)
|
120
|
-
ruby-progressbar (1.
|
121
|
-
ruby_parser (3.
|
122
|
+
ruby-progressbar (1.13.0)
|
123
|
+
ruby_parser (3.20.0)
|
122
124
|
sexp_processor (~> 4.16)
|
123
125
|
sexp_processor (4.16.1)
|
124
126
|
strings (0.2.1)
|
@@ -129,22 +131,29 @@ GEM
|
|
129
131
|
sync (0.5.0)
|
130
132
|
terminal-table (3.0.2)
|
131
133
|
unicode-display_width (>= 1.1.1, < 3)
|
132
|
-
thor (1.
|
133
|
-
timecop (0.9.
|
134
|
-
tins (1.
|
134
|
+
thor (1.2.1)
|
135
|
+
timecop (0.9.6)
|
136
|
+
tins (1.32.1)
|
135
137
|
sync
|
136
138
|
tty-box (0.7.0)
|
137
139
|
pastel (~> 0.8)
|
138
140
|
strings (~> 0.2.0)
|
139
141
|
tty-cursor (~> 0.7)
|
140
142
|
tty-color (0.6.0)
|
141
|
-
tty-config (0.
|
143
|
+
tty-config (0.6.0)
|
142
144
|
tty-cursor (0.7.1)
|
143
145
|
tty-editor (0.7.0)
|
144
146
|
tty-prompt (~> 0.22)
|
145
147
|
tty-font (0.5.0)
|
146
148
|
tty-logger (0.6.0)
|
147
149
|
pastel (~> 0.8)
|
150
|
+
tty-markdown (0.7.1)
|
151
|
+
kramdown (>= 1.16.2, < 3.0)
|
152
|
+
pastel (~> 0.8)
|
153
|
+
rouge (~> 3.14)
|
154
|
+
strings (~> 0.2.0)
|
155
|
+
tty-color (~> 0.5)
|
156
|
+
tty-screen (~> 0.8)
|
148
157
|
tty-prompt (0.23.1)
|
149
158
|
pastel (~> 0.8)
|
150
159
|
tty-reader (~> 0.8)
|
@@ -159,11 +168,11 @@ GEM
|
|
159
168
|
pastel (~> 0.8)
|
160
169
|
strings (~> 0.2.0)
|
161
170
|
tty-screen (~> 0.8)
|
162
|
-
tzinfo (2.0.
|
171
|
+
tzinfo (2.0.6)
|
163
172
|
concurrent-ruby (~> 1.0)
|
164
173
|
unicode-display_width (1.8.0)
|
165
174
|
unicode_utils (1.4.0)
|
166
|
-
webmock (3.
|
175
|
+
webmock (3.18.1)
|
167
176
|
addressable (>= 2.8.0)
|
168
177
|
crack (>= 0.3.2)
|
169
178
|
hashdiff (>= 0.4.0, < 2.0.0)
|
@@ -182,4 +191,4 @@ DEPENDENCIES
|
|
182
191
|
webmock (~> 3.5)
|
183
192
|
|
184
193
|
BUNDLED WITH
|
185
|
-
2.
|
194
|
+
2.4.7
|
data/README.md
CHANGED
@@ -59,6 +59,7 @@ $ dri profile
|
|
59
59
|
- quarantines
|
60
60
|
- dequarantines
|
61
61
|
- featureflags
|
62
|
+
- runbooks
|
62
63
|
- [4. publish](#4-publish)
|
63
64
|
- report
|
64
65
|
- [5. rm](#5-rm)
|
@@ -139,6 +140,13 @@ $ dri fetch pipelines
|
|
139
140
|
Fetches a table containing last executed pipeline and its test report link for all monitored pipelines.
|
140
141
|
The timestamps are in UTC
|
141
142
|
|
143
|
+
```shell
|
144
|
+
$ dri fetch runbooks [runbook]
|
145
|
+
```
|
146
|
+
|
147
|
+
Fetches a runbook from the [runbooks](https://gitlab.com/gitlab-org/quality/runbooks) project.
|
148
|
+
If `[runbook]` is omitted, the command will prompt the user to select from a list of available runbooks.
|
149
|
+
|
142
150
|
#### 4. publish
|
143
151
|
|
144
152
|
```shell
|
@@ -156,12 +164,13 @@ $ dri publish report --format=table # formats the report in a table (default)
|
|
156
164
|
$ dri publish report --dry-run # the report is only generated locally
|
157
165
|
$ dri publish report --actions # activate the actions prompt for each failure
|
158
166
|
$ dri publish report --feature-flags # includes a summary of the feature flag changes on each environment
|
167
|
+
$ dri publish report --update # update the report note if has already been posted
|
159
168
|
```
|
160
169
|
|
161
170
|
**Note:** These options above can be combined like:
|
162
171
|
|
163
172
|
```shell
|
164
|
-
$ dri publish report --format=list --dry-run --actions
|
173
|
+
$ dri publish report --format=list --dry-run --actions --update
|
165
174
|
```
|
166
175
|
|
167
176
|
**Actions**
|
data/dri.gemspec
CHANGED
@@ -23,17 +23,18 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
25
|
spec.add_dependency 'amatch', '~> 0.4.1'
|
26
|
-
spec.add_dependency "gitlab", "~> 4.
|
27
|
-
spec.add_dependency 'httparty', '~> 0.
|
26
|
+
spec.add_dependency "gitlab", "~> 4.19"
|
27
|
+
spec.add_dependency 'httparty', '~> 0.21.0'
|
28
28
|
spec.add_dependency 'json', '~> 2.6.1'
|
29
29
|
spec.add_dependency 'markdown-tables', '~> 1.1.1'
|
30
30
|
spec.add_dependency 'pastel', '~> 0.8.0'
|
31
|
-
spec.add_dependency 'thor', '~> 1.0
|
31
|
+
spec.add_dependency 'thor', '~> 1.2.0'
|
32
32
|
spec.add_dependency 'tty-box', '~> 0.7.0'
|
33
|
-
spec.add_dependency 'tty-config', '~> 0.
|
34
|
-
spec.add_dependency 'tty-editor', '~> 0.
|
33
|
+
spec.add_dependency 'tty-config', '~> 0.6.0'
|
34
|
+
spec.add_dependency 'tty-editor', '~> 0.7'
|
35
35
|
spec.add_dependency 'tty-font', '~> 0.5'
|
36
36
|
spec.add_dependency 'tty-logger', '~> 0.6.0'
|
37
|
+
spec.add_dependency 'tty-markdown', '~> 0.7.0'
|
37
38
|
spec.add_dependency 'tty-prompt', '~> 0.23.1'
|
38
39
|
spec.add_dependency 'tty-spinner', '~> 0.9'
|
39
40
|
spec.add_dependency 'tty-table', '~> 0.12.0'
|
data/lib/dri/api_client.rb
CHANGED
@@ -6,16 +6,16 @@ require "tty-config"
|
|
6
6
|
require "cgi"
|
7
7
|
require "gitlab"
|
8
8
|
|
9
|
+
require_relative './utils/constants'
|
10
|
+
|
9
11
|
module Dri
|
10
12
|
TokenNotProvidedError = Class.new(StandardError)
|
11
13
|
class ApiClient # rubocop:disable Metrics/ClassLength
|
14
|
+
include Dri::Utils::Constants::ProjectIDs
|
15
|
+
include Dri::Utils::Constants::Triage::Labels
|
16
|
+
|
12
17
|
API_URL = "https://gitlab.com/api/v4"
|
13
18
|
OPS_API_URL = "https://ops.gitlab.net/api/v4"
|
14
|
-
TESTCASES_PROJECT_ID = 11229385
|
15
|
-
TRIAGE_PROJECT_ID = 15291320
|
16
|
-
GITLAB_PROJECT_ID = 278964
|
17
|
-
FEATURE_FLAG_LOG_PROJECT_ID = 15208716
|
18
|
-
INFRA_TEAM_PROD_PROJECT_ID = 7444821
|
19
19
|
|
20
20
|
def initialize(config, ops = false)
|
21
21
|
@token = config.read.dig("settings", "token")
|
@@ -28,14 +28,31 @@ module Dri
|
|
28
28
|
@ops_instance = ops
|
29
29
|
end
|
30
30
|
|
31
|
-
# Fetch triaged failures
|
31
|
+
# Fetch all triaged failures
|
32
32
|
#
|
33
33
|
# @param [String] emoji
|
34
34
|
# @param [String] state
|
35
|
-
# @return [Gitlab::ObjectifiedHash]
|
36
|
-
def
|
35
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
36
|
+
def fetch_all_triaged_failures(emoji:, state:)
|
37
|
+
project_ids = [GITLAB_PROJECT_ID, CUSTOMERSDOT_PROJECT_ID]
|
38
|
+
failures = []
|
39
|
+
|
40
|
+
project_ids.each do |project_id|
|
41
|
+
failures += fetch_triaged_failures(project_id: project_id, emoji: emoji, state: state)
|
42
|
+
end
|
43
|
+
|
44
|
+
failures
|
45
|
+
end
|
46
|
+
|
47
|
+
# Fetch triaged failures for a given project
|
48
|
+
#
|
49
|
+
# @param [Integer] project_id
|
50
|
+
# @param [String] emoji
|
51
|
+
# @param [String] state
|
52
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
53
|
+
def fetch_triaged_failures(project_id:, emoji:, state:)
|
37
54
|
gitlab.issues(
|
38
|
-
|
55
|
+
project_id,
|
39
56
|
order_by: "updated_at",
|
40
57
|
my_reaction_emoji: emoji,
|
41
58
|
scope: "all",
|
@@ -61,7 +78,7 @@ module Dri
|
|
61
78
|
# @param [Integer] issue_iid
|
62
79
|
# @param [Integer] project_id
|
63
80
|
# @return [Array<Gitlab::ObjectifiedHash>]
|
64
|
-
def fetch_awarded_emojis(issue_iid, project_id:
|
81
|
+
def fetch_awarded_emojis(issue_iid, project_id:)
|
65
82
|
gitlab.award_emojis(project_id, issue_iid, "issue")
|
66
83
|
end
|
67
84
|
|
@@ -76,14 +93,14 @@ module Dri
|
|
76
93
|
labels: "#{pipeline}::failed",
|
77
94
|
state: state,
|
78
95
|
scope: "all",
|
79
|
-
"not[labels]":
|
96
|
+
"not[labels]": QUARANTINE
|
80
97
|
).auto_paginate
|
81
98
|
end
|
82
99
|
|
83
100
|
# Fetch issues related to failing test cases
|
84
101
|
#
|
85
102
|
# @return [Array<Gitlab::ObjectifiedHash>]
|
86
|
-
def fetch_test_failure_issues(labels:
|
103
|
+
def fetch_test_failure_issues(labels: FAILURE_NEW)
|
87
104
|
gitlab.issues(
|
88
105
|
GITLAB_PROJECT_ID,
|
89
106
|
labels: labels,
|
@@ -94,10 +111,11 @@ module Dri
|
|
94
111
|
|
95
112
|
# Fetch related issue mrs
|
96
113
|
#
|
114
|
+
# @param [Integer] project_id
|
97
115
|
# @param [Integer] issue_iid
|
98
116
|
# @return [Array<Gitlab::ObjectifiedHash>]
|
99
|
-
def fetch_related_mrs(issue_iid)
|
100
|
-
gitlab.related_issue_merge_requests(
|
117
|
+
def fetch_related_mrs(project_id, issue_iid)
|
118
|
+
gitlab.related_issue_merge_requests(project_id, issue_iid)
|
101
119
|
end
|
102
120
|
|
103
121
|
# Fetch MRs
|
@@ -130,15 +148,42 @@ module Dri
|
|
130
148
|
gitlab.create_issue_note(TRIAGE_PROJECT_ID, iid, body)
|
131
149
|
end
|
132
150
|
|
133
|
-
#
|
151
|
+
# Update triage report note
|
152
|
+
#
|
153
|
+
# @param [Integer] iid
|
154
|
+
# @param [Integer] note_id
|
155
|
+
# @param [String] body
|
156
|
+
# @return [Gitlab::ObjectifiedHash]
|
157
|
+
def update_triage_report_note(iid:, note_id:, body:)
|
158
|
+
gitlab.edit_issue_note(TRIAGE_PROJECT_ID, iid, note_id, body)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Fetch all new failures
|
134
162
|
#
|
135
163
|
# @param [String] date
|
136
164
|
# @param [String] state
|
137
165
|
# @return [Array<Gitlab::ObjectifiedHash>]
|
138
|
-
def
|
166
|
+
def fetch_all_new_failures(date:, state:)
|
167
|
+
project_ids = [GITLAB_PROJECT_ID, CUSTOMERSDOT_PROJECT_ID]
|
168
|
+
failures = []
|
169
|
+
|
170
|
+
project_ids.each do |project_id|
|
171
|
+
failures += fetch_new_failures(project_id: project_id, date: date, state: state)
|
172
|
+
end
|
173
|
+
|
174
|
+
failures
|
175
|
+
end
|
176
|
+
|
177
|
+
# Fetch new failures for a given project
|
178
|
+
#
|
179
|
+
# @param [Integer] project_id
|
180
|
+
# @param [String] date
|
181
|
+
# @param [String] state
|
182
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
183
|
+
def fetch_new_failures(project_id:, date:, state:)
|
139
184
|
gitlab.issues(
|
140
|
-
|
141
|
-
labels:
|
185
|
+
project_id,
|
186
|
+
labels: FAILURE_NEW,
|
142
187
|
order_by: "updated_at",
|
143
188
|
state: state,
|
144
189
|
scope: "all",
|
@@ -149,10 +194,11 @@ module Dri
|
|
149
194
|
|
150
195
|
# Fetch failure notes
|
151
196
|
#
|
197
|
+
# @param [Integer] project_id
|
152
198
|
# @param [Integer] issue_iid
|
153
199
|
# @return [Array<Gitlab::ObjectifiedHash>]
|
154
|
-
def fetch_failure_notes(issue_iid)
|
155
|
-
gitlab.issue_notes(
|
200
|
+
def fetch_failure_notes(project_id, issue_iid)
|
201
|
+
gitlab.issue_notes(project_id, issue_iid, per_page: 100).auto_paginate
|
156
202
|
end
|
157
203
|
|
158
204
|
# Delete award emoji
|
@@ -233,6 +279,28 @@ module Dri
|
|
233
279
|
gitlab.pipeline_jobs(project_id, pipeline_id, options).auto_paginate
|
234
280
|
end
|
235
281
|
|
282
|
+
# Fetch runbooks from the runbooks project
|
283
|
+
#
|
284
|
+
# @param [Integer] project_id
|
285
|
+
# @return [Array<Gitlab::ObjectifedHash>]
|
286
|
+
def list_runbooks(project_id = RUNBOOKS_PROJECT_ID)
|
287
|
+
tree = gitlab.tree(project_id, { recursive: true, ref: 'main' }).auto_paginate
|
288
|
+
|
289
|
+
tree.select do |node|
|
290
|
+
node.type == 'tree' && !node.name.start_with?('_')
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Fetches file contents at <path>
|
295
|
+
#
|
296
|
+
# @param [String] path
|
297
|
+
# @param [String] ref
|
298
|
+
# @param [Integer] project_id
|
299
|
+
# @return [Gitlab::ObjectifiedHash]
|
300
|
+
def get_file(path, ref:, project_id:)
|
301
|
+
gitlab.get_file(project_id, path, ref)
|
302
|
+
end
|
303
|
+
|
236
304
|
private
|
237
305
|
|
238
306
|
attr_reader :token, :ops_token
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
+
require_relative '../../utils/constants'
|
5
6
|
require 'amatch'
|
6
7
|
require 'fileutils'
|
7
8
|
|
@@ -11,10 +12,11 @@ module Dri
|
|
11
12
|
class StackTraces < Dri::Command
|
12
13
|
include Amatch
|
13
14
|
include Dri::Utils::Table
|
15
|
+
include Dri::Utils::Constants::Triage::Labels
|
14
16
|
|
15
17
|
def initialize(options)
|
16
18
|
@options = options
|
17
|
-
@labels = options[:labels] ||
|
19
|
+
@labels = options[:labels] || FAILURE_NEW
|
18
20
|
@similarity_score_threshold = options[:similarity_score_threshold] || 0.9
|
19
21
|
end
|
20
22
|
|
@@ -29,7 +31,7 @@ module Dri
|
|
29
31
|
logger.info "#{Time.now.utc} API response completed"
|
30
32
|
|
31
33
|
if response.empty?
|
32
|
-
logger.info
|
34
|
+
logger.info "There are no #{FAILURE_NEW} issues identified!"
|
33
35
|
exit 0
|
34
36
|
end
|
35
37
|
|
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
+
require_relative '../../utils/constants'
|
5
6
|
|
6
7
|
module Dri
|
7
8
|
module Commands
|
8
9
|
class Fetch
|
9
10
|
class Failures < Dri::Command
|
10
11
|
include Dri::Utils::Table
|
12
|
+
include Dri::Utils::Constants::Triage::Labels
|
11
13
|
using Refinements
|
12
14
|
|
13
15
|
SORT_BY_OPTIONS = {
|
@@ -34,33 +36,34 @@ module Dri
|
|
34
36
|
author = add_color('Author', :bright_yellow)
|
35
37
|
url = add_color('URL', :bright_yellow)
|
36
38
|
|
37
|
-
|
39
|
+
sorted_failures = []
|
38
40
|
labels = [title, triaged, environment, author, url]
|
39
41
|
triaged_counter = 0
|
40
42
|
|
41
43
|
logger.info "Fetching today's failures..."
|
42
44
|
|
43
45
|
spinner.run do # rubocop:disable Metrics/BlockLength
|
44
|
-
|
46
|
+
failures = api_client.fetch_all_new_failures(date: @today_iso_format, state: 'opened')
|
45
47
|
|
46
|
-
if
|
48
|
+
if failures.empty?
|
47
49
|
logger.info 'Life is great, there are no new failures today!'
|
48
50
|
exit 0
|
49
51
|
end
|
50
52
|
|
51
|
-
|
53
|
+
failures.each do |failure|
|
54
|
+
project_id = failure.project_id
|
52
55
|
title = failure.title.truncate(60)
|
53
56
|
author = failure.to_h.dig('author', 'username')
|
54
57
|
url = failure.web_url
|
55
58
|
triaged = add_color('x', :red)
|
56
|
-
envs = failure.labels.select { |l| l.include?(
|
59
|
+
envs = failure.labels.select { |l| l.include?(FOUND) }.map do |l|
|
57
60
|
env = l.split(':').last.gsub('.gitlab.com', '')
|
58
61
|
|
59
62
|
env == 'gitlab.com' ? 'production' : env
|
60
63
|
end
|
61
64
|
urgent = urgent_environments.all? { |env| envs.include?(env) }
|
62
65
|
|
63
|
-
emoji_awards = api_client.fetch_awarded_emojis(failure.iid).find do |e|
|
66
|
+
emoji_awards = api_client.fetch_awarded_emojis(failure.iid, project_id: project_id).find do |e|
|
64
67
|
e.name == emoji && e.to_h.dig('user', 'username') == username
|
65
68
|
end
|
66
69
|
|
@@ -70,26 +73,26 @@ module Dri
|
|
70
73
|
end
|
71
74
|
|
72
75
|
if @options[:urgent]
|
73
|
-
|
76
|
+
sorted_failures << [title, triaged, envs.first, author, url] if urgent
|
74
77
|
else
|
75
|
-
|
78
|
+
sorted_failures << [title, triaged, envs.first, author, url]
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
79
|
-
|
82
|
+
sorted_failures.sort_by! { |failure| failure[SORT_BY_OPTIONS[@options[:sort_by]&.to_sym || :environment]] }
|
80
83
|
end
|
81
84
|
|
82
85
|
msg = if @options[:urgent]
|
83
86
|
<<~MSG
|
84
|
-
Found: #{
|
87
|
+
Found: #{sorted_failures.size} urgent failures, occurring in both canary.gitlab.com and canary.staging.gitlab.com.
|
85
88
|
MSG
|
86
89
|
else
|
87
90
|
<<~MSG
|
88
|
-
Found: #{
|
91
|
+
Found: #{sorted_failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
|
89
92
|
MSG
|
90
93
|
end
|
91
94
|
|
92
|
-
print_table(labels,
|
95
|
+
print_table(labels, sorted_failures, alignments: [:left, :center, :center, :left])
|
93
96
|
output.puts(msg)
|
94
97
|
end
|
95
98
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
-
require_relative '../../utils/
|
5
|
+
require_relative '../../utils/constants'
|
6
6
|
require_relative '../../feature_flag_report'
|
7
7
|
|
8
8
|
module Dri
|
@@ -10,7 +10,7 @@ module Dri
|
|
10
10
|
class Fetch
|
11
11
|
class FeatureFlags < Dri::Command
|
12
12
|
include Dri::Utils::Table
|
13
|
-
include Dri::Utils::
|
13
|
+
include Dri::Utils::Constants::FeatureFlag
|
14
14
|
|
15
15
|
def initialize(options)
|
16
16
|
@options = options
|
@@ -10,6 +10,7 @@ module Dri
|
|
10
10
|
class Fetch
|
11
11
|
class Pipelines < Dri::Command # rubocop:disable Metrics/ClassLength
|
12
12
|
include Dri::Utils::Table
|
13
|
+
include Dri::Utils::Constants
|
13
14
|
using Refinements
|
14
15
|
|
15
16
|
NUM_OF_TESTS_LIVE_ENV = 1000
|
@@ -27,7 +28,7 @@ module Dri
|
|
27
28
|
table_labels = define_table_labels
|
28
29
|
|
29
30
|
spinner.run do
|
30
|
-
|
31
|
+
PIPELINE_ENVIRONMENTS.each do |environment, details|
|
31
32
|
logger.info "Fetching last executed #{environment} pipeline"
|
32
33
|
pipelines << fetch_pipeline(pipeline_name: environment.to_s, details: details)
|
33
34
|
logger.info "Fetching complete for #{environment} ✓"
|
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
+
require_relative '../../utils/constants'
|
5
6
|
|
6
7
|
module Dri
|
7
8
|
module Commands
|
8
9
|
class Fetch
|
9
10
|
class Quarantines < Dri::Command
|
10
11
|
include Dri::Utils::Table
|
12
|
+
include Dri::Utils::Constants::Triage::Labels
|
11
13
|
using Refinements
|
12
14
|
|
13
15
|
def initialize(options, search: '[QUARANTINE]')
|
@@ -30,7 +32,7 @@ module Dri
|
|
30
32
|
spinner.run do
|
31
33
|
response = api_client.fetch_mrs(
|
32
34
|
project_id: 'gitlab-org/gitlab',
|
33
|
-
labels:
|
35
|
+
labels: "#{QA},#{QUALITY}",
|
34
36
|
search: @search,
|
35
37
|
in: :title,
|
36
38
|
state: :opened
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../utils/constants'
|
5
|
+
require 'tty-markdown'
|
6
|
+
require 'tty-prompt'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
module Dri
|
10
|
+
module Commands
|
11
|
+
class Fetch
|
12
|
+
class Runbooks < Dri::Command
|
13
|
+
def initialize(options)
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(folder: nil, input: $stdin, output: $stdout)
|
18
|
+
return fetch_summary(output: output) unless folder
|
19
|
+
|
20
|
+
fetch_runbook("#{folder}/index.md", output: output)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch_summary(output:)
|
24
|
+
logger.info 'Fetching runbooks'
|
25
|
+
prompt = TTY::Prompt.new
|
26
|
+
runbooks = api_client.list_runbooks
|
27
|
+
|
28
|
+
return output.puts 'No runbooks could be found' if runbooks.empty?
|
29
|
+
|
30
|
+
choices = runbooks.map(&:path)
|
31
|
+
path = prompt.select('Which runbook would you like to look at?', choices)
|
32
|
+
|
33
|
+
fetch_runbook("#{path}/index.md", output: output)
|
34
|
+
end
|
35
|
+
|
36
|
+
def fetch_runbook(path, output:)
|
37
|
+
runbook = nil
|
38
|
+
spinner.run do
|
39
|
+
runbook = api_client.get_file(
|
40
|
+
path,
|
41
|
+
ref: 'main',
|
42
|
+
project_id: Utils::Constants::ProjectIDs::RUNBOOKS_PROJECT_ID
|
43
|
+
)
|
44
|
+
rescue Gitlab::Error::NotFound
|
45
|
+
logger.error "The runbook #{path} could not be found."
|
46
|
+
end
|
47
|
+
|
48
|
+
return unless runbook
|
49
|
+
|
50
|
+
content = Base64.decode64(runbook.content)
|
51
|
+
markdown(content, output)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def markdown(str, io)
|
57
|
+
io.puts TTY::Markdown.parse(str, symbols: :ascii)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
+
require_relative '../../utils/constants'
|
5
6
|
|
6
7
|
module Dri
|
7
8
|
module Commands
|
8
9
|
class Fetch
|
9
10
|
class Triaged < Dri::Command
|
10
11
|
include Dri::Utils::Table
|
12
|
+
include Dri::Utils::Constants::Triage::Labels
|
11
13
|
using Refinements
|
12
14
|
|
13
15
|
def initialize(options)
|
@@ -27,21 +29,21 @@ module Dri
|
|
27
29
|
logger.info "Fetching your triaged failures..."
|
28
30
|
spinner.start
|
29
31
|
|
30
|
-
|
32
|
+
failures = api_client.fetch_all_triaged_failures(emoji: emoji, state: 'opened')
|
31
33
|
|
32
|
-
if
|
34
|
+
if failures.empty?
|
33
35
|
logger.info "There are no failures triaged yet with #{add_color(emoji, :black, :on_white)}."
|
34
36
|
exit 0
|
35
37
|
end
|
36
38
|
|
37
|
-
|
39
|
+
failures.each do |triaged|
|
38
40
|
title = triaged["title"].truncate(70)
|
39
41
|
url = triaged["web_url"]
|
40
42
|
labels = triaged["labels"]
|
41
43
|
type = ""
|
42
44
|
|
43
45
|
labels.each do |label|
|
44
|
-
type = label.gsub!(
|
46
|
+
type = label.gsub!(FAILURE, ' ').to_s if label.include? FAILURE
|
45
47
|
end
|
46
48
|
|
47
49
|
failures_triaged << [title, url, type]
|
data/lib/dri/commands/fetch.rb
CHANGED
@@ -94,6 +94,17 @@ module Dri
|
|
94
94
|
require_relative 'fetch/pipelines'
|
95
95
|
Dri::Commands::Fetch::Pipelines.new(options).execute
|
96
96
|
end
|
97
|
+
|
98
|
+
desc 'runbooks', 'Fetch runbooks'
|
99
|
+
method_option :help, aliases: '-h', type: :boolean,
|
100
|
+
desc: 'Display usage information'
|
101
|
+
|
102
|
+
def runbooks(*args)
|
103
|
+
return invoke :help, %w[runbooks] if options[:help]
|
104
|
+
|
105
|
+
require_relative 'fetch/runbooks'
|
106
|
+
Dri::Commands::Fetch::Runbooks.new(options).execute(folder: args.first)
|
107
|
+
end
|
97
108
|
end
|
98
109
|
end
|
99
110
|
end
|
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
require_relative '../command'
|
4
4
|
require_relative '../utils/table'
|
5
|
+
require_relative '../utils/constants'
|
5
6
|
|
6
7
|
module Dri
|
7
8
|
module Commands
|
8
9
|
class Incidents < Dri::Command
|
9
10
|
include Dri::Utils::Table
|
11
|
+
include Dri::Utils::Constants::Triage::Labels
|
10
12
|
using Refinements
|
11
13
|
|
12
14
|
def initialize(options)
|
@@ -42,8 +44,8 @@ module Dri
|
|
42
44
|
service = "N/A"
|
43
45
|
|
44
46
|
labels.each do |label|
|
45
|
-
status = label.gsub!(
|
46
|
-
service = label.gsub!(
|
47
|
+
status = label.gsub!(INCIDENT, ' ').to_s if label.include? INCIDENT
|
48
|
+
service = label.gsub!(SERVICE, ' ').to_s if label.include? SERVICE
|
47
49
|
end
|
48
50
|
|
49
51
|
incidents << [title, service, status, url]
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/markdown_lists'
|
5
|
-
require_relative '../../utils/
|
5
|
+
require_relative '../../utils/constants'
|
6
6
|
require_relative '../../report'
|
7
7
|
require_relative '../../feature_flag_report'
|
8
8
|
|
@@ -14,7 +14,7 @@ module Dri
|
|
14
14
|
module Commands
|
15
15
|
class Publish
|
16
16
|
class Report < Dri::Command # rubocop:disable Metrics/ClassLength
|
17
|
-
include Dri::Utils::
|
17
|
+
include Dri::Utils::Constants::FeatureFlag
|
18
18
|
|
19
19
|
def initialize(options)
|
20
20
|
@options = options
|
@@ -32,13 +32,13 @@ module Dri
|
|
32
32
|
|
33
33
|
spinner.start
|
34
34
|
|
35
|
-
|
35
|
+
failures = api_client.fetch_all_triaged_failures(emoji: emoji, state: 'opened')
|
36
36
|
incidents = api_client.fetch_triaged_incidents(emoji: emoji)
|
37
37
|
|
38
38
|
spinner.stop
|
39
39
|
|
40
|
-
if
|
41
|
-
logger.warn "Found no
|
40
|
+
if failures.empty? && incidents.empty?
|
41
|
+
logger.warn "Found no failures nor incidents associated with \"#{emoji}\" emoji. Will exit. Bye 👋"
|
42
42
|
exit 1
|
43
43
|
end
|
44
44
|
|
@@ -58,18 +58,18 @@ module Dri
|
|
58
58
|
|
59
59
|
spinner.start
|
60
60
|
|
61
|
-
|
61
|
+
failures.each do |failure|
|
62
62
|
actions = []
|
63
63
|
|
64
64
|
if @options[:actions]
|
65
65
|
actions = prompt.multi_select(
|
66
|
-
"Please mark the actions on #{add_color(
|
66
|
+
"Please mark the actions on #{add_color(failure.title, :yellow)}: ",
|
67
67
|
action_options,
|
68
68
|
per_page: 9
|
69
69
|
)
|
70
70
|
end
|
71
71
|
|
72
|
-
report.add_failure(
|
72
|
+
report.add_failure(failure, actions)
|
73
73
|
end
|
74
74
|
|
75
75
|
unless incidents.empty?
|
@@ -180,11 +180,29 @@ module Dri
|
|
180
180
|
issues = api_client.fetch_current_triage_issue
|
181
181
|
current_issue_iid = issues.first.iid
|
182
182
|
|
183
|
-
|
183
|
+
note_action = 'posted'
|
184
|
+
posted_note = nil
|
185
|
+
if @options[:update]
|
186
|
+
report_file = File.read("handover_reports/.tmp/report-#{@date}.json")
|
187
|
+
report_json = JSON.parse(report_file) if report_file
|
188
|
+
posted_note = api_client.update_triage_report_note(
|
189
|
+
iid: current_issue_iid, note_id: report_json['id'], body: note
|
190
|
+
)
|
191
|
+
note_action = 'updated'
|
192
|
+
else
|
193
|
+
posted_note = api_client.post_triage_report_note(iid: current_issue_iid, body: note)
|
194
|
+
|
195
|
+
FileUtils.mkdir_p("#{Dir.pwd}/handover_reports/.tmp")
|
196
|
+
report_path = "handover_reports/.tmp/report-#{@date}.json"
|
197
|
+
|
198
|
+
File.open(report_path, 'w') do |out_file|
|
199
|
+
out_file.write(posted_note.to_h.to_json)
|
200
|
+
end
|
201
|
+
end
|
184
202
|
|
185
203
|
output.puts "Done! ✅\n"
|
186
204
|
logger.success(<<~MSG)
|
187
|
-
Thanks @#{username}, your report was
|
205
|
+
Thanks @#{username}, your report was #{note_action} at https://gitlab.com/gitlab-org/quality/pipeline-triage/-/issues/#{current_issue_iid}#note_#{posted_note.id} 🎉
|
188
206
|
MSG
|
189
207
|
end
|
190
208
|
|
data/lib/dri/commands/publish.rb
CHANGED
@@ -16,6 +16,9 @@ module Dri
|
|
16
16
|
desc: 'Updates actions on failures'
|
17
17
|
method_option :feature_flags, type: :boolean,
|
18
18
|
desc: 'Adds summary of feature flag changes'
|
19
|
+
method_option :update, aliases: '-u', type: :boolean,
|
20
|
+
desc: 'Updates an existing report'
|
21
|
+
|
19
22
|
def report(*)
|
20
23
|
if options[:help]
|
21
24
|
invoke :help, ['report']
|
@@ -24,7 +24,7 @@ module Dri
|
|
24
24
|
|
25
25
|
spinner.start
|
26
26
|
|
27
|
-
failures_with_award_emoji = api_client.
|
27
|
+
failures_with_award_emoji = api_client.fetch_all_triaged_failures(emoji: emoji, state: 'opened')
|
28
28
|
incidents_with_award_emoji = api_client.fetch_triaged_incidents(emoji: emoji)
|
29
29
|
|
30
30
|
issues_with_award_emoji = failures_with_award_emoji + incidents_with_award_emoji
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './utils/
|
3
|
+
require_relative './utils/constants'
|
4
4
|
|
5
5
|
module Dri
|
6
6
|
class FeatureFlagReport
|
7
|
-
include Dri::Utils::
|
7
|
+
include Dri::Utils::Constants::FeatureFlag::Labels
|
8
8
|
|
9
9
|
attr_reader :header, :labels, :prod, :staging, :staging_ref, :preprod
|
10
10
|
|
data/lib/dri/report.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative './utils/constants'
|
4
|
+
|
3
5
|
module Dri
|
4
6
|
class Report # rubocop:disable Metrics/ClassLength
|
7
|
+
include Dri::Utils::Constants::Triage::Labels
|
5
8
|
using Refinements
|
6
9
|
|
7
10
|
attr_reader :header, :failures, :labels, :labels_incidents, :incidents
|
@@ -31,24 +34,23 @@ module Dri
|
|
31
34
|
service = 'N/A'
|
32
35
|
|
33
36
|
labels.each do |label|
|
34
|
-
status = label.gsub!(
|
35
|
-
service = label.gsub!(
|
37
|
+
status = label.gsub!(INCIDENT, ' ').to_s if label.include? INCIDENT
|
38
|
+
service = label.gsub!(SERVICE, ' ').to_s if label.include? SERVICE
|
36
39
|
end
|
37
40
|
|
38
41
|
@incidents << [title, service, status, url]
|
39
42
|
end
|
40
43
|
|
41
44
|
def add_failure(failure, actions_opts = [])
|
45
|
+
project_id = failure["project_id"]
|
42
46
|
iid = failure["iid"]
|
43
47
|
title = format_title(failure["title"])
|
44
48
|
link = failure["web_url"]
|
45
49
|
labels = failure["labels"]
|
46
|
-
created_at = failure["created_at"]
|
47
|
-
assignees = failure["assignees"]
|
48
50
|
description = failure["description"]
|
49
51
|
|
50
|
-
related_mrs = @api_client.fetch_related_mrs(iid)
|
51
|
-
emoji = classify_failure_emoji(created_at)
|
52
|
+
related_mrs = @api_client.fetch_related_mrs(project_id, iid)
|
53
|
+
emoji = classify_failure_emoji(failure["created_at"])
|
52
54
|
emojified_link = "#{emoji} #{link}"
|
53
55
|
|
54
56
|
stack_blob = if description.empty?
|
@@ -60,10 +62,10 @@ module Dri
|
|
60
62
|
stack_trace = ":link:[`#{stack_blob}...`](#{link}#stack-trace)"
|
61
63
|
|
62
64
|
failure_type = filter_failure_type_labels(labels)
|
63
|
-
assigned_status = assigned?(assignees)
|
65
|
+
assigned_status = assigned?(failure["assignees"])
|
64
66
|
pipelines = filter_pipeline_labels(labels)
|
65
67
|
|
66
|
-
linked_pipelines = link_pipelines(iid, pipelines, description)
|
68
|
+
linked_pipelines = link_pipelines(project_id, iid, pipelines, description)
|
67
69
|
|
68
70
|
actions_status = actions_status_template(failure_type, assigned_status, actions_opts)
|
69
71
|
actions_fixes = actions_fixes_template(related_mrs)
|
@@ -73,7 +75,7 @@ module Dri
|
|
73
75
|
|
74
76
|
private
|
75
77
|
|
76
|
-
def link_pipelines(iid, pipelines, description) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
78
|
+
def link_pipelines(project_id, iid, pipelines, description) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
77
79
|
linked = []
|
78
80
|
label_pipeline_map = {
|
79
81
|
'gitlab.com' => '/quality/production',
|
@@ -88,7 +90,7 @@ module Dri
|
|
88
90
|
'release' => '/quality/release'
|
89
91
|
}
|
90
92
|
|
91
|
-
failure_notes = @api_client.fetch_failure_notes(iid)
|
93
|
+
failure_notes = @api_client.fetch_failure_notes(project_id, iid)
|
92
94
|
|
93
95
|
return if pipelines.empty?
|
94
96
|
|
@@ -173,10 +175,10 @@ module Dri
|
|
173
175
|
pipelines = []
|
174
176
|
|
175
177
|
labels.each do |label|
|
176
|
-
matchers = {
|
178
|
+
matchers = { FOUND => ' ' }
|
177
179
|
|
178
|
-
if label.include?
|
179
|
-
pipeline = label.gsub(/
|
180
|
+
if label.include? FOUND
|
181
|
+
pipeline = label.gsub(/#{FOUND}/o) { |match| matchers[match] }
|
180
182
|
pipelines << pipeline.strip
|
181
183
|
end
|
182
184
|
end
|
@@ -185,7 +187,7 @@ module Dri
|
|
185
187
|
|
186
188
|
def filter_failure_type_labels(labels)
|
187
189
|
labels.each do |label|
|
188
|
-
@type = label.gsub!(
|
190
|
+
@type = label.gsub!(FAILURE, ' ').to_s if label.include? FAILURE
|
189
191
|
end
|
190
192
|
@type
|
191
193
|
end
|
data/lib/dri/utils/constants.rb
CHANGED
@@ -3,6 +3,40 @@
|
|
3
3
|
module Dri
|
4
4
|
module Utils
|
5
5
|
module Constants
|
6
|
+
module ProjectIDs
|
7
|
+
TESTCASES_PROJECT_ID = 11229385
|
8
|
+
TRIAGE_PROJECT_ID = 15291320
|
9
|
+
GITLAB_PROJECT_ID = 278964
|
10
|
+
CUSTOMERSDOT_PROJECT_ID = 2670515
|
11
|
+
FEATURE_FLAG_LOG_PROJECT_ID = 15208716
|
12
|
+
INFRA_TEAM_PROD_PROJECT_ID = 7444821
|
13
|
+
RUNBOOKS_PROJECT_ID = 41045213
|
14
|
+
end
|
15
|
+
|
16
|
+
module Triage
|
17
|
+
module Labels
|
18
|
+
FOUND = 'found:'
|
19
|
+
FAILURE = 'failure::'
|
20
|
+
FAILURE_NEW = "#{FAILURE}new"
|
21
|
+
INCIDENT = 'Incident::'
|
22
|
+
SERVICE = 'Service::'
|
23
|
+
QA = 'QA'
|
24
|
+
QUALITY = 'Quality'
|
25
|
+
QUARANTINE = 'quarantine'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module FeatureFlag
|
30
|
+
module Labels
|
31
|
+
PRODUCTION = 'host::gitlab.com'
|
32
|
+
STAGING = 'host::staging.gitlab.com'
|
33
|
+
STAGING_REF = 'host::staging-ref.gitlab.com'
|
34
|
+
PREPROD = 'host::pre.gitlab.com'
|
35
|
+
end
|
36
|
+
|
37
|
+
TITLE_SUBSTRINGS = ["set to \"true\"", "set to \"false\""].freeze
|
38
|
+
end
|
39
|
+
|
6
40
|
PIPELINE_ENVIRONMENTS =
|
7
41
|
{
|
8
42
|
production: {
|
data/lib/dri/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.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:
|
11
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: amatch
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '4.
|
33
|
+
version: '4.19'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '4.
|
40
|
+
version: '4.19'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: httparty
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.21.0
|
48
48
|
type: :runtime
|
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: 0.
|
54
|
+
version: 0.21.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.0
|
103
|
+
version: 1.2.0
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.0
|
110
|
+
version: 1.2.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: tty-box
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,28 +128,28 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 0.6.0
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
138
|
+
version: 0.6.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: tty-editor
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '0.
|
145
|
+
version: '0.7'
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '0.
|
152
|
+
version: '0.7'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: tty-font
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: 0.6.0
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: tty-markdown
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 0.7.0
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 0.7.0
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: tty-prompt
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -315,6 +329,7 @@ files:
|
|
315
329
|
- ".editorconfig"
|
316
330
|
- ".gitignore"
|
317
331
|
- ".gitlab-ci.yml"
|
332
|
+
- ".gitlab/merge_request_templates/Release.md"
|
318
333
|
- ".rspec"
|
319
334
|
- ".rubocop.yml"
|
320
335
|
- ".ruby-version"
|
@@ -339,6 +354,7 @@ files:
|
|
339
354
|
- lib/dri/commands/fetch/featureflags.rb
|
340
355
|
- lib/dri/commands/fetch/pipelines.rb
|
341
356
|
- lib/dri/commands/fetch/quarantines.rb
|
357
|
+
- lib/dri/commands/fetch/runbooks.rb
|
342
358
|
- lib/dri/commands/fetch/testcases.rb
|
343
359
|
- lib/dri/commands/fetch/triaged.rb
|
344
360
|
- lib/dri/commands/incidents.rb
|
@@ -355,7 +371,6 @@ files:
|
|
355
371
|
- lib/dri/refinements/truncate.rb
|
356
372
|
- lib/dri/report.rb
|
357
373
|
- lib/dri/utils/constants.rb
|
358
|
-
- lib/dri/utils/feature_flag_consts.rb
|
359
374
|
- lib/dri/utils/markdown_lists.rb
|
360
375
|
- lib/dri/utils/table.rb
|
361
376
|
- lib/dri/version.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dri
|
4
|
-
module Utils
|
5
|
-
module FeatureFlagConsts
|
6
|
-
PRODUCTION = 'host::gitlab.com'
|
7
|
-
STAGING = 'host::staging.gitlab.com'
|
8
|
-
STAGING_REF = 'host::staging-ref.gitlab.com'
|
9
|
-
PREPROD = 'host::pre.gitlab.com'
|
10
|
-
TITLE_SUBSTRINGS = ["set to \"true\"", "set to \"false\""].freeze
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|