dri 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b4a86b6e658b2426bfce682d92f34f1441a9a1812f0cc805088b8c250991d4d
4
- data.tar.gz: 3cf2b62c9aa5b1ef8de5cd51f8fdd927fa5335c9a1299b4947ab162b8afe2526
3
+ metadata.gz: b5791162eb6afd6c20228dc94f5c247233a1f9703743fb671df15f0cef3258c2
4
+ data.tar.gz: 2629b72f72f18669b362b7f904bce44a4abc63b8fa421a4dbb515c1dd17ee8cb
5
5
  SHA512:
6
- metadata.gz: 4d79cdc2db7e1f959fee5b80988516677455a1d18e151a300923b2d19a58f0bb4fc4342db5e3785c34b5ef4475655b37cb10ad8850e488429ab12cfd8ad03fb8
7
- data.tar.gz: 5120e934a2e8a45a51b4328bf5a1ae3af1a55b19e42023e538f65c958bfad0a8810f89844b7f2ef40608d0c7233d64f652ba9f101cff37f203a900d940084771
6
+ metadata.gz: 6ffc4003b8ea2cc342c88a3f457f3ea9701f9dfe0e7ca0ff7a5f54e2ec1a8ccc896dea9e16bb4ea1655d3e9d1eadadaa0ef2d01652ffb4740fb94fcc01690397
7
+ data.tar.gz: f302fd36aa8cc2385e6c83e6de915481b3515097be2d5e7137ea63af3ef70e7462ad2a4f64a575777cd734b1320699b01c4efd99fd60941d59b0b8b65a4b005a
@@ -0,0 +1,28 @@
1
+ ## Diff
2
+ <!-- Replace `v0.9.0` with the previous DRI release, and `55ddcace1c166fa2323d4e556262eba6b274230a` 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...55ddcace1c166fa2323d4e556262eba6b274230a
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
@@ -26,7 +26,7 @@ include:
26
26
  - /ci/ref-update.gitlab-ci.yml
27
27
 
28
28
  variables:
29
- RUBY_VERSION: "2.7"
29
+ RUBY_VERSION: "3.0"
30
30
 
31
31
  stages:
32
32
  - build
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.4
1
+ 3.0.5
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.0.4
1
+ ruby 3.0.5
data/Gemfile.lock CHANGED
@@ -1,19 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dri (0.8.0)
4
+ dri (0.10.0)
5
5
  amatch (~> 0.4.1)
6
- gitlab (~> 4.18)
7
- httparty (~> 0.20.0)
6
+ gitlab (~> 4.19)
7
+ httparty (~> 0.21.0)
8
8
  json (~> 2.6.1)
9
+ launchy (~> 2.4)
9
10
  markdown-tables (~> 1.1.1)
10
11
  pastel (~> 0.8.0)
11
- thor (~> 1.0.1)
12
+ thor (~> 1.2.0)
12
13
  tty-box (~> 0.7.0)
13
- tty-config (~> 0.4.0)
14
- tty-editor (~> 0.6)
14
+ tty-config (~> 0.6.0)
15
+ tty-editor (~> 0.7)
15
16
  tty-font (~> 0.5)
16
17
  tty-logger (~> 0.6.0)
18
+ tty-markdown (~> 0.7.0)
17
19
  tty-prompt (~> 0.23.1)
18
20
  tty-spinner (~> 0.9)
19
21
  tty-table (~> 0.12.0)
@@ -21,19 +23,19 @@ PATH
21
23
  GEM
22
24
  remote: https://rubygems.org/
23
25
  specs:
24
- activesupport (7.0.2.3)
26
+ activesupport (7.0.5)
25
27
  concurrent-ruby (~> 1.0, >= 1.0.2)
26
28
  i18n (>= 1.6, < 2)
27
29
  minitest (>= 5.1)
28
30
  tzinfo (~> 2.0)
29
- addressable (2.8.0)
30
- public_suffix (>= 2.0.2, < 5.0)
31
+ addressable (2.8.4)
32
+ public_suffix (>= 2.0.2, < 6.0)
31
33
  amatch (0.4.1)
32
34
  mize
33
35
  tins (~> 1.0)
34
36
  ast (2.4.2)
35
37
  coderay (1.1.3)
36
- concurrent-ruby (1.1.10)
38
+ concurrent-ruby (1.2.2)
37
39
  crack (0.4.5)
