dri 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.gitlab-ci.yml +32 -13
- data/.rubocop.yml +53 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/Gemfile +2 -3
- data/Gemfile.lock +69 -17
- data/README.md +22 -0
- data/Rakefile +3 -1
- data/bin/console +1 -0
- data/dri.gemspec +25 -22
- data/exe/dri +3 -3
- data/lib/dri/api_client.rb +41 -10
- data/lib/dri/cli.rb +2 -2
- data/lib/dri/command.rb +7 -5
- data/lib/dri/commands/fetch/failures.rb +29 -29
- data/lib/dri/commands/fetch/featureflags.rb +95 -0
- data/lib/dri/commands/fetch/quarantines.rb +53 -0
- data/lib/dri/commands/fetch/testcases.rb +18 -7
- data/lib/dri/commands/fetch/triaged.rb +14 -18
- data/lib/dri/commands/fetch.rb +36 -2
- data/lib/dri/commands/init.rb +9 -6
- data/lib/dri/commands/profile.rb +14 -5
- data/lib/dri/commands/publish/report.rb +24 -9
- data/lib/dri/commands/publish.rb +4 -5
- data/lib/dri/commands/rm/emoji.rb +5 -5
- data/lib/dri/commands/rm/profile.rb +2 -2
- data/lib/dri/commands/rm.rb +0 -1
- data/lib/dri/refinements/truncate.rb +15 -0
- data/lib/dri/report.rb +56 -41
- data/lib/dri/utils/markdown_lists.rb +7 -9
- data/lib/dri/utils/table.rb +20 -0
- data/lib/dri/version.rb +3 -1
- data/lib/dri.rb +2 -0
- metadata +67 -46
@@ -1,19 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
|
-
|
5
|
-
require 'tty-table'
|
4
|
+
require_relative '../../utils/table'
|
6
5
|
|
7
6
|
module Dri
|
8
7
|
module Commands
|
9
8
|
class Fetch
|
10
9
|
class Failures < Dri::Command
|
10
|
+
include Dri::Utils::Table
|
11
|
+
using Refinements
|
12
|
+
|
11
13
|
def initialize(options)
|
12
14
|
@options = options
|
13
15
|
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
14
16
|
end
|
15
17
|
|
16
|
-
def execute(input: $stdin, output: $stdout)
|
18
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
17
19
|
verify_config_exists
|
18
20
|
|
19
21
|
title = add_color('Title', :bright_yellow)
|
@@ -23,38 +25,40 @@ module Dri
|
|
23
25
|
|
24
26
|
failures = []
|
25
27
|
urgent = []
|
26
|
-
labels = [
|
28
|
+
labels = [title, triaged, author, url]
|
27
29
|
triaged_counter = 0
|
28
30
|
|
29
|
-
logger.info "Fetching today
|
30
|
-
|
31
|
-
spinner.run do
|
31
|
+
logger.info "Fetching today's failures..."
|
32
32
|
|
33
|
+
spinner.run do # rubocop:disable Metrics/BlockLength
|
33
34
|
response = api_client.fetch_failures(date: @today_iso_format, state: 'opened')
|
34
35
|
|
35
36
|
if response.nil?
|
36
|
-
logger.info
|
37
|
+
logger.info 'Life is great, there are no new failures today!'
|
37
38
|
exit 0
|
38
39
|
end
|
39
40
|
|
40
41
|
response.each do |failure|
|
41
|
-
title =
|
42
|
-
author = failure[
|
43
|
-
url = failure[
|
44
|
-
award_emoji_url = failure[
|
42
|
+
title = failure['title'].truncate(60)
|
43
|
+
author = failure['author']['username']
|
44
|
+
url = failure['web_url']
|
45
|
+
award_emoji_url = failure['_links']['award_emoji']
|
45
46
|
triaged = add_color('x', :red)
|
46
47
|
|
47
|
-
emoji_awards = api_client.fetch_awarded_emojis(award_emoji_url)
|
48
|
+
emoji_awards = api_client.fetch_awarded_emojis(award_emoji_url).find do |e|
|
49
|
+
(e['name'] == emoji) && (e['user']['username'] == username)
|
50
|
+
end
|
48
51
|
|
49
|
-
|
50
|
-
|
52
|
+
if emoji_awards
|
53
|
+
triaged = add_color('✓', :green)
|
54
|
+
triaged_counter += 1
|
51
55
|
end
|
52
56
|
|
53
57
|
if @options[:urgent]
|
54
|
-
labels = failure[
|
58
|
+
labels = failure['labels']
|
55
59
|
|
56
60
|
labels.each do |label|
|
57
|
-
if label.include?
|
61
|
+
if label.include?('found:canary.gitlab.com' && 'found:canary.staging.gitlab.com')
|
58
62
|
urgent << [title, triaged, author, url]
|
59
63
|
end
|
60
64
|
end
|
@@ -65,21 +69,17 @@ module Dri
|
|
65
69
|
end
|
66
70
|
|
67
71
|
if @options[:urgent]
|
68
|
-
|
69
|
-
puts
|
70
|
-
|
72
|
+
print_table(labels, urgent, alignments: [:left, :center, :center, :left])
|
73
|
+
output.puts(<<~MSG)
|
74
|
+
Found: #{urgent.size} urgent failures, occurring in both canary.gitlab.com and canary.staging.gitlab.com.
|
75
|
+
MSG
|
71
76
|
else
|
72
|
-
|
73
|
-
puts
|
74
|
-
|
77
|
+
print_table(labels, failures, alignments: [:left, :center, :center, :left])
|
78
|
+
output.puts(<<~MSG)
|
79
|
+
Found: #{failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
|
80
|
+
MSG
|
75
81
|
end
|
76
82
|
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def truncate(string, max)
|
81
|
-
string.length > max ? "#{string[0...max]}..." : string
|
82
|
-
end
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../utils/table'
|
5
|
+
|
6
|
+
module Dri
|
7
|
+
module Commands
|
8
|
+
class Fetch
|
9
|
+
class FeatureFlags < Dri::Command
|
10
|
+
include Dri::Utils::Table
|
11
|
+
|
12
|
+
PRODUCTION = 'host::gitlab.com'
|
13
|
+
STAGING = 'host::staging.gitlab.com'
|
14
|
+
STAGING_REF = 'host::staging-ref.gitlab.com'
|
15
|
+
PREPROD = 'host::pre.gitlab.com'
|
16
|
+
|
17
|
+
def initialize(options)
|
18
|
+
@options = options
|
19
|
+
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
23
|
+
verify_config_exists
|
24
|
+
|
25
|
+
summary = add_color('Summary', :bright_yellow)
|
26
|
+
changed_on = add_color('Changed(UTC)', :bright_yellow)
|
27
|
+
url = add_color('URL', :bright_yellow)
|
28
|
+
|
29
|
+
prod_feature_flags = []
|
30
|
+
staging_feature_flags = []
|
31
|
+
staging_ref_feature_flags = []
|
32
|
+
preprod_feature_flags = []
|
33
|
+
|
34
|
+
headers = [summary, changed_on, url]
|
35
|
+
|
36
|
+
logger.info "Fetching today's feature flag changes..."
|
37
|
+
|
38
|
+
spinner.run do # rubocop:disable Metrics/BlockLength
|
39
|
+
page = 1
|
40
|
+
loop do # rubocop:disable Metrics/BlockLength
|
41
|
+
response = api_client.fetch_feature_flag_logs(date: @today_iso_format, page: page)
|
42
|
+
|
43
|
+
if response.nil? && page == 1
|
44
|
+
logger.info 'It\'s been quiet...no feature flag changes for today 👀'
|
45
|
+
exit 0
|
46
|
+
end
|
47
|
+
|
48
|
+
response.each do |feature_flag|
|
49
|
+
summary = feature_flag['title']
|
50
|
+
|
51
|
+
substrings = ["set to \"true\"", "set to \"false\""]
|
52
|
+
next unless substrings.any? { |substr| summary.include?(substr) }
|
53
|
+
|
54
|
+
changed_on = feature_flag['description'][/(?<=Changed on \(in UTC\): ).+?(?=\n)/].delete('`')
|
55
|
+
url = feature_flag['web_url']
|
56
|
+
|
57
|
+
feature_flag_data = [summary, changed_on, url]
|
58
|
+
|
59
|
+
labels = feature_flag['labels']
|
60
|
+
host_label = labels.select { |label| /^host::/.match(label) }.join('')
|
61
|
+
|
62
|
+
case host_label
|
63
|
+
when PRODUCTION
|
64
|
+
prod_feature_flags << feature_flag_data
|
65
|
+
when STAGING
|
66
|
+
staging_feature_flags << feature_flag_data
|
67
|
+
when STAGING_REF
|
68
|
+
staging_ref_feature_flags << feature_flag_data
|
69
|
+
when PREPROD
|
70
|
+
preprod_feature_flags << feature_flag_data
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
page += 1
|
75
|
+
break if response.count < 100 || response.nil?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
print_results('Production', headers, prod_feature_flags, output) unless prod_feature_flags.empty?
|
80
|
+
print_results('Staging', headers, staging_feature_flags, output) unless staging_feature_flags.empty?
|
81
|
+
print_results('Staging Ref', headers, staging_ref_feature_flags, output) unless staging_ref_feature_flags.empty? # rubocop:disable Layout/LineLength
|
82
|
+
print_results('Preprod', headers, preprod_feature_flags, output) unless preprod_feature_flags.empty?
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def print_results(env, headers, rows, output_src)
|
88
|
+
puts "\n#{add_color(env, :bright_blue)}"
|
89
|
+
print_table(headers, rows)
|
90
|
+
output_src.puts "\nFound: #{rows.count} feature flag change(s) set to true or false on #{env}."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../utils/table'
|
5
|
+
|
6
|
+
module Dri
|
7
|
+
module Commands
|
8
|
+
class Fetch
|
9
|
+
class Quarantines < Dri::Command
|
10
|
+
include Dri::Utils::Table
|
11
|
+
using Refinements
|
12
|
+
|
13
|
+
def initialize(options, search: '[QUARANTINE]')
|
14
|
+
@options = options
|
15
|
+
@search = search
|
16
|
+
|
17
|
+
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute(input: $stdin, output: $stdout)
|
21
|
+
verify_config_exists
|
22
|
+
title = add_color('Example name', :bright_yellow)
|
23
|
+
url = add_color('URL', :bright_yellow)
|
24
|
+
|
25
|
+
headers = [title, url]
|
26
|
+
mrs = []
|
27
|
+
|
28
|
+
logger.info "Fetching #{@search} MRs..."
|
29
|
+
|
30
|
+
spinner.run do
|
31
|
+
response = api_client.fetch_mrs(
|
32
|
+
project_id: 'gitlab-org/gitlab',
|
33
|
+
labels: 'QA,Quality',
|
34
|
+
search: @search,
|
35
|
+
in: :title,
|
36
|
+
state: :opened
|
37
|
+
)
|
38
|
+
|
39
|
+
mrs = response.each_with_object([]) do |mr, found_mrs|
|
40
|
+
title = mr['title'][13..].truncate(60) # remove the "[QUARANTINE] " prefix
|
41
|
+
url = mr['web_url']
|
42
|
+
|
43
|
+
found_mrs << [title, url]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
print_table(headers, mrs, alignments: [:left, :left])
|
48
|
+
output.puts "Found #{mrs.size} open #{@search} MRs"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -8,13 +8,22 @@ module Dri
|
|
8
8
|
module Commands
|
9
9
|
class Fetch
|
10
10
|
class Testcases < Dri::Command
|
11
|
-
|
12
11
|
def initialize(options)
|
13
12
|
@options = options
|
14
|
-
@available_pipelines = %w
|
13
|
+
@available_pipelines = %w[
|
14
|
+
main
|
15
|
+
canary
|
16
|
+
master
|
17
|
+
nightly
|
18
|
+
production
|
19
|
+
staging-canary
|
20
|
+
staging-orchestrated
|
21
|
+
staging-ref
|
22
|
+
staging
|
23
|
+
]
|
15
24
|
end
|
16
25
|
|
17
|
-
def execute(input: $stdin, output: $stdout)
|
26
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
18
27
|
verify_config_exists
|
19
28
|
|
20
29
|
if @options[:filter_pipelines]
|
@@ -31,18 +40,20 @@ module Dri
|
|
31
40
|
|
32
41
|
pipelines = @options[:filter_pipelines] ? filtered_pipelines : @available_pipelines
|
33
42
|
|
43
|
+
logger.error "No pipelines selected to continue to fetch testcases." if pipelines.empty?
|
44
|
+
|
34
45
|
pipelines.each do |pipeline|
|
35
46
|
logger.info "Fetching failing testcases in #{pipeline}\n"
|
36
47
|
response = api_client.fetch_failing_testcases(pipeline, state: 'opened')
|
37
|
-
|
48
|
+
|
38
49
|
output.puts "♦♦♦♦♦ #{add_color(pipeline, :black, :on_white)}♦♦♦♦♦\n\n"
|
39
50
|
|
40
51
|
response.each do |pipeline|
|
41
|
-
output.puts "#{title_label} #{pipeline[
|
52
|
+
output.puts "#{title_label} #{pipeline['title']}\n#{url_label} #{pipeline['web_url']}"
|
42
53
|
output.puts "#{divider}\n"
|
43
|
-
end
|
54
|
+
end
|
44
55
|
end
|
45
|
-
|
56
|
+
|
46
57
|
spinner.stop
|
47
58
|
end
|
48
59
|
end
|
@@ -1,26 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../../command'
|
2
|
-
|
4
|
+
require_relative '../../utils/table'
|
3
5
|
|
4
6
|
module Dri
|
5
7
|
module Commands
|
6
8
|
class Fetch
|
7
9
|
class Triaged < Dri::Command
|
10
|
+
include Dri::Utils::Table
|
11
|
+
using Refinements
|
12
|
+
|
8
13
|
def initialize(options)
|
9
14
|
@options = options
|
10
15
|
end
|
11
16
|
|
12
|
-
def execute(input: $stdin, output: $stdout)
|
17
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
13
18
|
verify_config_exists
|
14
19
|
|
15
|
-
title = add_color('Title', :
|
16
|
-
url = add_color('URL', :
|
17
|
-
type_label = add_color('Type', :
|
20
|
+
title = add_color('Title', :magenta)
|
21
|
+
url = add_color('URL', :magenta)
|
22
|
+
type_label = add_color('Type', :magenta)
|
18
23
|
|
19
|
-
table_labels = [
|
24
|
+
table_labels = [title, url, type_label]
|
20
25
|
failures_triaged = []
|
21
26
|
|
22
27
|
logger.info "Fetching your triaged failures..."
|
23
|
-
spinner.start
|
28
|
+
spinner.start
|
24
29
|
|
25
30
|
response = api_client.fetch_triaged_failures(emoji: emoji, state: 'opened')
|
26
31
|
|
@@ -30,7 +35,7 @@ module Dri
|
|
30
35
|
end
|
31
36
|
|
32
37
|
response.each do |triaged|
|
33
|
-
title =
|
38
|
+
title = triaged["title"].truncate(70)
|
34
39
|
url = triaged["web_url"]
|
35
40
|
labels = triaged["labels"]
|
36
41
|
type = ""
|
@@ -39,21 +44,12 @@ module Dri
|
|
39
44
|
type = label.gsub!('failure::', ' ').to_s if label.include? "failure::"
|
40
45
|
end
|
41
46
|
|
42
|
-
labels = triaged["labels"]
|
43
|
-
|
44
47
|
failures_triaged << [title, url, type]
|
45
48
|
end
|
46
49
|
|
47
50
|
spinner.stop
|
48
51
|
|
49
|
-
|
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
|
52
|
+
print_table(table_labels, failures_triaged)
|
57
53
|
end
|
58
54
|
end
|
59
55
|
end
|
data/lib/dri/commands/fetch.rb
CHANGED
@@ -7,6 +7,18 @@ module Dri
|
|
7
7
|
class Fetch < Thor
|
8
8
|
namespace :fetch
|
9
9
|
|
10
|
+
desc 'featureflags', 'Display feature flag changes for today'
|
11
|
+
method_option :help, aliases: '-h', type: :boolean,
|
12
|
+
desc: 'Display usage information'
|
13
|
+
def featureflags(*)
|
14
|
+
if options[:help]
|
15
|
+
invoke :help, ['featureflags']
|
16
|
+
else
|
17
|
+
require_relative 'fetch/featureflags'
|
18
|
+
Dri::Commands::Fetch::FeatureFlags.new(options).execute
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
10
22
|
desc 'triaged', 'Command description...'
|
11
23
|
method_option :help, aliases: '-h', type: :boolean,
|
12
24
|
desc: 'Display usage information'
|
@@ -23,7 +35,7 @@ module Dri
|
|
23
35
|
method_option :help, aliases: '-h', type: :boolean,
|
24
36
|
desc: 'Display usage information'
|
25
37
|
method_option :filter_pipelines, type: :boolean,
|
26
|
-
|
38
|
+
desc: 'Filter by pipeline'
|
27
39
|
def testcases(*)
|
28
40
|
if options[:help]
|
29
41
|
invoke :help, ['testcases']
|
@@ -37,7 +49,7 @@ module Dri
|
|
37
49
|
method_option :help, aliases: '-h', type: :boolean,
|
38
50
|
desc: 'Display usage information'
|
39
51
|
method_option :urgent, type: :boolean,
|
40
|
-
|
52
|
+
desc: 'Shows failures that quickly escalated'
|
41
53
|
def failures(*)
|
42
54
|
if options[:help]
|
43
55
|
invoke :help, ['failures']
|
@@ -46,6 +58,28 @@ module Dri
|
|
46
58
|
Dri::Commands::Fetch::Failures.new(options).execute
|
47
59
|
end
|
48
60
|
end
|
61
|
+
|
62
|
+
desc 'quarantines', 'Display open quarantine MRs'
|
63
|
+
method_option :help, aliases: '-h', type: :boolean,
|
64
|
+
desc: 'Display usage information'
|
65
|
+
def quarantines(*)
|
66
|
+
if options[:help]
|
67
|
+
invoke :help, ['quarantines']
|
68
|
+
else
|
69
|
+
require_relative 'fetch/quarantines'
|
70
|
+
Dri::Commands::Fetch::Quarantines.new(options, search: '[QUARANTINE]').execute
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
desc 'dequarantines', 'Display open dequarantine MRs'
|
75
|
+
method_option :help, aliases: '-h', type: :boolean,
|
76
|
+
desc: 'Display usage information'
|
77
|
+
def dequarantines(*)
|
78
|
+
return invoke :help, %w[quarantines] if options[:help]
|
79
|
+
|
80
|
+
require_relative 'fetch/quarantines'
|
81
|
+
Dri::Commands::Fetch::Quarantines.new(options, search: '[DEQUARANTINE]').execute
|
82
|
+
end
|
49
83
|
end
|
50
84
|
end
|
51
85
|
end
|
data/lib/dri/commands/init.rb
CHANGED
@@ -3,17 +3,18 @@
|
|
3
3
|
require_relative '../command'
|
4
4
|
|
5
5
|
require "tty-font"
|
6
|
-
require "pastel"
|
7
6
|
|
8
7
|
module Dri
|
9
8
|
module Commands
|
10
9
|
class Init < Dri::Command
|
11
10
|
def initialize(options)
|
12
|
-
|
11
|
+
@options = options
|
12
|
+
|
13
|
+
font = TTY::Font.new(:doom)
|
13
14
|
puts pastel.yellow(font.write("DRI"))
|
14
15
|
end
|
15
16
|
|
16
|
-
def execute(input: $stdin, output: $stdout)
|
17
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
17
18
|
output.puts "🤖 Welcome to DRI 🤖\n"
|
18
19
|
|
19
20
|
logger.info "🔎 Scanning for existing configurations...\n"
|
@@ -21,14 +22,16 @@ module Dri
|
|
21
22
|
if config.exist?
|
22
23
|
overwrite = prompt.yes?("There is already a configuration initialized. Would you like to overwrite it?")
|
23
24
|
unless overwrite
|
24
|
-
output.puts
|
25
|
+
output.puts(
|
26
|
+
"Using existing configuration. To view configuration in use try #{add_color('dri profile', :yellow)}."
|
27
|
+
)
|
25
28
|
exit 0
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
32
|
@username = prompt.ask("What is your GitLab username?")
|
30
33
|
@token = prompt.mask("Please provide your GitLab personal access token:")
|
31
|
-
@timezone = prompt.select("Choose your current timezone?", %w
|
34
|
+
@timezone = prompt.select("Choose your current timezone?", %w[EMEA AMER APAC])
|
32
35
|
@emoji = prompt.ask("Have a triage emoji?")
|
33
36
|
|
34
37
|
if (@emoji || @token || @username).nil?
|
@@ -42,7 +45,7 @@ module Dri
|
|
42
45
|
config.set(:settings, :emoji, value: @emoji)
|
43
46
|
config.write(force: true)
|
44
47
|
|
45
|
-
logger.success "✅ We're ready to go 🚀"
|
48
|
+
logger.success "✅ We're ready to go 🚀"
|
46
49
|
end
|
47
50
|
end
|
48
51
|
end
|
data/lib/dri/commands/profile.rb
CHANGED
@@ -20,10 +20,15 @@ module Dri
|
|
20
20
|
logger.info "🔎 Looking for profiles...\n"
|
21
21
|
|
22
22
|
if config.exist?
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
frame_args = {
|
24
|
+
width: 30,
|
25
|
+
height: 10,
|
26
|
+
align: :center,
|
27
|
+
padding: 1,
|
28
|
+
border: :thick,
|
29
|
+
title: { top_left: add_color('PROFILE:', :bright_cyan) }
|
30
|
+
}
|
31
|
+
output.print TTY::Box.frame(**frame_args) { pretty_print_profile.strip }
|
27
32
|
output.puts "☝️ To modify this profile try passing #{add_color('dri profile --edit', :yellow)}.\n"
|
28
33
|
else
|
29
34
|
logger.error "Oops.. Profile not found. Try creating one using #{add_color('dri init', :yellow)}."
|
@@ -31,7 +36,11 @@ module Dri
|
|
31
36
|
end
|
32
37
|
|
33
38
|
def pretty_print_profile
|
34
|
-
|
39
|
+
<<~PROFILE
|
40
|
+
#{add_color('User:', :bright_cyan)} #{username}\n #{add_color('Token:', :bright_cyan)} #{token}
|
41
|
+
#{add_color('Timezone:', :bright_cyan)} #{timezone}
|
42
|
+
#{add_color('Emoji:', :bright_cyan)} #{emoji}
|
43
|
+
PROFILE
|
35
44
|
end
|
36
45
|
end
|
37
46
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../../command'
|
2
4
|
require_relative '../../utils/markdown_lists'
|
3
5
|
require_relative "../../report"
|
@@ -17,14 +19,14 @@ module Dri
|
|
17
19
|
@time = Time.now.to_i
|
18
20
|
end
|
19
21
|
|
20
|
-
def execute(input: $stdin, output: $stdout)
|
22
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
21
23
|
verify_config_exists
|
22
24
|
report = Dri::Report.new(config)
|
23
25
|
|
24
26
|
logger.info "Fetching triaged failures with award emoji #{emoji}..."
|
25
27
|
|
26
28
|
spinner.start
|
27
|
-
issues = api_client.fetch_triaged_failures(emoji: emoji, state: 'opened')
|
29
|
+
issues = api_client.fetch_triaged_failures(emoji: emoji, state: 'opened')
|
28
30
|
spinner.stop
|
29
31
|
|
30
32
|
if issues.empty?
|
@@ -33,7 +35,7 @@ module Dri
|
|
33
35
|
end
|
34
36
|
|
35
37
|
logger.info "Assembling the report... "
|
36
|
-
# sets each failure on the table
|
38
|
+
# sets each failure on the table
|
37
39
|
action_options = ["pinged SET", "reproduced", "transient", "quarantined"]
|
38
40
|
|
39
41
|
spinner.start
|
@@ -41,17 +43,27 @@ module Dri
|
|
41
43
|
actions = []
|
42
44
|
|
43
45
|
if @options[:actions]
|
44
|
-
actions = prompt.multi_select(
|
46
|
+
actions = prompt.multi_select(
|
47
|
+
"Please mark the actions on #{add_color(issue['title'], :yellow)}: ",
|
48
|
+
action_options
|
49
|
+
)
|
45
50
|
end
|
51
|
+
|
46
52
|
report.add_failure(issue, actions)
|
47
53
|
end
|
48
54
|
|
49
55
|
if @options[:format] == 'list'
|
50
56
|
# generates markdown list with failures
|
51
57
|
format_style = Utils::MarkdownLists.make_list(report.labels, report.failures) unless report.failures.empty?
|
52
|
-
else
|
58
|
+
else
|
53
59
|
# generates markdown table with rows as failures
|
54
|
-
|
60
|
+
unless report.failures.empty?
|
61
|
+
format_style = MarkdownTables.make_table(
|
62
|
+
report.labels,
|
63
|
+
report.failures,
|
64
|
+
is_rows: true, align: %w[l l l l l]
|
65
|
+
)
|
66
|
+
end
|
55
67
|
end
|
56
68
|
|
57
69
|
report.set_header(timezone, username)
|
@@ -71,7 +83,7 @@ module Dri
|
|
71
83
|
File.open(report_path, 'a') do |out_file|
|
72
84
|
out_file.puts note
|
73
85
|
end
|
74
|
-
|
86
|
+
|
75
87
|
spinner.stop
|
76
88
|
|
77
89
|
output.puts "Done! ✅\n"
|
@@ -82,10 +94,13 @@ module Dri
|
|
82
94
|
# sends note to the weekly triage report
|
83
95
|
issues = api_client.fetch_current_triage_issue
|
84
96
|
current_issue_iid = issues[0]["iid"]
|
85
|
-
|
97
|
+
|
98
|
+
api_client.post_triage_report_note(iid: current_issue_iid, body: note)
|
86
99
|
|
87
100
|
output.puts "Done! ✅\n"
|
88
|
-
logger.success
|
101
|
+
logger.success(<<~MSG)
|
102
|
+
Thanks @#{username}, your report was posted at https://gitlab.com/gitlab-org/quality/pipeline-triage/-/issues/#{current_issue_iid} 🎉
|
103
|
+
MSG
|
89
104
|
end
|
90
105
|
end
|
91
106
|
end
|
data/lib/dri/commands/publish.rb
CHANGED
@@ -5,16 +5,15 @@ require 'thor'
|
|
5
5
|
module Dri
|
6
6
|
module Commands
|
7
7
|
class Publish < Thor
|
8
|
-
|
9
8
|
namespace :publish
|
10
9
|
|
11
10
|
desc 'report', 'Generate a report'
|
12
11
|
method_option :dry_run, type: :boolean,
|
13
|
-
|
14
|
-
method_option :format, aliases: '-f', type: :string, :
|
15
|
-
|
12
|
+
desc: 'Generates a report locally'
|
13
|
+
method_option :format, aliases: '-f', type: :string, default: "table",
|
14
|
+
desc: 'Formats the report'
|
16
15
|
method_option :actions, type: :boolean,
|
17
|
-
|
16
|
+
desc: 'Updates actions on failures'
|
18
17
|
def report(*)
|
19
18
|
if options[:help]
|
20
19
|
invoke :help, ['report']
|
@@ -10,9 +10,9 @@ module Dri
|
|
10
10
|
@options = options
|
11
11
|
end
|
12
12
|
|
13
|
-
def execute(input: $stdin, output: $stdout)
|
13
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
14
14
|
verify_config_exists
|
15
|
-
|
15
|
+
|
16
16
|
remove = prompt.yes? "Are you sure you want to remove all #{emoji} award emojis from issues?"
|
17
17
|
|
18
18
|
unless remove
|
@@ -29,7 +29,7 @@ module Dri
|
|
29
29
|
spinner.stop
|
30
30
|
|
31
31
|
issues_with_award_emoji.each do |issue|
|
32
|
-
logger.info "Removing #{emoji} from #{issue[
|
32
|
+
logger.info "Removing #{emoji} from #{issue['web_url']}..."
|
33
33
|
|
34
34
|
award_emoji_url = issue["_links"]["award_emoji"]
|
35
35
|
|
@@ -37,8 +37,8 @@ module Dri
|
|
37
37
|
|
38
38
|
emoji_found = response.find { |e| e['name'] == emoji && e['user']['username'] == username }
|
39
39
|
|
40
|
-
|
41
|
-
url = "#{award_emoji_url}/#{emoji_found[
|
40
|
+
unless emoji_found.nil?
|
41
|
+
url = "#{award_emoji_url}/#{emoji_found['id']}"
|
42
42
|
api_client.delete_award_emoji(url)
|
43
43
|
end
|
44
44
|
end
|