dri 0.1.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1c589c770547e0142cb5b2942316e41af19cad293ed2e141d95e54a7379f741
4
- data.tar.gz: b1cc881757273745c40485c469b34abb642a8edcda18ae1baf22bfe80ed8bacd
3
+ metadata.gz: 3ae68ce5f20bab397121604708b813e8f488316559f82392a389f1750e57c89c
4
+ data.tar.gz: 30b16b0291beb7e18cc74acb9c54100c869544bba883c79729f577c8bda5dd7f
5
5
  SHA512:
6
- metadata.gz: 0fa73e3af14a31bcf96f919c1b37465695a52a7db5d0fcaedf8ee36e51c817bf4c789c3fe24bc2169de0b385b83d0ec92ae716f8da6fbb55cb134c6219a0b26a
7
- data.tar.gz: 880ae4a81c350dcfe7b49c9db00c3760d7f98b56383b7516d0c890dae24034fc3d8ebb86f37592c8d65655c3cbe8671bddf3c26327d49a6006b0e9f5f0313afa
6
+ metadata.gz: ad35cf45172de050ecd86c376527abc98ba535f9ad97f54f84f7be3875882c46ae897039d26a4c9f4db3c7df598608c81e8613518b7c7eeb44b7903610899406
7
+ data.tar.gz: a790667c5528fc3ad94f610b2add55b36a4fb5efd9bad3e8e10a78d44e58a8140721d4717a75def60ca829715389bebf001704a38a1a8127e1e6872228dd0fe6
data/.gitlab-ci.yml CHANGED
@@ -1,9 +1,10 @@
1
1
  .job_base:
2
- image: ruby:3.1
2
+ image: ruby:2.7
3
3
  variables:
4
4
  BUNDLE_PATH: vendor/bundle
5
5
  BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES: "true"
6
6
  before_script:
7
+ - gem install bundler -v 2.3.9 --no-document
7
8
  - bundle install
8
9
  cache:
9
10
  key:
@@ -33,8 +34,14 @@ build_gem:
33
34
  script:
34
35
  - gem build
35
36
 
37
+ rubocop:
38
+ stage: test
39
+ extends: .job_base
40
+ script:
41
+ - bundle exec rubocop --color
42
+
36
43
  rspec:
37
44
  stage: test
38
45
  extends: .job_base
39
46
  script:
40
- - bundle exec rspec
47
+ - bundle exec rspec --color
data/.rubocop.yml ADDED
@@ -0,0 +1,53 @@
1
+ inherit_gem:
2
+ gitlab-styles:
3
+ - rubocop-all.yml
4
+ - rubocop-gemspec.yml
5
+ - rubocop-lint.yml
6
+ - rubocop-naming.yml
7
+ - rubocop-performance.yml
8
+ - rubocop-rspec.yml
9
+ - rubocop-security.yml
10
+ - rubocop-style.yml
11
+
12
+ AllCops:
13
+ TargetRubyVersion: 2.7
14
+
15
+ RSpec/MultipleMemoizedHelpers:
16
+ Max: 25
17
+ AllowSubject: true
18
+
19
+ CodeReuse/ActiveRecord:
20
+ Exclude:
21
+ - spec/**/*.rb
22
+
23
+ Metrics/AbcSize:
24
+ Enabled: true
25
+ Max: 30
26
+
27
+ Metrics/BlockLength:
28
+ Enabled: true
29
+ Exclude:
30
+ - spec/**/*.rb
31
+ - dri.gemspec
32
+
33
+ Metrics/MethodLength:
34
+ Enabled: true
35
+ Max: 30
36
+
37
+ Layout/BeginEndAlignment:
38
+ Enabled: true
39
+
40
+ Layout/EmptyLinesAroundAttributeAccessor:
41
+ Enabled: true
42
+
43
+ Layout/SpaceAroundMethodCallOperator:
44
+ Enabled: true
45
+
46
+ Lint/HashCompareByIdentity:
47
+ Enabled: true
48
+
49
+ Lint/RedundantSafeNavigation:
50
+ Enabled: true
51
+
52
+ Style/ClassEqualityComparison:
53
+ Enabled: true
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.5
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in dri.gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dri (0.1.2)
4
+ dri (0.1.3)
5
5
  httparty (~> 0.20.0)
6
6
  json (~> 2.6.1)
7
7
  markdown-tables (~> 1.1.1)