38
40
  rexml
39
41
  diff-lcs (1.5.0)
@@ -48,37 +50,40 @@ GEM
48
50
  rubocop-rails (~> 2.9)
49
51
  rubocop-rspec (~> 1.44)
50
52
  hashdiff (1.0.1)
51
- httparty (0.20.0)
52
- mime-types (~> 3.0)
53
+ httparty (0.21.0)
54
+ mini_mime (>= 1.0.0)
53
55
  multi_xml (>= 0.5.2)
54
- i18n (1.10.0)
56
+ i18n (1.13.0)
55
57
  concurrent-ruby (~> 1.0)
56
- json (2.6.2)
58
+ json (2.6.3)
59
+ kramdown (2.4.0)
60
+ rexml
61
+ launchy (2.5.2)
62
+ addressable (~> 2.8)
57
63
  markdown-tables (1.1.1)
58
64
  method_source (1.0.0)
59
- mime-types (3.4.1)
60
- mime-types-data (~> 3.2015)
61
- mime-types-data (3.2022.0105)
62
- minitest (5.15.0)
63
- mize (0.4.0)
65
+ mini_mime (1.1.2)
66
+ minitest (5.18.0)
67
+ mize (0.4.1)
64
68
  protocol (~> 2.0)
65
69
  multi_xml (0.6.0)
66
- parallel (1.22.1)
67
- parser (3.1.1.0)
70
+ parallel (1.23.0)
71
+ parser (3.2.2.1)
68
72
  ast (~> 2.4.1)
69
73
  pastel (0.8.0)
70
74
  tty-color (~> 0.5)
71
75
  protocol (2.0.0)
72
76
  ruby_parser (~> 3.0)
73
- pry (0.14.1)
77
+ pry (0.14.2)
74
78
  coderay (~> 1.1)
75
79
  method_source (~> 1.0)
76
- public_suffix (4.0.6)
77
- rack (2.2.3)
80
+ public_suffix (5.0.1)
81
+ rack (3.0.7)
78
82
  rainbow (3.1.1)
79
83
  rake (13.0.6)
80
- regexp_parser (2.2.1)
84
+ regexp_parser (2.8.0)
81
85
  rexml (3.2.5)
86
+ rouge (4.1.1)
82
87
  rspec (3.10.0)
83
88
  rspec-core (~> 3.10.0)
84
89
  rspec-expectations (~> 3.10.0)
@@ -101,11 +106,11 @@ GEM
101
106
  rubocop-ast (>= 0.6.0)
102
107
  ruby-progressbar (~> 1.7)
103
108
  unicode-display_width (>= 1.4.0, < 2.0)
104
- rubocop-ast (1.16.0)
105
- parser (>= 3.1.1.0)
109
+ rubocop-ast (1.28.1)
110
+ parser (>= 3.2.1.0)
106
111
  rubocop-gitlab-security (0.1.1)
107
112
  rubocop (>= 0.51)
108
- rubocop-graphql (0.14.2)
113
+ rubocop-graphql (0.19.0)
109
114
  rubocop (>= 0.87, < 2)
110
115
  rubocop-performance (1.9.2)
111
116
  rubocop (>= 0.90.0, < 2.0)
@@ -117,10 +122,10 @@ GEM
117
122
  rubocop-rspec (1.44.1)
118
123
  rubocop (~> 0.87)
119
124
  rubocop-ast (>= 0.7.1)
120
- ruby-progressbar (1.11.0)
121
- ruby_parser (3.19.1)
125
+ ruby-progressbar (1.13.0)
126
+ ruby_parser (3.20.1)
122
127
  sexp_processor (~> 4.16)
123
- sexp_processor (4.16.1)
128
+ sexp_processor (4.17.0)
124
129
  strings (0.2.1)
125
130
  strings-ansi (~> 0.2)
126
131
  unicode-display_width (>= 1.5, < 3.0)
@@ -129,22 +134,29 @@ GEM
129
134
  sync (0.5.0)
130
135
  terminal-table (3.0.2)
131
136
  unicode-display_width (>= 1.1.1, < 3)
132
- thor (1.0.1)
133
- timecop (0.9.5)
134
- tins (1.31.1)
137
+ thor (1.2.2)
138
+ timecop (0.9.6)
139
+ tins (1.32.1)
135
140
  sync
136
141
  tty-box (0.7.0)
