dri 0.1.3 → 0.2.0

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: 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