@@ -19,39 +19,88 @@ PATH
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
+ activesupport (7.0.2.3)
23
+ concurrent-ruby (~> 1.0, >= 1.0.2)
24
+ i18n (>= 1.6, < 2)
25
+ minitest (>= 5.1)
26
+ tzinfo (~> 2.0)
22
27
  addressable (2.8.0)
23
28
  public_suffix (>= 2.0.2, < 5.0)
29
+ ast (2.4.2)
30
+ concurrent-ruby (1.1.10)
24
31
  crack (0.4.5)
25
32
  rexml
26
33
  diff-lcs (1.5.0)
34
+ gitlab-styles (7.0.0)
35
+ rubocop (~> 0.91, >= 0.91.1)
36
+ rubocop-gitlab-security (~> 0.1.1)
37
+ rubocop-graphql (~> 0.10)
38
+ rubocop-performance (~> 1.9.2)
39
+ rubocop-rails (~> 2.9)
40
+ rubocop-rspec (~> 1.44)
27
41
  hashdiff (1.0.1)
28
42
  httparty (0.20.0)
29
43
  mime-types (~> 3.0)
30
44
  multi_xml (>= 0.5.2)
45
+ i18n (1.10.0)
46
+ concurrent-ruby (~> 1.0)
31
47
  json (2.6.1)
32
48
  markdown-tables (1.1.1)
33
49
  mime-types (3.4.1)
34
50
  mime-types-data (~> 3.2015)
35
51
  mime-types-data (3.2022.0105)
52
+ minitest (5.15.0)
36
53
  multi_xml (0.6.0)
54
+ parallel (1.22.1)
55
+ parser (3.1.1.0)
56
+ ast (~> 2.4.1)
37
57
  pastel (0.8.0)
38
58
  tty-color (~> 0.5)
39
59
  public_suffix (4.0.6)
40
- rake (12.3.3)
60
+ rack (2.2.3)
61
+ rainbow (3.1.1)
62
+ rake (13.0.6)
63
+ regexp_parser (2.2.1)
41
64
  rexml (3.2.5)
42
65
  rspec (3.10.0)
43
66
  rspec-core (~> 3.10.0)
44
67
  rspec-expectations (~> 3.10.0)
45
68
  rspec-mocks (~> 3.10.0)
46
- rspec-core (3.10.1)
69
+ rspec-core (3.10.2)
47
70
  rspec-support (~> 3.10.0)
48
- rspec-expectations (3.10.1)
71
+ rspec-expectations (3.10.2)
49
72
  diff-lcs (>= 1.2.0, < 2.0)
50
73
  rspec-support (~> 3.10.0)
51
- rspec-mocks (3.10.2)
74
+ rspec-mocks (3.10.3)
52
75
  diff-lcs (>= 1.2.0, < 2.0)
53
76
  rspec-support (~> 3.10.0)
54
- rspec-support (3.10.2)
77
+ rspec-support (3.10.3)
78
+ rubocop (0.93.1)
79
+ parallel (~> 1.10)
80
+ parser (>= 2.7.1.5)
81
+ rainbow (>= 2.2.2, < 4.0)
82
+ regexp_parser (>= 1.8)
83
+ rexml
84
+ rubocop-ast (>= 0.6.0)
85
+ ruby-progressbar (~> 1.7)
86
+ unicode-display_width (>= 1.4.0, < 2.0)
87
+ rubocop-ast (1.16.0)
88
+ parser (>= 3.1.1.0)
89
+ rubocop-gitlab-security (0.1.1)
90
+ rubocop (>= 0.51)
91
+ rubocop-graphql (0.14.2)
92
+ rubocop (>= 0.87, < 2)
93
+ rubocop-performance (1.9.2)
94
+ rubocop (>= 0.90.0, < 2.0)
95
+ rubocop-ast (>= 0.4.0)
96
+ rubocop-rails (2.9.1)
97
+ activesupport (>= 4.2.0)
98
+ rack (>= 1.1)
99
+ rubocop (>= 0.90.0, < 2.0)
100
+ rubocop-rspec (1.44.1)
101
+ rubocop (~> 0.87)
102
+ rubocop-ast (>= 0.7.1)
103
+ ruby-progressbar (1.11.0)
55
104
  strings (0.2.1)
56
105
  strings-ansi (~> 0.2)
57
106
  unicode-display_width (>= 1.5, < 3.0)
@@ -85,7 +134,9 @@ GEM
85
134
  pastel (~> 0.8)
86
135
  strings (~> 0.2.0)