137
142
  pastel (~> 0.8)
138
143
  strings (~> 0.2.0)
139
144
  tty-cursor (~> 0.7)
140
145
  tty-color (0.6.0)
141
- tty-config (0.4.0)
146
+ tty-config (0.6.0)
142
147
  tty-cursor (0.7.1)
143
148
  tty-editor (0.7.0)
144
149
  tty-prompt (~> 0.22)
145
150
  tty-font (0.5.0)
146
151
  tty-logger (0.6.0)
147
152
  pastel (~> 0.8)
153
+ tty-markdown (0.7.2)
154
+ kramdown (>= 1.16.2, < 3.0)
155
+ pastel (~> 0.8)
156
+ rouge (>= 3.14, < 5.0)
157
+ strings (~> 0.2.0)
158
+ tty-color (~> 0.5)
159
+ tty-screen (~> 0.8)
148
160
  tty-prompt (0.23.1)
149
161
  pastel (~> 0.8)
150
162
  tty-reader (~> 0.8)
@@ -159,11 +171,11 @@ GEM
159
171
  pastel (~> 0.8)
160
172
  strings (~> 0.2.0)
161
173
  tty-screen (~> 0.8)
162
- tzinfo (2.0.4)
174
+ tzinfo (2.0.6)
163
175
  concurrent-ruby (~> 1.0)
164
176
  unicode-display_width (1.8.0)
165
177
  unicode_utils (1.4.0)
166
- webmock (3.14.0)
178
+ webmock (3.18.1)
167
179
  addressable (>= 2.8.0)
168
180
  crack (>= 0.3.2)
169
181
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -182,4 +194,4 @@ DEPENDENCIES
182
194
  webmock (~> 3.5)
183
195
 
184
196
  BUNDLED WITH
