dri 0.1.0 → 0.1.1

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: fb31c263acfb2d576ed72028d207df2d36d76b1965ac00aa5228fbdd991a7524
4
- data.tar.gz: 179c9389a9b3ce00a9f4ff357da3d1f4fdf3af9b22ec96a8d582dfb7d35bf17a
3
+ metadata.gz: e352230c90233014a517cb67addf17a051a2b2eb05c93f0e88bcaab45c40e723
4
+ data.tar.gz: 51bbd9e7f07e20668fa8b6161e41b3995ae47b8d1866be6ad81fd07fc0c37bf1
5
5
  SHA512:
6
- metadata.gz: d38a554fad6c98a72992c2d5c97eae39f6ecebce78ff466174f20074a4aa74b436ee6fcff6192ad4800515056fd9e53ec049a5aa1f6dfa90fdcafa2489376256
7
- data.tar.gz: 2f2994a17800bd2d1fbf02ed9724e9b0428e4ded12ae9516135d19a6b529982d3e36d2148e6ef9df4f6bc740355555831ed035b440d30d89f94fdf814e3a1a99
6
+ metadata.gz: 00b8bcfe9d1d884523f2f5d3963cfa8ab3b7f33f04f819fd17b253838bf899d67394de91524d3dfa40ff692b48c5768f039dc8b6ed44abbcd5faa14b1606eb60
7
+ data.tar.gz: 58a9c606cd89a5282f25b9fe89fcf16bcf9c70d53df868876884d10149e34786de5c3341d216dd227bbb3d44e16649e26032117c1f12e33e61de52168fd54ebe
data/README.md CHANGED
@@ -7,9 +7,9 @@ Welcome to your new gem! DRI is a CLI ready to help:
7
7
  - Fetching failing test cases by pipeline
8
8
  - Reporting at the end of the timezone shift
9
9
  - View today's newest and untriaged failures
10
- - Take actions on failures
10
+ - Mark actions on failures
11
11
 
12
- ... and more.
12
+ ... and more
13
13
 
14
14
  ## Installation
15
15
 
