dri 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -0
- data/lib/dri/command.rb +1 -1
- data/lib/dri/commands/fetch/featureflags.rb +12 -36
- data/lib/dri/commands/publish/report.rb +91 -17
- data/lib/dri/commands/publish.rb +2 -0
- data/lib/dri/feature_flag_report.rb +47 -0
- data/lib/dri/utils/feature_flag_consts.rb +13 -0
- data/lib/dri/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 879c4292254a2a17a0ebcd8e2c0a3f8bbc6e654a69c153ad66423c71eb750fc4
|
4
|
+
data.tar.gz: 51f8e1acec1894ce4a6ab264ef690cf063259f46512d743609bf2f5a6529132f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad020b17eb8d05322800332e59b5d286dcb8712df055dab50be7f234df2864a5ba719f900d61b0ba25308a1ea130fa2b586b7f01215beec90eafb614cc8c6da1
|
7
|
+
data.tar.gz: c0ef20575dcc1f9fa3312df5970b79a8b6fa11b8401a1a80d30561c8a764c7bcd140d4e649c619fbce1be6b9f71c943fb51aa5a48c20b18c5f480af4a821bc07
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -145,6 +145,7 @@ $ dri publish report --format=list # formats the report in a list
|
|
145
145
|
$ dri publish report --format=table # formats the report in a table (default)
|
146
146
|
$ dri publish report --dry-run # the report is only generated locally
|
147
147
|
$ dri publish report --actions # activate the actions prompt for each failure
|
148
|
+
$ dri publish report --feature-flags # includes a summary of the feature flag changes on each environment
|
148
149
|
```
|
149
150
|
|
150
151
|
**Note:** These options above can be combined like:
|
data/lib/dri/command.rb
CHANGED
@@ -2,34 +2,29 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/table'
|
5
|
+
require_relative '../../utils/feature_flag_consts'
|
6
|
+
require_relative '../../feature_flag_report'
|
5
7
|
|
6
8
|
module Dri
|
7
9
|
module Commands
|
8
10
|
class Fetch
|
9
11
|
class FeatureFlags < Dri::Command
|
10
12
|
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'
|
13
|
+
include Dri::Utils::FeatureFlagConsts
|
16
14
|
|
17
15
|
def initialize(options)
|
18
16
|
@options = options
|
19
17
|
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
20
18
|
end
|
21
19
|
|
22
|
-
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
20
|
+
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
23
21
|
verify_config_exists
|
24
22
|
|
25
23
|
summary = add_color('Summary', :bright_yellow)
|
26
24
|
changed_on = add_color('Changed(UTC)', :bright_yellow)
|
27
25
|
url = add_color('URL', :bright_yellow)
|
28
26
|
|
29
|
-
|
30
|
-
staging_feature_flags = []
|
31
|
-
staging_ref_feature_flags = []
|
32
|
-
preprod_feature_flags = []
|
27
|
+
report = Dri::FeatureFlagReport.new
|
33
28
|
|
34
29
|
headers = [summary, changed_on, url]
|
35
30
|
|
@@ -37,42 +32,23 @@ module Dri
|
|
37
32
|
|
38
33
|
spinner.run do
|
39
34
|
response = api_client.fetch_feature_flag_logs(@today_iso_format)
|
35
|
+
|
40
36
|
if response.empty?
|
41
37
|
logger.info 'It\'s been quiet...no feature flag changes for today 👀'
|
42
38
|
break
|
43
39
|
end
|
44
40
|
|
45
41
|
response.each do |feature_flag|
|
46
|
-
|
47
|
-
|
48
|
-
substrings = ["set to \"true\"", "set to \"false\""]
|
49
|
-
next unless substrings.any? { |substr| summary.include?(substr) }
|
50
|
-
|
51
|
-
changed_on = feature_flag.description[/(?<=Changed on \(in UTC\): ).+?(?=\n)/].delete('`')
|
52
|
-
url = feature_flag.web_url
|
53
|
-
|
54
|
-
feature_flag_data = [summary, changed_on, url]
|
55
|
-
|
56
|
-
labels = feature_flag.labels
|
57
|
-
host_label = labels.select { |label| /^host::/.match(label) }.join('')
|
42
|
+
next unless TITLE_SUBSTRINGS.any? { |substr| feature_flag.title.include?(substr) }
|
58
43
|
|
59
|
-
|
60
|
-
when PRODUCTION
|
61
|
-
prod_feature_flags << feature_flag_data
|
62
|
-
when STAGING
|
63
|
-
staging_feature_flags << feature_flag_data
|
64
|
-
when STAGING_REF
|
65
|
-
staging_ref_feature_flags << feature_flag_data
|
66
|
-
when PREPROD
|
67
|
-
preprod_feature_flags << feature_flag_data
|
68
|
-
end
|
44
|
+
report.add_change(feature_flag)
|
69
45
|
end
|
70
46
|
end
|
71
47
|
|
72
|
-
print_results('Production', headers,
|
73
|
-
print_results('Staging', headers,
|
74
|
-
print_results('Staging Ref', headers,
|
75
|
-
print_results('Preprod', headers,
|
48
|
+
print_results('Production', headers, report.prod, output) unless report.prod.empty?
|
49
|
+
print_results('Staging', headers, report.staging, output) unless report.staging.empty?
|
50
|
+
print_results('Staging Ref', headers, report.staging_ref, output) unless report.staging_ref.empty?
|
51
|
+
print_results('Preprod', headers, report.preprod, output) unless report.preprod.empty?
|
76
52
|
end
|
77
53
|
|
78
54
|
private
|
@@ -2,21 +2,26 @@
|
|
2
2
|
|
3
3
|
require_relative '../../command'
|
4
4
|
require_relative '../../utils/markdown_lists'
|
5
|
-
require_relative
|
5
|
+
require_relative '../../utils/feature_flag_consts'
|
6
|
+
require_relative '../../report'
|
7
|
+
require_relative '../../feature_flag_report'
|
6
8
|
|
7
9
|
require 'markdown-tables'
|
8
10
|
require 'fileutils'
|
9
|
-
require
|
11
|
+
require 'uri'
|
10
12
|
|
11
13
|
module Dri
|
12
14
|
module Commands
|
13
15
|
class Publish
|
14
|
-
class Report < Dri::Command
|
16
|
+
class Report < Dri::Command # rubocop:disable Metrics/ClassLength
|
17
|
+
include Dri::Utils::FeatureFlagConsts
|
18
|
+
|
15
19
|
def initialize(options)
|
16
20
|
@options = options
|
17
21
|
|
18
22
|
@date = Date.today
|
19
23
|
@time = Time.now.to_i
|
24
|
+
@today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
|
20
25
|
end
|
21
26
|
|
22
27
|
def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
@@ -26,7 +31,9 @@ module Dri
|
|
26
31
|
logger.info "Fetching triaged failures with award emoji #{emoji}..."
|
27
32
|
|
28
33
|
spinner.start
|
34
|
+
|
29
35
|
issues = api_client.fetch_triaged_failures(emoji: emoji, state: 'opened')
|
36
|
+
|
30
37
|
spinner.stop
|
31
38
|
|
32
39
|
if issues.empty?
|
@@ -34,27 +41,28 @@ module Dri
|
|
34
41
|
exit 1
|
35
42
|
end
|
36
43
|
|
37
|
-
logger.info
|
44
|
+
logger.info 'Assembling the failures report... '
|
38
45
|
# sets each failure on the table
|
39
46
|
action_options = [
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
'pinged SET',
|
48
|
+
'reproduced',
|
49
|
+
'transient',
|
50
|
+
'quarantined',
|
51
|
+
'active investigation',
|
52
|
+
'blocking pipelines',
|
53
|
+
'awaiting for a fix to merge',
|
54
|
+
'notified the team',
|
55
|
+
'due to feature flag'
|
49
56
|
]
|
50
57
|
|
51
58
|
spinner.start
|
59
|
+
|
52
60
|
issues.each do |issue|
|
53
61
|
actions = []
|
54
62
|
|
55
63
|
if @options[:actions]
|
56
64
|
actions = prompt.multi_select(
|
57
|
-
"Please mark the actions on #{add_color(issue
|
65
|
+
"Please mark the actions on #{add_color(issue.title, :yellow)}: ",
|
58
66
|
action_options,
|
59
67
|
per_page: 9
|
60
68
|
)
|
@@ -77,14 +85,59 @@ module Dri
|
|
77
85
|
end
|
78
86
|
end
|
79
87
|
|
88
|
+
spinner.stop
|
89
|
+
|
90
|
+
if @options[:feature_flags]
|
91
|
+
logger.info 'Fetching today\'s feature flag changes...'
|
92
|
+
|
93
|
+
feature_flag_report = Dri::FeatureFlagReport.new
|
94
|
+
|
95
|
+
spinner.start
|
96
|
+
|
97
|
+
feature_flags = api_client.fetch_feature_flag_logs(@today_iso_format)
|
98
|
+
|
99
|
+
feature_flags.each do |feature_flag|
|
100
|
+
next unless TITLE_SUBSTRINGS.any? { |substr| feature_flag.title.include?(substr) }
|
101
|
+
|
102
|
+
feature_flag_report.add_change(feature_flag)
|
103
|
+
end
|
104
|
+
|
105
|
+
spinner.stop
|
106
|
+
|
107
|
+
logger.info 'Assembling the feature flags report...'
|
108
|
+
|
109
|
+
spinner.start
|
110
|
+
|
111
|
+
feature_flag_note = "\n\n## Feature Flag Changes"
|
112
|
+
feature_flag_changes = ''
|
113
|
+
|
114
|
+
format_type = @options[:format] == 'list' ? :list : :table
|
115
|
+
|
116
|
+
feature_flag_report.get_all_flag_changes.each do |env, changes|
|
117
|
+
next if changes.empty?
|
118
|
+
|
119
|
+
feature_flag_changes += format_feature_flag_changes(
|
120
|
+
env, changes, feature_flag_report.labels, format_type
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
feature_flag_note += if feature_flag_changes.empty?
|
125
|
+
"\n\nNo changes found today"
|
126
|
+
else
|
127
|
+
"\n\n<details><summary>Click to expand</summary>#{feature_flag_changes}</details>"
|
128
|
+
end
|
129
|
+
|
130
|
+
spinner.stop
|
131
|
+
end
|
132
|
+
|
80
133
|
report.set_header(timezone, username)
|
81
134
|
note = "#{report.header}\n\n#{format_style}"
|
82
135
|
|
83
|
-
|
136
|
+
note += feature_flag_note if @options[:feature_flags]
|
84
137
|
|
85
138
|
# creates an .md file with the report locally in /handover_reports
|
86
139
|
if @options[:dry_run]
|
87
|
-
logger.info
|
140
|
+
logger.info 'Downloading the report... '
|
88
141
|
|
89
142
|
spinner.start
|
90
143
|
|
@@ -104,7 +157,7 @@ module Dri
|
|
104
157
|
|
105
158
|
# sends note to the weekly triage report
|
106
159
|
issues = api_client.fetch_current_triage_issue
|
107
|
-
current_issue_iid = issues
|
160
|
+
current_issue_iid = issues.first.iid
|
108
161
|
|
109
162
|
api_client.post_triage_report_note(iid: current_issue_iid, body: note)
|
110
163
|
|
@@ -113,6 +166,27 @@ module Dri
|
|
113
166
|
Thanks @#{username}, your report was posted at https://gitlab.com/gitlab-org/quality/pipeline-triage/-/issues/#{current_issue_iid} 🎉
|
114
167
|
MSG
|
115
168
|
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def format_feature_flag_changes(env, changes, labels, format_type)
|
173
|
+
unless format_type == :table || format_type == :list
|
174
|
+
raise ArgumentError, 'format_type must be one of type :table or :list'
|
175
|
+
end
|
176
|
+
|
177
|
+
case format_type
|
178
|
+
when :list
|
179
|
+
formatted_changes = Utils::MarkdownLists.make_list(labels, changes)
|
180
|
+
when :table
|
181
|
+
formatted_changes = MarkdownTables.make_table(
|
182
|
+
labels,
|
183
|
+
changes,
|
184
|
+
is_rows: true, align: %w[l l l]
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
"\n\n### #{env.to_s.capitalize.tr('_', ' ')}\n\n#{formatted_changes}"
|
189
|
+
end
|
116
190
|
end
|
117
191
|
end
|
118
192
|
end
|
data/lib/dri/commands/publish.rb
CHANGED
@@ -14,6 +14,8 @@ module Dri
|
|
14
14
|
desc: 'Formats the report'
|
15
15
|
method_option :actions, type: :boolean,
|
16
16
|
desc: 'Updates actions on failures'
|
17
|
+
method_option :feature_flags, type: :boolean,
|
18
|
+
desc: 'Adds summary of feature flag changes'
|
17
19
|
def report(*)
|
18
20
|
if options[:help]
|
19
21
|
invoke :help, ['report']
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './utils/feature_flag_consts'
|
4
|
+
|
5
|
+
module Dri
|
6
|
+
class FeatureFlagReport
|
7
|
+
include Dri::Utils::FeatureFlagConsts
|
8
|
+
|
9
|
+
attr_reader :header, :labels, :prod, :staging, :staging_ref, :preprod
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@header = '## Feature Flag Changes'
|
13
|
+
@labels = %w[Summary Changed(UTC) URL]
|
14
|
+
@prod = []
|
15
|
+
@staging = []
|
16
|
+
@staging_ref = []
|
17
|
+
@preprod = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_change(feature_flag)
|
21
|
+
summary = feature_flag.title
|
22
|
+
|
23
|
+
changed_on = feature_flag.description[/(?<=Changed on \(in UTC\): ).+?(?=\n)/].delete('`')
|
24
|
+
url = feature_flag.web_url
|
25
|
+
|
26
|
+
feature_flag_data = [summary, changed_on, url]
|
27
|
+
|
28
|
+
labels = feature_flag.labels
|
29
|
+
host_label = labels.select { |label| /^host::/.match(label) }.join('')
|
30
|
+
|
31
|
+
case host_label
|
32
|
+
when PRODUCTION
|
33
|
+
@prod << feature_flag_data
|
34
|
+
when STAGING
|
35
|
+
@staging << feature_flag_data
|
36
|
+
when STAGING_REF
|
37
|
+
@staging_ref << feature_flag_data
|
38
|
+
when PREPROD
|
39
|
+
@preprod << feature_flag_data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_all_flag_changes
|
44
|
+
{ production: @prod, staging: @staging, staging_ref: @staging_ref, preprod: @preprod }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dri
|
4
|
+
module Utils
|
5
|
+
module FeatureFlagConsts
|
6
|
+
PRODUCTION = 'host::gitlab.com'
|
7
|
+
STAGING = 'host::staging.gitlab.com'
|
8
|
+
STAGING_REF = 'host::staging-ref.gitlab.com'
|
9
|
+
PREPROD = 'host::pre.gitlab.com'
|
10
|
+
TITLE_SUBSTRINGS = ["set to \"true\"", "set to \"false\""].freeze
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/dri/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.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
|
+
date: 2022-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gitlab
|
@@ -333,10 +333,12 @@ files:
|
|
333
333
|
- lib/dri/commands/rm/emoji.rb
|
334
334
|
- lib/dri/commands/rm/profile.rb
|
335
335
|
- lib/dri/commands/rm/reports.rb
|
336
|
+
- lib/dri/feature_flag_report.rb
|
336
337
|
- lib/dri/gitlab/issues.rb
|
337
338
|
- lib/dri/refinements/truncate.rb
|
338
339
|
- lib/dri/report.rb
|
339
340
|
- lib/dri/templates/incidents/.gitkeep
|
341
|
+
- lib/dri/utils/feature_flag_consts.rb
|
340
342
|
- lib/dri/utils/markdown_lists.rb
|
341
343
|
- lib/dri/utils/table.rb
|
342
344
|
- lib/dri/version.rb
|