185
- 2.3.16
197
+ 2.4.13
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)
@@ -69,6 +70,7 @@ $ dri profile
69
70
  - [7. analyze](#7-analyze)
70
71
  - stacktraces
71
72
  - [8. version](#8-version)
73
+ - [9. faq](#8-faq)
72
74
 
73
75
  #### 1. init
74
76
 
@@ -96,6 +98,11 @@ $ dri fetch failures
96
98
  Fetches today's opened failures and lists them according to their triage status.
97
99
  Helpful to understand if there are missing recent failures to be reviewed.
98
100
 
101
+ There is the possibility to customise the timeframe for such failures by passing a
102
+ `--start_date=DD-MM-YYYY` and `--end_date=DD-MM-YYYY`. It is also possible to pass
103
+ a `--cutoff=HH:MM` to just show failures after a certain period of the day. The cutoff
104
+ time will be converted to UTC.
105
+
99
106
  To surface most urgent issues pass the `--urgent` flag to see issues that are both
100
107
  in `canary` and `staging-canary` pipelines just during today's timespan.
101
108
 
@@ -139,6 +146,13 @@ $ dri fetch pipelines
139
146
  Fetches a table containing last executed pipeline and its test report link for all monitored pipelines.
140
147
  The timestamps are in UTC
141
148
 
149
+ ```shell
150
+ $ dri fetch runbooks [runbook]
151
+ ```
152
+
153
+ Fetches a runbook from the [runbooks](https://gitlab.com/gitlab-org/quality/runbooks) project.
154
+ If `[runbook]` is omitted, the command will prompt the user to select from a list of available runbooks.
155
+
142
156
  #### 4. publish
143
157
 
144
158
  ```shell
@@ -220,6 +234,15 @@ $ dri version
220
234
 
221
235
  `dri` gem version.
222
236
 
237
+ #### 9. faq
238
+
239
+ ```shell
240
+ $ dri faq
241
+ ```
242
+
243
+ Returns a list of questions and answers related to on-call operations. This leverages
244
+ existing pages of documentation, redirecting directly to the relevant section to help
245
+ with a problem.
223
246
  ## Copyright
224
247
 
225
248
  Copyright (c) 2022 GitLab, Inc. See [MIT License](LICENSE.txt) for further details.
data/dri.gemspec CHANGED
@@ -23,17 +23,19 @@ 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.18"
27
- spec.add_dependency 'httparty', '~> 0.20.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
+ spec.add_dependency 'launchy', '~> 2.4'
29
30
  spec.add_dependency 'markdown-tables', '~> 1.1.1'
30
31
  spec.add_dependency 'pastel', '~> 0.8.0'
31
- spec.add_dependency 'thor', '~> 1.0.1'
32
+ spec.add_dependency 'thor', '~> 1.2.0'
32
33
  spec.add_dependency 'tty-box', '~> 0.7.0'
33
- spec.add_dependency 'tty-config', '~> 0.4.0'
34
- spec.add_dependency 'tty-editor', '~> 0.6'
34
+ spec.add_dependency 'tty-config', '~> 0.6.0'
35
+ spec.add_dependency 'tty-editor', '~> 0.7'
35
36
  spec.add_dependency 'tty-font', '~> 0.5'
36
37
  spec.add_dependency 'tty-logger', '~> 0.6.0'
38
+ spec.add_dependency 'tty-markdown', '~> 0.7.0'
37
39
  spec.add_dependency 'tty-prompt', '~> 0.23.1'
38
40
  spec.add_dependency 'tty-spinner', '~> 0.9'
39
41
  spec.add_dependency 'tty-table', '~> 0.12.0'
data/faq.yaml ADDED
@@ -0,0 +1,21 @@
1
+ ---
2
+ - question: "Which pipelines we currently have and what is their running cadence?"
3
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#qa-test-pipelines"
4
+ - question: "Where can I find the rotation schedule?"
5
+ link: "https://gitlab.com/gitlab-org/quality/pipeline-triage#dri-weekly-rotation-schedule"
6
+ - question: "What is the process to quarantine a test?"
7
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#quarantining-tests"
8
+ - question: "What is the process to dequarantine a test?"
9
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#dequarantining-tests"
10
+ - question: "What are the failure classification labels?"
11
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#classify-and-triage-the-test-failure"
12
+ - question: "I have a correlation ID. How to find logs from various GitLab components?"
13
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#kibana-correlation-dashboards"
14
+ - question: "Where do I find the MR that introduced a feature flag?"
15
+ link: "https://samdbeckham.gitlab.io/feature-flags/#%5B%7B%22type%22:%22filtered-search-term%22,%22value%22:%7B%22data%22:%22%22%7D%7D%5D"
16
+ - question: "What to do when a failure needs escalation?"
17
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#failure-needs-escalation"
18
+ - question: "I have an MR to fix the failure. How I make sure it is merged as soon as possible?"
19
+ link: "https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#fixing-the-test"
20
+
21
+
@@ -160,15 +160,24 @@ module Dri
160
160
 
161
161
  # Fetch all new failures
162
162
  #
163
- # @param [String] date
163
+ # @param [String] start_date
164
+ # @param [String] end_date
164
165
  # @param [String] state
165
166
  # @return [Array<Gitlab::ObjectifiedHash>]
166
- def fetch_all_new_failures(date:, state:)
167
+ def fetch_all_new_failures(start_date:, end_date:, state:)
167
168
  project_ids = [GITLAB_PROJECT_ID, CUSTOMERSDOT_PROJECT_ID]
168
169
  failures = []
169
170
 
171
+ start_date_iso = start_date.strftime('%Y-%m-%dT00:00:00Z')
172
+ end_date_iso = end_date.strftime('%Y-%m-%dT23:59:59Z')
173
+
170
174
  project_ids.each do |project_id|
171
- failures += fetch_new_failures(project_id: project_id, date: date, state: state)
175
+ failures += fetch_new_failures(
176
+ project_id: project_id,
177
+ start_date: start_date_iso,
178
+ end_date: end_date_iso,
179
+ state: state
180
+ )
172
181
  end
173
182
 
174
183
  failures
@@ -177,17 +186,20 @@ module Dri
177
186
  # Fetch new failures for a given project
178
187
  #
179
188
  # @param [Integer] project_id
180
- # @param [String] date
189
+ # @param [String] start_date
190
+ # @param [String] end_date
181
191
  # @param [String] state
182
192
  # @return [Array<Gitlab::ObjectifiedHash>]
183
- def fetch_new_failures(project_id:, date:, state:)
193
+ def fetch_new_failures(project_id:, start_date:, end_date:, state:)
184
194
  gitlab.issues(
185
195
  project_id,
186
196
  labels: FAILURE_NEW,
187
- order_by: "updated_at",
197
+ order_by: "created_at",
198
+ sort: 'desc',
188
199
  state: state,
189
200
  scope: "all",
190
- created_after: date,
201
+ created_after: start_date,
202
+ created_before: end_date,
191
203
  per_page: 100
192
204
  )
193
205
  end
@@ -279,6 +291,28 @@ module Dri
279
291
  gitlab.pipeline_jobs(project_id, pipeline_id, options).auto_paginate
280
292
  end
281
293
 
294
+ # Fetch runbooks from the runbooks project
295
+ #
296
+ # @param [Integer] project_id
297
+ # @return [Array<Gitlab::ObjectifedHash>]
298
+ def list_runbooks(project_id = RUNBOOKS_PROJECT_ID)
299
+ tree = gitlab.tree(project_id, { recursive: true, ref: 'main' }).auto_paginate
300
+
301
+ tree.select do |node|
302
+ node.type == 'tree' && !node.name.start_with?('_')
303
+ end
304
+ end
305
+
306
+ # Fetches file contents at <path>
307
+ #
308
+ # @param [String] path
309
+ # @param [String] ref
310
+ # @param [Integer] project_id
311
+ # @return [Gitlab::ObjectifiedHash]
312
+ def get_file(path, ref:, project_id:)
313
+ gitlab.get_file(project_id, path, ref)
314
+ end
315
+
282
316
  private
283
317
 
284
318
  attr_reader :token, :ops_token
data/lib/dri/cli.rb CHANGED
@@ -77,6 +77,23 @@ module Dri
77
77
  end
78
78
  end
79
79
 
80
+ desc 'faq', 'Consult frequently ask questions while on-call'
81
+ method_option :help, aliases: '-h', type: :boolean,
82
+ desc: 'Display usage information'
83
+
84
+ def faq(*)
85
+ if options[:help]
86
+ invoke :help, ['faq']
87
+ else
88
+ begin
89
+ require_relative 'commands/faq'
90
+ Dri::Commands::FAQ.new(options).execute
91
+ rescue Dri::Commands::FAQ::ExitCommand
92
+ puts "Exiting faq command..."
93
+ end
94
+ end
95
+ end
96
+
80
97
  require_relative 'commands/fetch'
81
98
  register Dri::Commands::Fetch, 'fetch', 'fetch [SUBCOMMAND]', 'Fetch failures & testcases'
82
99
 
data/lib/dri/command.rb CHANGED
@@ -16,6 +16,10 @@ module Dri
16
16
 
17
17
  def_delegators :command, :run
18
18
 
19
+ def initialize(*options)
20
+ @options = options
21
+ end
22
+
19
23
  def pastel(**options)
20
24
  Pastel.new(**options)
21
25
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require 'tty-prompt'
5
+ require 'launchy'
6
+
7
+ module Dri
8
+ module Commands
9
+ class FAQ < Dri::Command
10
+ ExitCommand = Class.new(StandardError)
11
+
12
+ def execute(input: $stdin, output: $stdout)
13
+ root_dir = File.expand_path('../../..', __dir__)
14
+ faq_file = File.join(root_dir, 'faq.yaml')
15
+ faq_data = YAML.load_file(faq_file)
16
+
17
+ prompt = TTY::Prompt.new
18
+
19
+ choices = faq_data.map { |entry| { name: entry['question'], value: entry['link'] } }
20
+
21
+ url = prompt.select("Select a question:", choices)
22
+ raise ExitCommand if url.nil? || url.strip.empty?
23
+
24
+ begin
25
+ Launchy.open(url)
26
+ rescue Launchy::Error => e
27
+ puts "Failed to open URL: #{e.message}"
28
+ raise ExitCommand
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -12,17 +12,11 @@ module Dri
12
12
  include Dri::Utils::Constants::Triage::Labels
13
13
  using Refinements
14
14
 
15
- SORT_BY_OPTIONS = {
16
- title: 0,
17
- triaged: 1,
18
- environment: 2,
19
- author: 3,
20
- url: 4
21
- }.freeze
22
-
23
15
  def initialize(options)
24
16
  @options = options
25
- @today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
17
+ @start_date = @options[:start_date] ? Date.parse(@options[:start_date]) : Date.today
18
+ @end_date = @options[:end_date] ? Date.parse(@options[:end_date]) : Date.today
19
+ @cutoff_time = @options[:cutoff] ? Time.parse(options[:cutoff]).utc : nil
26
20
  end
27
21
 
28
22
  def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
@@ -35,26 +29,40 @@ module Dri
35
29
  environment = add_color('Environment', :bright_yellow)
36
30
  author = add_color('Author', :bright_yellow)
37
31
  url = add_color('URL', :bright_yellow)
32
+ updated_at = add_color('Updated at', :bright_yellow)
38
33
 
39
34
  sorted_failures = []
40
- labels = [title, triaged, environment, author, url]
35
+ labels = { title: title, triaged: triaged, environment: environment, author: author, url: url,
36
+ updated_at: updated_at }
41
37
  triaged_counter = 0
42
38
 
43
- logger.info "Fetching today's failures..."
39
+ if @cutoff_time
40
+ @start_date = Time.new(
41
+ @start_date.year,
42
+ @start_date.month,
43
+ @start_date.day,
44
+ @cutoff_time.hour,
45
+ @cutoff_time.min, 0,
46
+ "+00:00"
47
+ )
48
+ end
49
+
50
+ logger.info "Fetching failures from #{@start_date} (UTC) to #{@end_date} (UTC)..."
44
51
 
45
52
  spinner.run do # rubocop:disable Metrics/BlockLength
46
- failures = api_client.fetch_all_new_failures(date: @today_iso_format, state: 'opened')
53
+ failures = api_client.fetch_all_new_failures(start_date: @start_date, end_date: @end_date, state: 'opened')
47
54
 
48
55
  if failures.empty?
49
- logger.info 'Life is great, there are no new failures today!'
56
+ logger.info "Life is great, there are no new failures between #{@start_date} and #{@end_date}!"
50
57
  exit 0
51
58
  end
52
59
 
53
60
  failures.each do |failure|
54
61
  project_id = failure.project_id
55
62
  title = failure.title.truncate(60)
56
- author = failure.to_h.dig('author', 'username')
63
+ author = failure.to_h.dig('author', 'username').truncate(25)
57
64
  url = failure.web_url
65
+ updated_at = failure.updated_at
58
66
  triaged = add_color('x', :red)
59
67
  envs = failure.labels.select { |l| l.include?(FOUND) }.map do |l|
60
68
  env = l.split(':').last.gsub('.gitlab.com', '')
@@ -63,6 +71,8 @@ module Dri
63
71
  end
64
72
  urgent = urgent_environments.all? { |env| envs.include?(env) }
65
73
 
74
+ next if @options[:urgent] && !urgent
75
+
66
76
  emoji_awards = api_client.fetch_awarded_emojis(failure.iid, project_id: project_id).find do |e|
67
77
  e.name == emoji && e.to_h.dig('user', 'username') == username
68
78
  end
@@ -72,14 +82,11 @@ module Dri
72
82
  triaged_counter += 1
73
83
  end
74
84
 
75
- if @options[:urgent]
76
- sorted_failures << [title, triaged, envs.first, author, url] if urgent
77
- else
78
- sorted_failures << [title, triaged, envs.first, author, url]
79
- end
85
+ sorted_failures << { title: title, triaged: triaged, environment: envs.first, author: author, url: url,
86
+ updated_at: updated_at }
80
87
  end
81
88
 
82
- sorted_failures.sort_by! { |failure| failure[SORT_BY_OPTIONS[@options[:sort_by]&.to_sym || :environment]] }
89
+ sorted_failures.sort_by! { |failure| failure[@options[:sort_by]&.to_sym || :environment] }
83
90
  end
84
91
 
85
92
  msg = if @options[:urgent]
@@ -92,7 +99,14 @@ module Dri
92
99
  MSG
93
100
  end
94
101
 
95
- print_table(labels, sorted_failures, alignments: [:left, :center, :center, :left])
102
+ terminal_width = TTY::Screen.width
103
+
104
+ if terminal_width <= 210 # adjust the desired minimum width
105
+ labels.delete(:updated_at)
106
+ sorted_failures.map { |failure| failure.delete(:updated_at) }
107
+ end
108
+
109
+ print_table(labels.values, sorted_failures.map(&:values), alignments: [:left, :center, :center, :left, :left])
96
110
  output.puts(msg)
97
111
  end
98
112
  end
@@ -120,7 +120,6 @@ module Dri
120
120
  tests_exceed_threshold?(project_id: project_id, pipeline_id: pipeline_id, ops: ops)
121
121
  else
122
122
  contains_stage?(jobs, "qa") || contains_stage?(jobs, "test")
123
- # Nightly pipeline does not execute full E2E suite if sanity fails so can't check tests count
124
123
  end
125
124
  end
126
125
 
@@ -161,8 +160,6 @@ module Dri
161
160
  case pipeline_name
162
161
  when "master"
163
162
  "e2e-package-and-test"
164
- when "nightly"
165
- pipeline_name
166
163
  when "pre_prod"
167
164
  "preprod-#{run_type(sanity)}"
168
165
  else
@@ -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
@@ -14,7 +14,6 @@ module Dri
14
14
  main
15
15
  canary
16
16
  master
17
- nightly
18
17
  production
19
18
  staging-canary
20
19
  staging-ref
@@ -45,13 +45,20 @@ module Dri
45
45
  end
46
46
  end
47
47
 
48
- desc 'failures', 'Display failures opened today'
48
+ desc 'failures', 'Display failures opened on a given period.'
49
49
  method_option :help, aliases: '-h', type: :boolean,
50
50
  desc: 'Display usage information'
51
51
  method_option :urgent, type: :boolean,
52
52
  desc: 'Shows failures that quickly escalated'
53
53
  method_option :sort_by, type: :string,
54
54
  desc: 'Shows failures in specified order'
55
+ method_option :start_date, type: :string,
56
+ desc: 'Fetch failures created after this date (YYYY-MM-DD)'
57
+ method_option :end_date, type: :string,
58
+ desc: 'Fetch failures created before this date (YYYY-MM-DD)'
59
+ method_option :cutoff, type: :string,
60
+ desc: 'Fetch failures created after this time (HH:MM)'
61
+
55
62
  def failures(*)
56
63
  if options[:help]
57
64
  invoke :help, ['failures']
@@ -94,6 +101,17 @@ module Dri
94
101
  require_relative 'fetch/pipelines'
95
102
  Dri::Commands::Fetch::Pipelines.new(options).execute
96
103
  end
104
+
105
+ desc 'runbooks', 'Fetch runbooks'
106
+ method_option :help, aliases: '-h', type: :boolean,
107
+ desc: 'Display usage information'
108
+
109
+ def runbooks(*args)
110
+ return invoke :help, %w[runbooks] if options[:help]
111
+
112
+ require_relative 'fetch/runbooks'
113
+ Dri::Commands::Fetch::Runbooks.new(options).execute(folder: args.first)
114
+ end
97
115
  end
98
116
  end
99
117
  end
@@ -20,10 +20,12 @@ module Dri
20
20
  logger.info "🔎 Looking for profiles...\n"
21
21
 
22
22
  if config.exist?
23
+ width = handover_report_path.nil? ? 30 : 75
24
+
23
25
  frame_args = {
24
- width: 30,
26
+ width: width,
25
27
  height: 10,
26
- align: :center,
28
+ align: :left,
27
29
  padding: 1,
28
30
  border: :thick,
29
31
  title: { top_left: add_color('PROFILE:', :bright_cyan) }
@@ -37,10 +39,13 @@ module Dri
37
39
 
38
40
  def pretty_print_profile
39
41
  <<~PROFILE
40
- #{add_color('User:', :bright_cyan)} #{username}\n #{add_color('Token:', :bright_cyan)} #{token}
42
+ #{add_color('User:', :bright_cyan)} #{username}
43
+ #{add_color('Token:', :bright_cyan)} #{token}
41
44
  #{add_color('OpsToken:', :bright_cyan)} #{ops_token}
42
45
  #{add_color('Timezone:', :bright_cyan)} #{timezone}
43
46
  #{add_color('Emoji:', :bright_cyan)} #{emoji}
47
+ #{add_color('Report Path:', :bright_cyan)} #{handover_report_path}
48
+
44
49
  PROFILE
45
50
  end
46
51
  end
data/lib/dri/report.rb CHANGED
@@ -83,7 +83,6 @@ module Dri
83
83
  'canary.staging.gitlab.com' => '/quality/staging-canary',
84
84
  'main' => '/gitlab-org/gitlab-qa-mirror',
85
85
  'master' => '/gitlab-org/gitlab-qa-mirror',
86
- 'nightly' => '/quality/nightly',
87
86
  'pre.gitlab.com' => '/quality/preprod',
88
87
  'staging-ref' => '/quality/staging-ref',
89
88
  'staging.gitlab.com' => '/quality/staging',
@@ -10,6 +10,7 @@ module Dri
10
10
  CUSTOMERSDOT_PROJECT_ID = 2670515
11
11
  FEATURE_FLAG_LOG_PROJECT_ID = 15208716
12
12
  INFRA_TEAM_PROD_PROJECT_ID = 7444821
13
+ RUNBOOKS_PROJECT_ID = 41045213
13
14
  end
14
15
 
15
16
  module Triage
@@ -62,12 +63,6 @@ module Dri
62
63
  project_id: "547",
63
64
  search_hours_ago: 12
64
65
  },
65
- nightly: {
66
- name: "nightly",
67
- url: "https://gitlab.com/gitlab-org/quality/nightly",
68
- project_id: "7523614",
69
- search_hours_ago: 24
70
- },
71
66
  pre_prod: {
72
67
  name: "pre.gitlab.com",
73
68
  url: "https://ops.gitlab.net/gitlab-org/quality/preprod",
@@ -84,7 +79,7 @@ module Dri
84
79
  name: "master",
85
80
  url: "https://gitlab.com/gitlab-org/gitlab",
86
81
  project_id: "278964",
87
- search_hours_ago: 3
82
+ search_hours_ago: 24
88
83
  }
89
84
  }.freeze
90
85
  end
data/lib/dri/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dri
4
- VERSION = "0.8.0"
4
+ VERSION = "0.10.0"
5
5
  end
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.8.0
4
+ version: 0.10.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: 2022-11-16 00:00:00.000000000 Z
11
+ date: 2023-05-31 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.18'
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.18'
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.20.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.20.0
54
+ version: 0.21.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: json
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 2.6.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: launchy
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.4'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: markdown-tables
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +114,14 @@ dependencies:
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 1.0.1
117
+ version: 1.2.0
104
118
  type: :runtime
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 1.0.1
124
+ version: 1.2.0
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: tty-box
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -128,28 +142,28 @@ dependencies:
128
142
  requirements:
129
143
  - - "~>"
130
144
  - !ruby/object:Gem::Version
131
- version: 0.4.0
145
+ version: 0.6.0
132
146
  type: :runtime
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
- version: 0.4.0
152
+ version: 0.6.0
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: tty-editor
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
157
  - - "~>"
144
158
  - !ruby/object:Gem::Version
145
- version: '0.6'
159
+ version: '0.7'
146
160
  type: :runtime
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
- version: '0.6'
166
+ version: '0.7'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: tty-font
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +192,20 @@ dependencies:
178
192
  - - "~>"
179
193
  - !ruby/object:Gem::Version
180
194
  version: 0.6.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: tty-markdown
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 0.7.0
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 0.7.0
181
209
  - !ruby/object:Gem::Dependency
182
210
  name: tty-prompt
183
211
  requirement: !ruby/object:Gem::Requirement
@@ -315,6 +343,7 @@ files:
315
343
  - ".editorconfig"
316
344
  - ".gitignore"
317
345
  - ".gitlab-ci.yml"
346
+ - ".gitlab/merge_request_templates/Release.md"
318
347
  - ".rspec"
319
348
  - ".rubocop.yml"
320
349
  - ".ruby-version"
@@ -328,17 +357,20 @@ files:
328
357
  - bin/setup
329
358
  - dri.gemspec
330
359
  - exe/dri
360
+ - faq.yaml
331
361
  - lib/dri.rb
332
362
  - lib/dri/api_client.rb
333
363
  - lib/dri/cli.rb
334
364
  - lib/dri/command.rb
335
365
  - lib/dri/commands/analyze.rb
336
366
  - lib/dri/commands/analyze/stack_traces.rb
367
+ - lib/dri/commands/faq.rb
337
368
  - lib/dri/commands/fetch.rb
338
369
  - lib/dri/commands/fetch/failures.rb
339
370
  - lib/dri/commands/fetch/featureflags.rb
340
371
  - lib/dri/commands/fetch/pipelines.rb
341
372
  - lib/dri/commands/fetch/quarantines.rb
373
+ - lib/dri/commands/fetch/runbooks.rb
342
374
  - lib/dri/commands/fetch/testcases.rb
343
375
  - lib/dri/commands/fetch/triaged.rb
344
376
  - lib/dri/commands/incidents.rb