@@ -55,10 +55,13 @@ $ dri profile
55
55
  - [3. fetch](#3-fetch)
56
56
  - failures
57
57
  - testcases
58
+ - triaged
58
59
  - [4. publish](#4-publish)
59
60
  - report
60
61
  - [5. rm](#5-rm)
61
62
  - emoji
63
+ - profile
64
+ - reports
62
65
  - [6. version](#6-version)
63
66
 
64
67
  #### 1. init
@@ -87,6 +90,9 @@ $ dri fetch failures
87
90
  Fetches today's opened failures and lists them according to their triage status.
88
91
  Helpful to understand if there are missing recent failures to be reviewed.
89
92
 
93
+ To surface most urgent issues pass the `--urgent` flag to see issues that are both
94
+ in `canary` and `staging-canary` pipelines just during today's timespan.
95
+
90
96
  ```shell
91
97
  $ dri fetch testcases
92
98
  ```
@@ -95,6 +101,12 @@ Fetches test cases that failing currently and groups them by pipeline.
95
101
  To filter the pipelines, pass the `--filter-pipelines` options to multi-select the pipelines you wish to consult.
96
102
  (Use `Space` to select an option)
97
103
 
104
+ ```shell
105
+ $ dri fetch triaged
106
+ ```
107
+
108
+ Fetches triaged failures which use the triage emoji specified in `dri profile`.
109
+
98
110
  #### 4. publish
99
111
 
100
112
  ```shell
@@ -109,8 +121,22 @@ Publishes a handover report on the latest triage issue, in the [pipeline-triage]
109
121
  $ dri publish report --format=list # formats the report in a list
110
122
  $ dri publish report --format=table # formats the report in a table (default)
111
123
  $ dri publish report --dry-run # the report is only generated locally
124
+ $ dri publish report --actions # activate the actions prompt for each failure
112
125
  ```
113
126
 
127
+ **Note:** These options above can be combined like:
128
+
129
+ ```shell
130
+ $ dri publish report --format=list --dry-run --actions
131
+ ```
132
+
133
+ **Actions**
134
+
135
+ When using `--actions` a set of actions are prompt on each failure. Use `Space` to
136
+ mark several actions: `pinged SET`, `quarantined`, `reproduced`, `transient`.
137
+ Hitting `Enter` without a selected action will skip marking the actions for a given
138
+ failure.
139
+
114
140
  #### 5. rm
115
141
 
116
142
  ```shell
@@ -119,6 +145,20 @@ $ dri rm emoji
119
145
 
120
146
  Removes the triage emoji from all triaged issues.
121
147
 
148
+ ```shell
149
+ $ dri rm reports
150
+ ```
151
+
152
+ When using `$ dri publish report --dry-run` to download the reports locally instead
153
+ of uploading to the latest Pipeline Triage Issue, an `/handover_reports/` folder
154
+ created to store these reports. This command removes this folder and subsequent reports stored in it.
155
+
156
+ ```shell
157
+ $ dri rm profile
158
+ ```
159
+
160
+ Removes the profile currently in use.
161
+
122
162
  #### 6. version
123
163
 
124
164
  ```shell
@@ -9,7 +9,7 @@ module Dri
9
9
 
10
10
  API_URL = 'https://gitlab.com/api/v4'
11
11
  TESTCASES_PROJECT_ID = '11229385'
12
- TRIAGE_PROJECT_ID = '34185524'
12
+ TRIAGE_PROJECT_ID = '15291320'
13
13
  GITLAB_PROJECT_ID = '278964'
14
14
 
15
15
  def initialize(config)
@@ -22,6 +22,7 @@ module Dri
22
22
  url = add_color('URL', :bright_yellow)
23
23
 
24
24
  failures = []
25
+ urgent = []
25
26
  labels = [ title, triaged, author, url ]
26
27
  triaged_counter = 0
27
28
 
@@ -49,13 +50,29 @@ module Dri
49
50
  e['name'] == emoji && e['user']['username'] == @username
50
51
  end
51
52
 
53
+ if @options[:urgent]
54
+ labels = failure["labels"]
55
+
56
+ labels.each do |label|
57
+ if label.include? ("found:canary.gitlab.com" && "found:canary.staging.gitlab.com")
58
+ urgent << [title, triaged, author, url]
59
+ end
60
+ end
61
+ end
62
+
52
63
  failures << [title, triaged, author, url]
53
64
  end
54
65
  end
55
66
 
56
- table = TTY::Table.new(labels, failures)
57
- puts table.render(:ascii, resize: true, alignments: [:center, :center, :center, :center])
58
- output.puts "\nFound: #{failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}."
67
+ if @options[:urgent]
68
+ table = TTY::Table.new(labels, urgent)
69
+ puts table.render(:ascii, resize: true, alignments: [:center, :center, :center, :center])
70
+ output.puts "\nFound: #{urgent.size} urgent failures, found in both canary.gitlab.com and canary.staging.gitlab.com."
71
+ else
72
+ table = TTY::Table.new(labels, failures)
73
+ puts table.render(:ascii, resize: true, alignments: [:center, :center, :center, :center])
74
+ output.puts "\nFound: #{failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}."
75
+ end
59
76
  end
60
77
 
61
78
  private
@@ -0,0 +1,61 @@
1
+ require_relative '../../command'
2
+ require 'tty-table'
3
+
4
+ module Dri
5
+ module Commands
6
+ class Fetch
7
+ class Triaged < Dri::Command
8
+ def initialize(options)
9
+ @options = options
10
+ end
11
+
12
+ def execute(input: $stdin, output: $stdout)
13
+ verify_config_exists
14
+
15
+ title = add_color('Title', :bright_yellow)
16
+ url = add_color('URL', :bright_yellow)
17
+ type_label = add_color('Type', :bright_yellow)
18
+
19
+ table_labels = [ title, url, type_label ]
20
+ failures_triaged = []
21
+
22
+ logger.info "Fetching your triaged failures..."
23
+ spinner.start
24
+
25
+ response = api_client.fetch_triaged_failures(emoji: emoji, state: 'opened')
26
+
27
+ if response.empty?
28
+ logger.info "There are no failures triaged yet with #{add_color(emoji, :black, :on_white)}."
29
+ exit 0
30
+ end
31
+
32
+ response.each do |triaged|
33
+ title = truncate(triaged["title"], 90)
34
+ url = triaged["web_url"]
35
+ labels = triaged["labels"]
36
+ type = ""
37
+
38
+ labels.each do |label|
39
+ type = label.gsub!('failure::', ' ').to_s if label.include? "failure::"
40
+ end
41
+
42
+ labels = triaged["labels"]
43
+
44
+ failures_triaged << [title, url, type]
45
+ end
46
+
47
+ spinner.stop
48
+
49
+ table = TTY::Table.new(table_labels,failures_triaged)
50
+ puts table.render(:ascii, resize: true, alignments: [:center, :center, :center])
51
+ end
52
+
53
+ private
54
+
55
+ def truncate(string, max)
56
+ string.length > max ? "#{string[0...max]}..." : string
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -7,6 +7,18 @@ module Dri
7
7
  class Fetch < Thor
8
8
  namespace :fetch
9
9
 
10
+ desc 'triaged', 'Command description...'
11
+ method_option :help, aliases: '-h', type: :boolean,
12
+ desc: 'Display usage information'
13
+ def triaged(*)
14
+ if options[:help]
15
+ invoke :help, ['triaged']
16
+ else
17
+ require_relative 'fetch/triaged'
18
+ Dri::Commands::Fetch::Triaged.new(options).execute
19
+ end
20
+ end
21
+
10
22
  desc 'testcases', 'Display failing testcases'
11
23
  method_option :help, aliases: '-h', type: :boolean,
12
24
  desc: 'Display usage information'
@@ -24,6 +36,8 @@ module Dri
24
36
  desc 'failures', 'Display failures opened today'
25
37
  method_option :help, aliases: '-h', type: :boolean,
26
38
  desc: 'Display usage information'
39
+ method_option :urgent, type: :boolean,
40
+ desc: 'Shows failures that quickly escalated'
27
41
  def failures(*)
28
42
  if options[:help]
29
43
  invoke :help, ['failures']
@@ -34,9 +34,16 @@ module Dri
34
34
 
35
35
  logger.info "Assembling the report... "
36
36
  # sets each failure on the table
37
+ action_options = ["pinged SET", "reproduced", "transient", "quarantined"]
38
+
37
39
  spinner.start
38
40
  issues.each do |issue|
39
- report.add_failure(issue)
41
+ actions = []
42
+
43
+ if @options[:actions]
44
+ actions = prompt.multi_select("Please mark the actions on #{add_color(issue['title'], :yellow)}: ", action_options)
45
+ end
46
+ report.add_failure(issue, actions)
40
47
  end
41
48
 
42
49
  if @options[:format] == 'list'
@@ -78,7 +85,7 @@ module Dri
78
85
  response = api_client.post_triage_report_note(iid: current_issue_iid, body: note)
79
86
 
80
87
  output.puts "Done! ✅\n"
81
- logger.success "Thanks @#{username}, your report was posted at https://gitlab.com/gitlab-org/quality/dri/-/issues/#{current_issue_iid} 🎉"
88
+ logger.success "Thanks @#{username}, your report was posted at https://gitlab.com/gitlab-org/quality/pipeline-triage/-/issues/#{current_issue_iid} 🎉"
82
89
  end
83
90
  end
84
91
  end
@@ -13,6 +13,8 @@ module Dri
13
13
  desc: 'Generates a report locally'
14
14
  method_option :format, aliases: '-f', type: :string, :default => "table",
15
15
  desc: 'Formats the report'
16
+ method_option :actions, type: :boolean,
17
+ desc: 'Updates actions on failures'
16
18
  def report(*)
17
19
  if options[:help]
18
20
  invoke :help, ['report']
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require 'fileutils'
5
+
6
+ module Dri
7
+ module Commands
8
+ class Rm
9
+ class Profile < Dri::Command
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ def execute(input: $stdin, output: $stdout)
15
+ verify_config_exists
16
+
17
+ remove = prompt.yes? "Are you sure you want to remove existing profile?"
18
+
19
+ unless remove
20
+ logger.info "Profile kept in place 👍"
21
+ exit 0
22
+ end
23
+
24
+ logger.info "Removing profile..."
25
+
26
+ FileUtils.rm("#{Dir.pwd}/.dri_profile.yml")
27
+
28
+ logger.success "Done ✅"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require 'fileutils'
5
+
6
+ module Dri
7
+ module Commands
8
+ class Rm
9
+ class Reports < Dri::Command
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ def execute(input: $stdin, output: $stdout)
15
+ FileUtils.rm_rf("#{Dir.pwd}/handover_reports")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -8,6 +8,30 @@ module Dri
8
8
 
9
9
  namespace :rm
10
10
 
11
+ desc 'profile', 'Command description...'
12
+ method_option :help, aliases: '-h', type: :boolean,
13
+ desc: 'Display usage information'
14
+ def profile(*)
15
+ if options[:help]
16
+ invoke :help, ['profile']
17
+ else
18
+ require_relative 'rm/profile'
19
+ Dri::Commands::Rm::Profile.new(options).execute
20
+ end
21
+ end
22
+
23
+ desc 'reports', 'Command description...'
24
+ method_option :help, aliases: '-h', type: :boolean,
25
+ desc: 'Display usage information'
26
+ def reports(*)
27
+ if options[:help]
28
+ invoke :help, ['reports']
29
+ else
30
+ require_relative 'rm/reports'
31
+ Dri::Commands::Rm::Reports.new(options).execute
32
+ end
33
+ end
34
+
11
35
  desc 'emoji', 'Remove triage emoji from all failures'
12
36
  method_option :help, aliases: '-h', type: :boolean,
13
37
  desc: 'Display usage information'
data/lib/dri/report.rb CHANGED
@@ -17,7 +17,7 @@ module Dri
17
17
  @header = "# #{timezone}, #{@weekday} - #{@date}\n posted by: @#{username}"
18
18
  end
19
19
 
20
- def add_failure(failure)
20
+ def add_failure(failure, actions_opts = [])
21
21
  iid = failure["iid"]
22
22
  title = failure["title"]
23
23
  link = failure["web_url"]
@@ -38,10 +38,10 @@ module Dri
38
38
  assigned_status = assigned?(assignees)
39
39
  pipelines = filter_pipeline_labels(labels)
40
40
 
41
- linked_pipelines = link_pipelines(iid, pipelines)
41
+ linked_pipelines = link_pipelines(iid, pipelines, description)
42
42
 
43
43
  actions = ""
44
- actions.concat actions_status_template(failure_type, assigned_status)
44
+ actions.concat actions_status_template(failure_type, assigned_status, actions_opts)
45
45
  actions.concat actions_fixes_template(related_mrs)
46
46
 
47
47
  @failures << [title, emojified_link, linked_pipelines, stack_trace, actions]
@@ -49,28 +49,75 @@ module Dri
49
49
 
50
50
  private
51
51
 
52
- def link_pipelines(iid, pipelines)
52
+ def link_pipelines(iid, pipelines, description)
53
+ linked = []
54
+ label_pipeline_map = {
55
+ 'gitlab.com' => '/quality/production',
56
+ 'canary.gitlab.com' => '/quality/canary',
57
+ # 'canary.staging.gitlab.com' => '',
58
+ 'main' => '/gitlab-org/gitlab-qa-mirror',
59
+ 'master' => '/gitlab-org/gitlab-qa-mirror',
60
+ 'nightly' => '/quality/nightly',
61
+ 'pre.gitlab.com' => '/quality/preprod',
62
+ 'staging-ref' => '/quality/staging-ref',
63
+ 'staging.gitlab.com' => '/quality/staging',
64
+ 'release' => '/quality/release'
65
+ }
66
+
53
67
  failure_notes = @api_client.fetch_failure_notes(issue_iid: iid)
54
68
 
55
- linked = ""
69
+ return if pipelines.empty?
56
70
 
57
71
  pipelines.each do |pipeline|
58
- failure_notes.each do |note|
59
- if note["body"].include? pipeline
60
- pipeline_link = URI.extract(note["body"], %w(https))
61
- pipeline_link_sanitized = pipeline_link.join.strip
62
- pipeline = "[#{pipeline}](#{pipeline_link_sanitized})"
63
- break
64
- end
72
+ next if !label_pipeline_map.has_key? pipeline
73
+
74
+ pipeline_in_notes_found = false
75
+ pipeline_link = ''
76
+ pipeline_link_sanitized = ''
77
+ pipeline_markdown = ''
78
+
79
+ failure_notes.each do |note|
80
+ if note["body"].include? label_pipeline_map.fetch(pipeline)
81
+ pipeline_in_notes_found = true
82
+ pipeline_link = URI.extract(note["body"], %w(https))
83
+ break
65
84
  end
85
+ end
86
+
87
+ unless pipeline_in_notes_found
88
+ links_description = URI.extract(description, %w(https))
89
+ pipeline_link = links_description.select { |link| link.include? label_pipeline_map.fetch(pipeline) }
90
+ end
66
91
 
67
- linked << pipeline
92
+ if !pipeline_link.empty?
93
+ pipeline_link_sanitized = pipeline_link.join.strip.chop
94
+ pipeline_markdown = "[#{pipeline.gsub(/.gitlab.com/, '')}](#{pipeline_link_sanitized})"
95
+ linked << pipeline_markdown
96
+ end
68
97
  end
69
- linked
98
+ linked.join(', ')
70
99
  end
71
100
 
72
- def actions_status_template(failure_type, assigned_status)
73
- "<i>Status:</i><ul><li>#{failure_type}</li><li>#{assigned_status}</li><li>[ ] notified SET</li><li>[ ] quarantined</li></ul>"
101
+ def actions_status_template(failure_type, assigned_status, actions_opts)
102
+ notified_set = ''
103
+ quarantined = ''
104
+ reproduced = ''
105
+ transient = ''
106
+
107
+ notified_set = '<li>[x] notified SET</li>' if actions_opts.include? 'pinged SET'
108
+ quarantined = '<li>[x] quarantined</li>' if actions_opts.include? 'quarantined'
109
+ reproduced = '<li>[x] reproduced</li>' if actions_opts.include? 'reproduced'
110
+ transient = '<li>[x] transient</li>' if actions_opts.include? 'transient'
111
+
112
+ action_status = "<i>Status:</i><ul>"
113
+ action_status << "<li>#{failure_type}</li>"
114
+ action_status << "</li><li>#{assigned_status}</li>"
115
+ action_status << notified_set
116
+ action_status << quarantined
117
+ action_status << reproduced
118
+ action_status << transient
119
+
120
+ action_status
74
121
  end
75
122
 
76
123
  def actions_fixes_template(related_mrs)
@@ -90,10 +137,10 @@ module Dri
90
137
  pipelines = []
91
138
 
92
139
  labels.each do |label|
93
- matchers = { 'found:' => ' ', '.gitlab.com' => ' ' }
140
+ matchers = { 'found:' => ' '}
94
141
 
95
142
  if label.include? "found:"
96
- pipeline = label.gsub(/found:|.gitlab.com/) { |match| matchers[match] }
143
+ pipeline = label.gsub(/found:/) { |match| matchers[match] }
97
144
  pipelines << pipeline.strip
98
145
  end
99
146
  end
data/lib/dri/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dri
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  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.1.0
4
+ version: 0.1.1
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-03-10 00:00:00.000000000 Z
11
+ date: 2022-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-config
@@ -276,12 +276,15 @@ files:
276
276
  - lib/dri/commands/fetch.rb
277
277
  - lib/dri/commands/fetch/failures.rb
278
278
  - lib/dri/commands/fetch/testcases.rb
279
+ - lib/dri/commands/fetch/triaged.rb
279
280
  - lib/dri/commands/init.rb
280
281
  - lib/dri/commands/profile.rb
281
282
  - lib/dri/commands/publish.rb
282
283
  - lib/dri/commands/publish/report.rb
283
284
  - lib/dri/commands/rm.rb
284
285
  - lib/dri/commands/rm/emoji.rb
286
+ - lib/dri/commands/rm/profile.rb
287
+ - lib/dri/commands/rm/reports.rb
285
288
  - lib/dri/report.rb
286
289
  - lib/dri/utils/markdown_lists.rb
287
290
  - lib/dri/version.rb