87
136
  tty-screen (~> 0.8)
88
- unicode-display_width (2.1.0)
137
+ tzinfo (2.0.4)
138
+ concurrent-ruby (~> 1.0)
139
+ unicode-display_width (1.8.0)
89
140
  unicode_utils (1.4.0)
90
141
  webmock (3.14.0)
91
142
  addressable (>= 2.8.0)
@@ -98,6 +149,7 @@ PLATFORMS
98
149
 
99
150
  DEPENDENCIES
100
151
  dri!
152
+ gitlab-styles (~> 7.0.0)
101
153
  rake
102
154
  rspec (~> 3.10.0)
103
155
  timecop (~> 0.9.1)
data/README.md CHANGED
@@ -56,6 +56,9 @@ $ dri profile
56
56
  - failures
57
57
  - testcases
58
58
  - triaged
59
+ - quarantines
60
+ - dequarantines
61
+ - featureflags
59
62
  - [4. publish](#4-publish)
60
63
  - report
61
64
  - [5. rm](#5-rm)
@@ -107,6 +110,25 @@ $ dri fetch triaged
107
110
 
108
111
  Fetches triaged failures which use the triage emoji specified in `dri profile`.
109
112
 
113
+ ```shell
114
+ $ dri fetch quarantines
115
+ ```
116
+
117
+ Fetches open quarantine Merge Requests to be reviewed
118
+
119
+ ```shell
120
+ $ dri fetch dequarantines
121
+ ```
122
+
123
+ Fetches open dequarantine Merge Requests to be reviewed
124
+
125
+ ```shell
126
+ $ dri fetch featureflags
127
+ ```
128
+
129
+ Fetches a list of today's feature flag changes, including the date and time in UTC of when the change occurred as well as a link to the corresponding issue from the feature-flag-log project.
130
+ Results are organized by environment (production, staging, staging ref and preprod).
131
+
110
132
  #### 4. publish
111
133
 
112
134
  ```shell
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "dri"
data/dri.gemspec CHANGED
@@ -1,41 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/dri/version'
2
4
 
3
5
  Gem::Specification.new do |spec|
4
- spec.name = "dri"
5
- spec.license = "MIT"
6
+ spec.name = 'dri'
7
+ spec.license = 'MIT'
6
8
  spec.version = Dri::VERSION
7
- spec.authors = ["GitLab Quality"]
8
- spec.email = ["quality+dri@gitlab.com"]
9
+ spec.authors = ['GitLab Quality']
10
+ spec.email = ['quality+dri@gitlab.com']
9
11
 
10
- spec.summary = %q{CLI app to help triage GitLab QA pipelines}
12
+ spec.summary = 'CLI app to help triage GitLab QA pipelines'
11
13
  spec.homepage = 'https://gitlab.com/gitlab-org/quality/dri'
12
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
13
15
 
14
16
  # Specify which files should be added to the gem when it is released.
15
17
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
17
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
20
  end
19
- spec.bindir = "exe"
21
+ spec.bindir = 'exe'
20
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
- spec.require_paths = ["lib"]
23
+ spec.require_paths = ['lib']
22
24
 
23
- spec.add_dependency "tty-config", "~> 0.4.0"
24
- spec.add_dependency "tty-font", "~> 0.5"
25
- spec.add_dependency "tty-prompt", "~> 0.23.1"
26
- spec.add_dependency "tty-spinner", "~> 0.9"
27
- spec.add_dependency "tty-table", "~> 0.12.0"
25
+ spec.add_dependency 'httparty', '~> 0.20.0'
26
+ spec.add_dependency 'json', '~> 2.6.1'
27
+ spec.add_dependency 'markdown-tables', '~> 1.1.1'
28
+ spec.add_dependency 'pastel', '~> 0.8.0'
29
+ spec.add_dependency 'thor', '~> 1.0.1'
28
30
  spec.add_dependency 'tty-box', '~> 0.7.0'
31
+ spec.add_dependency 'tty-config', '~> 0.4.0'
32
+ spec.add_dependency 'tty-editor', '~> 0.6'
33
+ spec.add_dependency 'tty-font', '~> 0.5'
29
34
  spec.add_dependency 'tty-logger', '~> 0.6.0'
30
- spec.add_dependency "tty-editor", "~> 0.6"
31
- spec.add_dependency "pastel", "~> 0.8.0"
32
- spec.add_dependency "thor", "~> 1.0.1"
33
- spec.add_dependency "markdown-tables", "~> 1.1.1"
34
- spec.add_dependency 'json', '~> 2.6.1'
35
- spec.add_dependency 'httparty', '~> 0.20.0'
35
+ spec.add_dependency 'tty-prompt', '~> 0.23.1'
36
+ spec.add_dependency 'tty-spinner', '~> 0.9'
37
+ spec.add_dependency 'tty-table', '~> 0.12.0'
36
38
 
37
- spec.add_development_dependency "rake"
39
+ spec.add_development_dependency 'gitlab-styles', '~> 7.0.0'
40
+ spec.add_development_dependency 'rake'
38
41
  spec.add_development_dependency 'rspec', '~> 3.10.0'
39
- spec.add_development_dependency 'webmock', '~> 3.5'
40
42
  spec.add_development_dependency "timecop", "~> 0.9.1"
43
+ spec.add_development_dependency 'webmock', '~> 3.5'
41
44
  end
data/exe/dri CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  lib_path = File.expand_path('../lib', __dir__)
5
- $:.unshift(lib_path) if !$:.include?(lib_path)
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
6
  require 'dri/cli'
7
7
 
8
8
  Signal.trap('INT') do
@@ -12,7 +12,7 @@ end
12
12
 
13
13
  begin
14
14
  Dri::CLI.start
15
- rescue Dri::CLI::Error => err
16
- puts "ERROR: #{err.message}"
15
+ rescue Dri::CLI::Error => e
16
+ puts "ERROR: #{e.message}"
17
17
  exit 1
18
18
  end
@@ -6,12 +6,12 @@ require "tty-config"
6
6
  require 'cgi'
7
7
 
8
8
  module Dri
9
- class ApiClient
10
-
11
- API_URL = 'https://gitlab.com/api/v4'
12
- TESTCASES_PROJECT_ID = '11229385'
13
- TRIAGE_PROJECT_ID = '15291320'
14
- GITLAB_PROJECT_ID = '278964'
9
+ class ApiClient # rubocop:disable Metrics/ClassLength
10
+ API_URL = 'https://gitlab.com/api/v4'
11
+ TESTCASES_PROJECT_ID = '11229385'
12
+ TRIAGE_PROJECT_ID = '15291320'
13
+ GITLAB_PROJECT_ID = '278964'
14
+ FEATURE_FLAG_LOG_PROJECT_ID = '15208716'
15
15
 
16
16
  def initialize(config)
17
17
  profile = config.read
@@ -64,7 +64,9 @@ module Dri
64
64
  def fetch_mrs(project_id:, **options)
65
65
  uri = URI(API_URL)
66
66
  uri.query = HTTParty::HashConversions.to_params(options)
67
- uri.path = File.join(uri.path, 'projects', CGI.escape(project_id), 'merge_requests') # CGI.escape('gitlab-org/gitlab') => 'gitlab-org%2Fgitlab'
67
+
68
+ # CGI.escape('gitlab-org/gitlab') => 'gitlab-org%2Fgitlab'
69
+ uri.path = File.join(uri.path, 'projects', CGI.escape(project_id), 'merge_requests')
68
70
 
69
71
  fetch_json(uri.to_s)
70
72
  end
@@ -106,6 +108,16 @@ module Dri
106
108
  delete_json(url)
107
109
  end
108
110
 
111
+ def fetch_feature_flag_logs(date:, page:)
112
+ url = ["#{API_URL}/projects/"]
113
+ url << "#{FEATURE_FLAG_LOG_PROJECT_ID}/issues"
114
+ url << "?created_after=#{date}"
115
+ url << "&per_page=100"
116
+ url << "&page=#{page}"
117
+
118
+ fetch_json(url.join)
119
+ end
120
+
109
121
  private
110
122
 
111
123
  def post_json(url, body)
@@ -116,7 +128,7 @@ module Dri
116
128
  }
117
129
  }
118
130
 
119
- response = HTTParty.post(url, options)
131
+ response = HTTParty.post(url, options)
120
132
  handle_response(response)
121
133
  end
122
134
 
@@ -126,12 +138,12 @@ module Dri
126
138
  end
127
139
 
128
140
  def handle_response(response)
129
- #puts response.to_json
141
+ # puts response.to_json
130
142
  response
131
143
  end
132
144
 
133
145
  def fetch_json(url)
134
- response = HTTParty.get(url, headers: header)
146
+ response = HTTParty.get(url, headers: header)
135
147
 
136
148
  if response.code != 200
137
149
  puts "Response error code \"#{response.code}\" - Unable to sync with GitLab"
data/lib/dri/cli.rb CHANGED
@@ -25,14 +25,14 @@ module Dri
25
25
  end
26
26
 
27
27
  class_option :no_color, type: :boolean, default: false,
28
- desc: "Disable colorization in output"
28
+ desc: "Disable colorization in output"
29
29
 
30
30
  desc 'version', 'dri version'
31
31
  def version
32
32
  require_relative 'version'
33
33
  puts "v#{Dri::VERSION}"
34
34
  end
35
- map %w(--version -v) => :version
35
+ map %w[--version -v] => :version
36
36
 
37
37
  require_relative 'commands/rm'
38
38
  register Dri::Commands::Rm, 'rm', 'rm [SUBCOMMAND]', 'Remove triage-related items'
data/lib/dri/command.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'command'
3
4
  require_relative 'api_client'
4
5
 
@@ -13,7 +14,6 @@ module Dri
13
14
  extend Forwardable
14
15
 
15
16
  def_delegators :command, :run
16
- attr_reader :config, :emoji, :token, :username, :timezone, :profile
17
17
 
18
18
  def pastel(**options)
19
19
  Pastel.new(**options)
@@ -56,10 +56,10 @@ module Dri
56
56
  end
57
57
 
58
58
  def verify_config_exists
59
- if !config.exist?
60
- logger.error "Oops, could not find a configuration. Try using #{add_color('dri init', :yellow)} first."
61
- exit 1
62
- end
59
+ return if config.exist?
60
+
61
+ logger.error "Oops, could not find a configuration. Try using #{add_color('dri init', :yellow)} first."
62
+ exit 1
63
63
  end
64
64
 
65
65
  def add_color(str, *color)
@@ -1,13 +1,13 @@
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
11
  using Refinements
12
12
 
13
13
  def initialize(options)
@@ -15,7 +15,7 @@ module Dri
15
15
  @today_iso_format = Time.now.strftime('%Y-%m-%dT00:00:00Z')
16
16
  end
17
17
 
18
- def execute(input: $stdin, output: $stdout)
18
+ def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
19
19
  verify_config_exists
20
20
 
21
21
  title = add_color('Title', :bright_yellow)
@@ -25,13 +25,12 @@ module Dri
25
25
 
26
26
  failures = []
27
27
  urgent = []
28
- labels = [ title, triaged, author, url ]
28
+ labels = [title, triaged, author, url]
29
29
  triaged_counter = 0
30
30
 
31
31
  logger.info "Fetching today's failures..."
32
32
 
33
- spinner.run do
34
-
33
+ spinner.run do # rubocop:disable Metrics/BlockLength
35
34
  response = api_client.fetch_failures(date: @today_iso_format, state: 'opened')
36
35
 
37
36
  if response.nil?
@@ -47,7 +46,7 @@ module Dri
47
46
  triaged = add_color('x', :red)
48
47
 
49
48
  emoji_awards = api_client.fetch_awarded_emojis(award_emoji_url).find do |e|
50
- e['name'] == emoji && e['user']['username'] == username
49
+ (e['name'] == emoji) && (e['user']['username'] == username)
51
50
  end
52
51
 
53
52
  if emoji_awards
@@ -59,7 +58,7 @@ module Dri
59
58
  labels = failure['labels']
60
59
 
61
60
  labels.each do |label|
62
- if label.include? ('found:canary.gitlab.com' && 'found:canary.staging.gitlab.com')
61
+ if label.include?('found:canary.gitlab.com' && 'found:canary.staging.gitlab.com')
63
62
  urgent << [title, triaged, author, url]
64
63
  end
65
64
  end
@@ -70,13 +69,15 @@ module Dri
70
69
  end
71
70
 
72
71
  if @options[:urgent]
73
- table = TTY::Table.new(labels, urgent)
74
- puts table.render(:ascii, resize: true, alignments: [:center, :center, :center, :center])
75
- output.puts "\nFound: #{urgent.size} urgent failures, occurring in both canary.gitlab.com and canary.staging.gitlab.com."
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
76
76
  else
77
- table = TTY::Table.new(labels, failures)
78
- puts table.render(:ascii, resize: true, alignments: [:center, :center, :center, :center])
79
- output.puts "\nFound: #{failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}."
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
80
81
  end
81
82
  end
82
83
  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