dri 0.10.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab/changelog_config.yml +13 -0
- data/.gitlab/merge_request_templates/Default.md +27 -0
- data/.gitlab/merge_request_templates/Release.md +8 -23
- data/.gitlab-ci.yml +6 -4
- data/.rubocop.yml +9 -1
- data/.ruby-version +1 -1
- data/.tool-versions +1 -1
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile.lock +58 -32
- data/README.md +88 -113
- data/dri.gemspec +9 -4
- data/exe/dri +2 -1
- data/faq.yaml +7 -7
- data/lefthook.yml +24 -0
- data/lib/dri/api_client.rb +66 -25
- data/lib/dri/cli.rb +2 -11
- data/lib/dri/command.rb +21 -52
- data/lib/dri/commands/add/fast_quarantine.rb +72 -0
- data/lib/dri/commands/add.rb +45 -0
- data/lib/dri/commands/analyze/stack_traces.rb +1 -4
- data/lib/dri/commands/analyze.rb +0 -1
- data/lib/dri/commands/faq.rb +1 -2
- data/lib/dri/commands/fetch/failures.rb +102 -43
- data/lib/dri/commands/fetch/{featureflags.rb → feature_flags.rb} +1 -6
- data/lib/dri/commands/fetch/pipelines.rb +3 -7
- data/lib/dri/commands/fetch/runbooks.rb +1 -3
- data/lib/dri/commands/fetch/testcases.rb +1 -3
- data/lib/dri/commands/fetch/triaged.rb +2 -6
- data/lib/dri/commands/fetch.rb +0 -30
- data/lib/dri/commands/incidents.rb +2 -6
- data/lib/dri/commands/init.rb +1 -3
- data/lib/dri/commands/profile.rb +3 -5
- data/lib/dri/commands/publish/report.rb +24 -26
- data/lib/dri/commands/publish.rb +0 -1
- data/lib/dri/commands/rm/emoji.rb +1 -3
- data/lib/dri/commands/rm/profile.rb +1 -2
- data/lib/dri/commands/rm/reports.rb +1 -2
- data/lib/dri/commands/rm.rb +0 -3
- data/lib/dri/commands/view/fast_quarantine.rb +25 -0
- data/lib/dri/commands/view.rb +22 -0
- data/lib/dri/feature_flag_report.rb +1 -3
- data/lib/dri/refinements/gitlab.rb +22 -0
- data/lib/dri/refinements/string.rb +19 -0
- data/lib/dri/report.rb +13 -55
- data/lib/dri/support/configuration.rb +62 -0
- data/lib/dri/support/influxdb_tools.rb +37 -0
- data/lib/dri/utils/constants.rb +2 -1
- data/lib/dri/utils/helpers.rb +15 -0
- data/lib/dri/version.rb +1 -1
- data/lib/dri.rb +8 -1
- metadata +96 -16
- data/lib/dri/commands/fetch/quarantines.rb +0 -55
- data/lib/dri/gitlab/issues.rb +0 -19
- data/lib/dri/refinements/truncate.rb +0 -15
data/lib/dri/command.rb
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'command'
|
4
|
-
require_relative 'api_client'
|
5
|
-
require_relative 'gitlab/issues'
|
6
|
-
|
7
|
-
require 'dri/refinements/truncate'
|
8
|
-
|
9
|
-
require "tty-config"
|
10
3
|
require "pastel"
|
11
4
|
require 'forwardable'
|
12
5
|
|
13
6
|
module Dri
|
14
7
|
class Command
|
8
|
+
include Utils::Helpers
|
15
9
|
extend Forwardable
|
16
10
|
|
17
11
|
def_delegators :command, :run
|
12
|
+
def_delegators :configuration,
|
13
|
+
:profile,
|
14
|
+
:config,
|
15
|
+
:emoji,
|
16
|
+
:username,
|
17
|
+
:token,
|
18
|
+
:ops_token,
|
19
|
+
:timezone,
|
20
|
+
:tz,
|
21
|
+
:handover_report_path
|
18
22
|
|
19
23
|
def initialize(*options)
|
20
24
|
@options = options
|
@@ -24,50 +28,10 @@ module Dri
|
|
24
28
|
Pastel.new(**options)
|
25
29
|
end
|
26
30
|
|
27
|
-
# Main configuration
|
28
|
-
def config
|
29
|
-
@config ||= begin
|
30
|
-
config = TTY::Config.new
|
31
|
-
config.filename = ".dri_profile"
|
32
|
-
config.extname = ".yml"
|
33
|
-
config.append_path Dir.home
|
34
|
-
config.append_path Dir.pwd
|
35
|
-
config
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
31
|
def api_client(ops: false)
|
40
32
|
ApiClient.new(config, ops)
|
41
33
|
end
|
42
34
|
|
43
|
-
def profile
|
44
|
-
@profile ||= config.read
|
45
|
-
end
|
46
|
-
|
47
|
-
def emoji
|
48
|
-
@emoji ||= profile["settings"]["emoji"]
|
49
|
-
end
|
50
|
-
|
51
|
-
def username
|
52
|
-
@username ||= profile["settings"]["user"]
|
53
|
-
end
|
54
|
-
|
55
|
-
def token
|
56
|
-
@token ||= profile["settings"]["token"]
|
57
|
-
end
|
58
|
-
|
59
|
-
def ops_token
|
60
|
-
@ops_token ||= profile["settings"]["ops_token"]
|
61
|
-
end
|
62
|
-
|
63
|
-
def timezone
|
64
|
-
@timezone ||= profile["settings"]["timezone"]
|
65
|
-
end
|
66
|
-
|
67
|
-
def handover_report_path
|
68
|
-
@handover_report_path ||= profile["settings"]["handover_report_path"]
|
69
|
-
end
|
70
|
-
|
71
35
|
def verify_config_exists
|
72
36
|
return if config.exist?
|
73
37
|
|
@@ -79,6 +43,10 @@ module Dri
|
|
79
43
|
@options[:no_color] ? str : pastel.decorate(str, *color)
|
80
44
|
end
|
81
45
|
|
46
|
+
def bold(str)
|
47
|
+
pastel.bold(str)
|
48
|
+
end
|
49
|
+
|
82
50
|
# Execute this command
|
83
51
|
#
|
84
52
|
# @api public
|
@@ -89,11 +57,6 @@ module Dri
|
|
89
57
|
)
|
90
58
|
end
|
91
59
|
|
92
|
-
def logger
|
93
|
-
require 'tty-logger'
|
94
|
-
TTY::Logger.new
|
95
|
-
end
|
96
|
-
|
97
60
|
def spinner
|
98
61
|
require 'tty-spinner'
|
99
62
|
TTY::Spinner.new("[:spinner] ⏳", format: :classic)
|
@@ -138,5 +101,11 @@ module Dri
|
|
138
101
|
require 'tty-prompt'
|
139
102
|
TTY::Prompt.new(**options.merge(interrupt: :exit))
|
140
103
|
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def configuration
|
108
|
+
@configuration ||= Support::Configuration.new
|
109
|
+
end
|
141
110
|
end
|
142
111
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dri
|
4
|
+
module Commands
|
5
|
+
class Add
|
6
|
+
class FastQuarantine < Dri::Command
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(*) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
12
|
+
verify_config_exists
|
13
|
+
|
14
|
+
logger.info "Adding to fast quarantined tests..."
|
15
|
+
current_content = api_client.get_fast_quarantine_tests
|
16
|
+
current_content += "\n" unless current_content.end_with?("\n")
|
17
|
+
|
18
|
+
if @options[:failure_url]
|
19
|
+
failure_url = @options[:failure_url]
|
20
|
+
issue_id = extract_issue_id_from_url(failure_url)
|
21
|
+
|
22
|
+
issue_title = api_client.get_failure_issue_title(issue_id)
|
23
|
+
test_path = extract_file_path(issue_title)
|
24
|
+
|
25
|
+
full_path = "qa/specs/features/#{test_path}"
|
26
|
+
new_file_content = "#{current_content}#{full_path}\n"
|
27
|
+
|
28
|
+
new_branch = "fast-quarantine-failure-#{issue_id}"
|
29
|
+
|
30
|
+
merge_request = api_client.add_test_to_fast_quarantine(
|
31
|
+
failure_url,
|
32
|
+
new_branch,
|
33
|
+
test_path,
|
34
|
+
new_file_content
|
35
|
+
)
|
36
|
+
|
37
|
+
logger.info "Opened an MR to review at #{merge_request.web_url}"
|
38
|
+
|
39
|
+
api_client.add_note_failure_issue(issue_id, merge_request)
|
40
|
+
logger.success "Note added to failure issue with link to fastquarantine merge request"
|
41
|
+
elsif @options[:test_id]
|
42
|
+
test_id = @options[:test_id]
|
43
|
+
parsed_test_name = test_id.match(%r{([^/]+)_spec})[1]
|
44
|
+
new_branch = "fast-quarantine-failure-#{parsed_test_name.tr('_', '-')}"
|
45
|
+
|
46
|
+
new_file_content = "#{current_content}#{test_id}\n"
|
47
|
+
merge_request = api_client.add_test_to_fast_quarantine(
|
48
|
+
"N/A",
|
49
|
+
new_branch,
|
50
|
+
test_id,
|
51
|
+
new_file_content
|
52
|
+
)
|
53
|
+
|
54
|
+
logger.info "Opened an MR to review at #{merge_request.web_url}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def extract_issue_id_from_url(url)
|
61
|
+
match = url.match(%r{/issues/(\d+)$})
|
62
|
+
match ? match[1].to_i : nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def extract_file_path(title)
|
66
|
+
match = title.match(/Failure in (.*?\.rb)/)
|
67
|
+
match ? match[1] : nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module Dri
|
6
|
+
module Commands
|
7
|
+
class Add < Thor
|
8
|
+
namespace :add
|
9
|
+
# rubocop:disable Layout/LineLength
|
10
|
+
full_description = <<-DESC
|
11
|
+
Creates a fast-quarantine merge request
|
12
|
+
|
13
|
+
Examples:#{' '}
|
14
|
+
dri add fastquarantine -f https://gitlab.com/gitlab-org/gitlab/-/issues/431736 # using failure issue
|
15
|
+
dri add fastquarantine -t qa/specs/features/ee/api/14_model_ops/code_suggestions_spec.rb # using test file
|
16
|
+
dri add fastquarantine -t ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb:42 # using test file and line number
|
17
|
+
dri add fastquarantine -t "spec/tasks/gitlab/usage_data_rake_spec.rb[1:5:2:1]" # using test id
|
18
|
+
DESC
|
19
|
+
desc 'fastquarantine', full_description
|
20
|
+
method_option :failure_url, aliases: '-f', type: :string,
|
21
|
+
desc: 'Failure URL, for example: https://gitlab.com/gitlab-org/gitlab/-/issues/431736'
|
22
|
+
method_option :test_id, aliases: '-t', type: :string,
|
23
|
+
desc: 'Test path, for example: qa/specs/features/ee/api/14_model_ops/code_suggestions_spec.rb'
|
24
|
+
method_option :help, aliases: '-h', type: :boolean,
|
25
|
+
desc: 'Display usage information'
|
26
|
+
# rubocop:enable Layout/LineLength
|
27
|
+
def fastquarantine(*)
|
28
|
+
if options[:help]
|
29
|
+
invoke :help, ['fastquarantine']
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
if options[:failure_url].nil? && options[:test_id].nil?
|
34
|
+
say 'Validation error: either failure_url or test_id is required.', :red
|
35
|
+
return
|
36
|
+
elsif options[:failure_url] && options[:test_id]
|
37
|
+
say 'Validation error: only one of failure_url or test_id should be provided, not both.', :red
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
Dri::Commands::Add::FastQuarantine.new(options).execute
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../command'
|
4
|
-
require_relative '../../utils/table'
|
5
|
-
require_relative '../../utils/constants'
|
6
3
|
require 'amatch'
|
7
4
|
require 'fileutils'
|
8
5
|
|
@@ -20,7 +17,7 @@ module Dri
|
|
20
17
|
@similarity_score_threshold = options[:similarity_score_threshold] || 0.9
|
21
18
|
end
|
22
19
|
|
23
|
-
def execute(
|
20
|
+
def execute(_input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
24
21
|
verify_config_exists
|
25
22
|
logger.info "#{Time.now.utc} Fetching issues"
|
26
23
|
|
data/lib/dri/commands/analyze.rb
CHANGED
data/lib/dri/commands/faq.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../command'
|
4
3
|
require 'tty-prompt'
|
5
4
|
require 'launchy'
|
6
5
|
|
@@ -9,7 +8,7 @@ module Dri
|
|
9
8
|
class FAQ < Dri::Command
|
10
9
|
ExitCommand = Class.new(StandardError)
|
11
10
|
|
12
|
-
def execute(
|
11
|
+
def execute(*)
|
13
12
|
root_dir = File.expand_path('../../..', __dir__)
|
14
13
|
faq_file = File.join(root_dir, 'faq.yaml')
|
15
14
|
faq_data = YAML.load_file(faq_file)
|
@@ -1,66 +1,67 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative '../../utils/table'
|
5
|
-
require_relative '../../utils/constants'
|
3
|
+
require "influxdb-client"
|
6
4
|
|
7
5
|
module Dri
|
8
6
|
module Commands
|
9
7
|
class Fetch
|
10
|
-
class Failures < Dri::Command
|
8
|
+
class Failures < Dri::Command # rubocop:disable Metrics/ClassLength
|
11
9
|
include Dri::Utils::Table
|
12
10
|
include Dri::Utils::Constants::Triage::Labels
|
13
|
-
|
11
|
+
include Dri::Support::InfluxdbTools
|
12
|
+
using Refinements::String
|
14
13
|
|
15
14
|
def initialize(options)
|
16
15
|
@options = options
|
17
|
-
@
|
18
|
-
@end_date = @options[:end_date] ? Date.parse(@options[:end_date]) : Date.today
|
19
|
-
@cutoff_time = @options[:cutoff] ? Time.parse(options[:cutoff]).utc : nil
|
16
|
+
@cutoff_time = @options[:cutoff] ? Time.parse(options[:cutoff]) : nil
|
20
17
|
end
|
21
18
|
|
22
|
-
def execute(
|
19
|
+
def execute(_input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
23
20
|
verify_config_exists
|
24
21
|
|
25
|
-
urgent_environments = %w[canary canary.staging]
|
26
|
-
|
27
22
|
title = add_color('Title', :bright_yellow)
|
28
23
|
triaged = add_color('Triaged?', :bright_yellow)
|
29
24
|
environment = add_color('Environment', :bright_yellow)
|
30
|
-
author = add_color('Author', :bright_yellow)
|
31
25
|
url = add_color('URL', :bright_yellow)
|
32
26
|
updated_at = add_color('Updated at', :bright_yellow)
|
33
27
|
|
34
28
|
sorted_failures = []
|
35
|
-
labels = { title: title, triaged: triaged, environment: environment,
|
29
|
+
labels = { title: title, triaged: triaged, environment: environment, url: url,
|
36
30
|
updated_at: updated_at }
|
37
31
|
triaged_counter = 0
|
38
32
|
|
39
|
-
|
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)..."
|
33
|
+
logger.info "Fetching failures from '#{start_date}' to '#{end_date}'..."
|
51
34
|
|
52
35
|
spinner.run do # rubocop:disable Metrics/BlockLength
|
53
|
-
failures = api_client.fetch_all_new_failures(start_date:
|
36
|
+
failures = api_client.fetch_all_new_failures(start_date: start_date, end_date: end_date, state: 'opened')
|
54
37
|
|
55
38
|
if failures.empty?
|
56
|
-
logger.info "Life is great, there are no new failures between #{
|
39
|
+
logger.info "Life is great, there are no new failures between #{start_date} and #{end_date}!"
|
57
40
|
exit 0
|
58
41
|
end
|
59
42
|
|
43
|
+
blocker_set = Set.new
|
44
|
+
|
45
|
+
if query_api
|
46
|
+
begin
|
47
|
+
blockers = query_api.query(query: query_reliables_smokes)
|
48
|
+
|
49
|
+
blockers.each do |table|
|
50
|
+
table.records.each do |record|
|
51
|
+
blocker_set.add(record.values['name'])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue StandardError => e
|
55
|
+
logger.error "An error occurred querying for reliable and smoke failures: #{e.message}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
60
59
|
failures.each do |failure|
|
61
60
|
project_id = failure.project_id
|
62
61
|
title = failure.title.truncate(60)
|
63
|
-
|
62
|
+
|
63
|
+
title = bold("*#{failure.title.truncate(60)}*") if blocker?(failure.title, blocker_set)
|
64
|
+
|
64
65
|
url = failure.web_url
|
65
66
|
updated_at = failure.updated_at
|
66
67
|
triaged = add_color('x', :red)
|
@@ -69,9 +70,6 @@ module Dri
|
|
69
70
|
|
70
71
|
env == 'gitlab.com' ? 'production' : env
|
71
72
|
end
|
72
|
-
urgent = urgent_environments.all? { |env| envs.include?(env) }
|
73
|
-
|
74
|
-
next if @options[:urgent] && !urgent
|
75
73
|
|
76
74
|
emoji_awards = api_client.fetch_awarded_emojis(failure.iid, project_id: project_id).find do |e|
|
77
75
|
e.name == emoji && e.to_h.dig('user', 'username') == username
|
@@ -82,33 +80,94 @@ module Dri
|
|
82
80
|
triaged_counter += 1
|
83
81
|
end
|
84
82
|
|
85
|
-
sorted_failures << { title: title, triaged: triaged, environment: envs.first || 'none',
|
83
|
+
sorted_failures << { title: title, triaged: triaged, environment: envs.first || 'none',
|
86
84
|
url: url, updated_at: updated_at }
|
87
85
|
end
|
88
86
|
|
89
87
|
sorted_failures.sort_by! { |failure| failure[@options[:sort_by]&.to_sym || :environment] }
|
90
88
|
end
|
91
89
|
|
92
|
-
msg =
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
else
|
97
|
-
<<~MSG
|
98
|
-
Found: #{sorted_failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
|
99
|
-
MSG
|
100
|
-
end
|
90
|
+
msg = <<~MSG
|
91
|
+
Found: #{sorted_failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
|
92
|
+
Smoke and Reliable failures are marked with *Failure..* in bold.
|
93
|
+
MSG
|
101
94
|
|
102
95
|
terminal_width = TTY::Screen.width
|
103
96
|
|
104
|
-
if terminal_width <= 210
|
97
|
+
if terminal_width <= 210
|
105
98
|
labels.delete(:updated_at)
|
106
99
|
sorted_failures.map { |failure| failure.delete(:updated_at) }
|
107
100
|
end
|
108
101
|
|
109
|
-
print_table(
|
102
|
+
print_table(
|
103
|
+
labels.values,
|
104
|
+
sorted_failures.map(&:values),
|
105
|
+
alignments: [:left, :center, :center, :left]
|
106
|
+
)
|
110
107
|
output.puts(msg)
|
111
108
|
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def start_date
|
113
|
+
return @start_date if @start_date
|
114
|
+
|
115
|
+
parsed_start_date = @options[:start_date] ? Date.parse(@options[:start_date]) : tz.now
|
116
|
+
@start_date = date_with_time(parsed_start_date, @cutoff_time&.hour, @cutoff_time&.min, 0,
|
117
|
+
@options[:start_date] ? "+00:00" : tz.canonical_zone)
|
118
|
+
end
|
119
|
+
|
120
|
+
def end_date
|
121
|
+
return @end_date if @end_date
|
122
|
+
|
123
|
+
parsed_end_date = @options[:end_date] ? Date.parse(@options[:end_date]) : tz.now
|
124
|
+
@end_date = date_with_time(parsed_end_date, 23, 59, 59,
|
125
|
+
@options[:end_date] ? "+00:00" : tz.canonical_zone)
|
126
|
+
end
|
127
|
+
|
128
|
+
def date_with_time(date, hour, min, seconds, tz_identifier)
|
129
|
+
Time.new(date.year, date.month, date.day, hour || 0, min || 0, seconds || 0, tz_identifier)
|
130
|
+
end
|
131
|
+
|
132
|
+
def blocker?(title, set)
|
133
|
+
title_part = title.split('|').last
|
134
|
+
return true if title_part&.strip && set.include?(title_part.strip)
|
135
|
+
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def query_reliables_smokes
|
140
|
+
<<~QUERY
|
141
|
+
from(bucket: "#{Support::InfluxdbTools::INFLUX_MAIN_TEST_METRICS_BUCKET}")
|
142
|
+
|> range(start: -1d)
|
143
|
+
|> filter(fn: (r) => r._measurement == "test-stats")
|
144
|
+
|> filter(fn: (r) => r.run_type == "staging-full" or
|
145
|
+
r.run_type == "staging-sanity" or
|
146
|
+
r.run_type == "production-full" or
|
147
|
+
r.run_type == "production-sanity" or
|
148
|
+
r.run_type == "package-and-qa" or
|
149
|
+
r.run_type == "nightly" or
|
150
|
+
r.run_type == "e2e-test-on-gdk"
|
151
|
+
)
|
152
|
+
|> filter(fn: (r) => r.job_name != "airgapped" and
|
153
|
+
r.job_name != "instance-image-slow-network" and
|
154
|
+
r.job_name != "nplus1-instance-image"
|
155
|
+
)
|
156
|
+
|> filter(fn: (r) => r.status != "pending" and
|
157
|
+
r.merge_request == "false" and
|
158
|
+
r.quarantined == "false" and
|
159
|
+
r.smoke == "true" or
|
160
|
+
r.reliable == "true"
|
161
|
+
)
|
162
|
+
|> filter(fn: (r) => r["_field"] == "job_url" or
|
163
|
+
r["_field"] == "failure_exception" or
|
164
|
+
r["_field"] == "id"
|
165
|
+
)
|
166
|
+
|> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
|
167
|
+
|> group(columns: ["name"])
|
168
|
+
|> distinct(column: "name")
|
169
|
+
QUERY
|
170
|
+
end
|
112
171
|
end
|
113
172
|
end
|
114
173
|
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../command'
|
4
|
-
require_relative '../../utils/table'
|
5
|
-
require_relative '../../utils/constants'
|
6
|
-
require_relative '../../feature_flag_report'
|
7
|
-
|
8
3
|
module Dri
|
9
4
|
module Commands
|
10
5
|
class Fetch
|
@@ -17,7 +12,7 @@ module Dri
|
|
17
12
|
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
18
13
|
end
|
19
14
|
|
20
|
-
def execute(
|
15
|
+
def execute(_input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
21
16
|
verify_config_exists
|
22
17
|
|
23
18
|
summary = add_color('Summary', :bright_yellow)
|
@@ -1,9 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'date'
|
4
|
-
require_relative '../../command'
|
5
|
-
require_relative '../../utils/table'
|
6
|
-
require_relative '../../utils/constants'
|
7
4
|
|
8
5
|
module Dri
|
9
6
|
module Commands
|
@@ -11,7 +8,6 @@ module Dri
|
|
11
8
|
class Pipelines < Dri::Command # rubocop:disable Metrics/ClassLength
|
12
9
|
include Dri::Utils::Table
|
13
10
|
include Dri::Utils::Constants
|
14
|
-
using Refinements
|
15
11
|
|
16
12
|
NUM_OF_TESTS_LIVE_ENV = 1000
|
17
13
|
NOT_FOUND = "Not found"
|
@@ -20,7 +16,7 @@ module Dri
|
|
20
16
|
@options = options
|
21
17
|
end
|
22
18
|
|
23
|
-
def execute(
|
19
|
+
def execute(*)
|
24
20
|
verify_config_exists
|
25
21
|
logger.info "Fetching pipelines' status, this might take a while..."
|
26
22
|
logger.warn "This command needs a large window to correctly print the table"
|
@@ -149,8 +145,8 @@ module Dri
|
|
149
145
|
# @param [Integer] pipeline_id
|
150
146
|
# @param [Boolean] sanity
|
151
147
|
def allure_report(pipeline_name:, pipeline_id:, sanity:)
|
152
|
-
"https://storage.googleapis.com/gitlab-qa-allure-reports/#{allure_bucket_name(pipeline_name, sanity)}"\
|
153
|
-
|
148
|
+
"https://storage.googleapis.com/gitlab-qa-allure-reports/#{allure_bucket_name(pipeline_name, sanity)}" \
|
149
|
+
"/master/#{pipeline_id}/index.html"
|
154
150
|
end
|
155
151
|
|
156
152
|
# Returns the GCP bucket name for different pipeline types
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../command'
|
4
|
-
require_relative '../../utils/constants'
|
5
3
|
require 'tty-markdown'
|
6
4
|
require 'tty-prompt'
|
7
5
|
require 'base64'
|
@@ -14,7 +12,7 @@ module Dri
|
|
14
12
|
@options = options
|
15
13
|
end
|
16
14
|
|
17
|
-
def execute(folder: nil,
|
15
|
+
def execute(folder: nil, _input: $stdin, output: $stdout)
|
18
16
|
return fetch_summary(output: output) unless folder
|
19
17
|
|
20
18
|
fetch_runbook("#{folder}/index.md", output: output)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../command'
|
4
|
-
|
5
3
|
require 'pastel'
|
6
4
|
|
7
5
|
module Dri
|
@@ -21,7 +19,7 @@ module Dri
|
|
21
19
|
]
|
22
20
|
end
|
23
21
|
|
24
|
-
def execute(
|
22
|
+
def execute(_input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize
|
25
23
|
verify_config_exists
|
26
24
|
|
27
25
|
if @options[:filter_pipelines]
|
@@ -1,22 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../command'
|
4
|
-
require_relative '../../utils/table'
|
5
|
-
require_relative '../../utils/constants'
|
6
|
-
|
7
3
|
module Dri
|
8
4
|
module Commands
|
9
5
|
class Fetch
|
10
6
|
class Triaged < Dri::Command
|
11
7
|
include Dri::Utils::Table
|
12
8
|
include Dri::Utils::Constants::Triage::Labels
|
13
|
-
using Refinements
|
9
|
+
using Refinements::String
|
14
10
|
|
15
11
|
def initialize(options)
|
16
12
|
@options = options
|
17
13
|
end
|
18
14
|
|
19
|
-
def execute(
|
15
|
+
def execute(*) # rubocop:disable Metrics/AbcSize
|
20
16
|
verify_config_exists
|
21
17
|
|
22
18
|
title = add_color('Title', :magenta)
|