reviewer 0.1.1 → 0.1.2

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: a5df0f3247eb105862f40b5092bb3c3b25fa20e87e155cb283fc2fd278933987
4
- data.tar.gz: 06716646a5f980c5d67f89abc4ab4938977c2dd2691101d8cdd924f4481599cf
3
+ metadata.gz: 64e0b63ddf470414a26b5903508646ace97b1b0ee6e2b0244e7233d9e6717652
4
+ data.tar.gz: 97b9d1d998959319791022b37f00fde7b6424411c728e98fb8109c352078088d
5
5
  SHA512:
6
- metadata.gz: 57ca3df253ec35a5544f9a2145733c535688f8be8f0ed6820973563f758563e08a6f3aa729e8743be49945d931cc63a27a21a75e4512d2f9855f1ecad055a9ac
7
- data.tar.gz: 5b06953f74f63aff8410b27470a37044d764b87b07289554d0ddc3581575d8a6849603a78f656d392273ac6e4d3d358acd91a84cae49a7d49fd427800536d5cb
6
+ metadata.gz: da483ff2104b138d463c1688731c3eb83ecb8778105af38efbe98f6c7597f9aa4a069341580a3fc7bb34833cf83119d64967a56398e0cea4f97ae7bebc2ae5f2
7
+ data.tar.gz: f9f1106bf11209abd1a5af2d3ad151413a1026cbe43a4a5db171414d335df7cae9c7ab8d922e661da0625240163d55906eccf9b8fe03a245869f97b00bc94ce8
@@ -10,7 +10,7 @@ jobs:
10
10
  - name: Set up Ruby
11
11
  uses: ruby/setup-ruby@v1
12
12
  with:
13
- ruby-version: 2.6.6
13
+ ruby-version: 2.7.3
14
14
  bundler-cache: true
15
15
  - name: Run the default task
16
16
  run: bundle exec rake
@@ -0,0 +1,47 @@
1
+ # Quick overview of the options configuration for command-line tools.
2
+ #
3
+ # <command_key>: // ex. 'rubocop', 'bundler-audit', etc.
4
+ # disabled: true // Optional. Tools are enabled by default
5
+ # name: // Optional. Will use the `command_key` if name isn't provided.
6
+ # description: // Optional. Serves as a handy reminder for the purpose of the command.
7
+ # tags: [ruby, dependencies] // Optional. Lets you run commands tagged with the same word.
8
+ # links:
9
+ # home: // Optional. A link to the home page for the tool.
10
+ # install: // Optional. A link to the installation instructions for the tool.
11
+ # ignore_syntax: // Optional. A link to the syntax for ignoring/disabling some rules for the tool.
12
+ # commands:
13
+ # install: // Optional. Command to run to install the tool.
14
+ # prepare: // Optional. Command to run prior to the review phase. ex. 'bundle exec bundle-audit update'
15
+ # review: // Required. The only truly required field because this is the whole point.
16
+ # format: // Optional. Command to auto-update rule violations when possible.
17
+ # quiet_option: // Optional, but strongly suggested. Helps keep output under control when running multiple tools.
18
+ # max_exit_status: // Optional, defaults to 0. Some tools like Yarn Audit essentially won't return less than a 3. This specifies the threshold that's still considered passing.
19
+ # env: // Optional. A way to specify necessary environment variables for the tools commands. The key is the variable name, and the value is, well, the value.
20
+ # example_one: value // - The names will automatically be capitalized, so you can freely use lower-case here.
21
+ # example_one: value // - Reviewer is smart enough to handle string values with spaces and automatically quote them.
22
+ # flags: // Optional. A way to specify flags *only for the review command*. The key is the flag name, and the value is, well, the value.
23
+ # example_one: value // - Reviewer is smart enough to handle single-letter (-f) and multi-letter (--format) flags.
24
+ # example_two: value // - It's highly-recommended to use the longer-name format for flags when possible to serve as self-documentation.
25
+
26
+ # This is an example for a YAML block for a command-line tool:
27
+ #
28
+ # tool-name-key:
29
+ # disabled: true
30
+ # name: Tool
31
+ # description: A tool that finds issues and fixes code.
32
+ # tags: [syntax, security]
33
+ # links:
34
+ # home: https://example.com
35
+ # install: https://example.com/install
36
+ # ignore_syntax: https://example.com/ignore
37
+ # commands:
38
+ # install: 'bundle install tool'
39
+ # prepare: 'bundle exec tool update'
40
+ # review: 'bundle exec tool'
41
+ # format: 'bundle exec tool --format'
42
+ # quiet_option: '--quiet'
43
+ # max_exit_status: 1
44
+ # env:
45
+ # report: false
46
+ # flags:
47
+ # format: json
data/.reviewer.yml ADDED
@@ -0,0 +1,36 @@
1
+ bundler_audit:
2
+ tags: [critical, dependencies, ruby]
3
+ name: Bundler Audit
4
+ description: Audit Gem Dependencies for Security Issues
5
+ links:
6
+ home: https://github.com/rubysec/bundler-audit
7
+ install: https://github.com/rubysec/bundler-audit#install
8
+ commands:
9
+ install: 'bundle exec gem install bundler-audit'
10
+ prepare: 'bundle exec bundle-audit update'
11
+ review: 'bundle exec bundle-audit check --no-update'
12
+ quiet_option: '--quiet'
13
+
14
+ tests:
15
+ name: Minitest
16
+ description: Unit Tests
17
+ tags: [ruby, tests]
18
+ links:
19
+ home:
20
+ commands:
21
+ review: "bundle exec rake TESTOPTS='--seed=$SEED'"
22
+ quiet_option: '--silent'
23
+
24
+ rubocop:
25
+ tags: [ruby, syntax]
26
+ description: Review Ruby syntax/formatting for consistency
27
+ links:
28
+ home: https://rubocop.org
29
+ install: https://docs.rubocop.org/rubocop/1.13/installation.html
30
+ ignore_syntax: https://docs.rubocop.org/rubocop/configuration.html#ignoredmethods
31
+ disable_syntax: https://docs.rubocop.org/rubocop/configuration.html#disabling-cops-within-source-code
32
+ commands:
33
+ install: 'bundle exec gem install rubocop'
34
+ review: 'bundle exec rubocop --parallel'
35
+ format: 'bundle exec rubocop --auto-correct'
36
+ quiet_option: '--format q'
data/.rubocop.yml ADDED
@@ -0,0 +1,17 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ Exclude:
4
+ - 'bin/**/*'
5
+
6
+ # Let's aim for 80, but we don't need to be nagged if we judiciously go over.
7
+ Layout/LineLength:
8
+ Enabled: false
9
+
10
+ # One case statement in a single method isn't complex.
11
+ Metrics/CyclomaticComplexity:
12
+ IgnoredMethods: ['case']
13
+
14
+ # 10 is a good goal but a little draconian
15
+ Metrics/MethodLength:
16
+ CountAsOne: ['array', 'hash', 'heredoc']
17
+ Max: 15
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.3
data/Gemfile CHANGED
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in reviewer.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
8
+ gem 'rake', '~> 13.0'
9
9
 
10
- gem "minitest", "~> 5.0"
10
+ gem 'minitest', '~> 5.0'
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reviewer (0.1.1)
4
+ reviewer (0.1.2)
5
5
  activesupport
6
+ colorize
6
7
  slop
7
8
 
8
9
  GEM
@@ -14,23 +15,58 @@ GEM
14
15
  minitest (>= 5.1)
15
16
  tzinfo (~> 2.0)
16
17
  zeitwerk (~> 2.3)
18
+ ast (2.4.2)
19
+ bundler-audit (0.8.0)
20
+ bundler (>= 1.2.0, < 3)
21
+ thor (~> 1.0)
22
+ colorize (0.8.1)
17
23
  concurrent-ruby (1.1.8)
18
24
  i18n (1.8.10)
19
25
  concurrent-ruby (~> 1.0)
20
26
  minitest (5.14.4)
27
+ parallel (1.20.1)
28
+ parser (3.0.1.0)
29
+ ast (~> 2.4.1)
30
+ rainbow (3.0.0)
21
31
  rake (13.0.3)
32
+ regexp_parser (2.1.1)
33
+ rexml (3.2.5)
34
+ rubocop (1.13.0)
35
+ parallel (~> 1.10)
36
+ parser (>= 3.0.0.0)
37
+ rainbow (>= 2.2.2, < 4.0)
38
+ regexp_parser (>= 1.8, < 3.0)
39
+ rexml
40
+ rubocop-ast (>= 1.2.0, < 2.0)
41
+ ruby-progressbar (~> 1.7)
42
+ unicode-display_width (>= 1.4.0, < 3.0)
43
+ rubocop-ast (1.4.1)
44
+ parser (>= 2.7.1.5)
45
+ rubocop-minitest (0.11.1)
46
+ rubocop (>= 0.90, < 2.0)
47
+ rubocop-rake (0.5.1)
48
+ rubocop
49
+ ruby-progressbar (1.11.0)
22
50
  slop (4.8.2)
51
+ thor (1.1.0)
23
52
  tzinfo (2.0.4)
24
53
  concurrent-ruby (~> 1.0)
54
+ unicode-display_width (2.0.0)
25
55
  zeitwerk (2.4.2)
26
56
 
27
57
  PLATFORMS
58
+ ruby
28
59
  x86_64-darwin-19
60
+ x86_64-linux
29
61
 
30
62
  DEPENDENCIES
63
+ bundler-audit
31
64
  minitest (~> 5.0)
32
65
  rake (~> 13.0)
33
66
  reviewer!
67
+ rubocop
68
+ rubocop-minitest
69
+ rubocop-rake
34
70
 
35
71
  BUNDLED WITH
36
72
  2.2.16
data/README.md CHANGED
@@ -1,8 +1,28 @@
1
+ **Note:** As of May 4th, 2021, Reviewer is a work in progress and does not actually do anything just yet. Hopefully soon.
2
+
1
3
  # Reviewer
2
4
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/reviewer`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ Reviewer reduces the friction of using automated tools for dependency audits, static analysis, linting, testing, and more by providing a standardized way to configure and run them in different contexts with less friction.
6
+
7
+ So, instead of...
8
+ ```
9
+ yarn audit --level moderate
10
+ bundle exec bundle-audit check --no-update
11
+ bundle exec rubocop --parallel
12
+ bundle exec erblint --lint-all --enable-all-linters
13
+ yarn stylelint .
14
+ yarn eslint .
15
+ bundle exec rake notes
16
+ ```
17
+
18
+ You run...
19
+ ```
20
+ ./bin/rvw
21
+ ```
22
+
23
+ Having a simpler command is just the beginning through. It also cleans up the output and lets you run subsets of commands.
4
24
 
5
- TODO: Delete this and the text above, and describe your gem
25
+ For more detailed information, take a look at the [Overview](https://github.com/garrettdimon/reviewer/wiki/Overview) and [Usage](https://github.com/garrettdimon/reviewer/wiki/Usage) pages in the wiki.
6
26
 
7
27
  ## Installation
8
28
 
data/Rakefile CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rake/testtask"
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
5
 
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
10
  end
11
11
 
12
12
  task default: :test
data/bin/console CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "reviewer"
4
+ require 'bundler/setup'
5
+ require 'reviewer'
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
10
  # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
11
+ # require 'pry'
12
12
  # Pry.start
13
13
 
14
- require "irb"
14
+ require 'irb'
15
15
  IRB.start(__FILE__)
data/bin/fmt ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/reviewer'
4
+
5
+ Reviewer.format
data/bin/{review → rvw} RENAMED
File without changes
data/lib/reviewer.rb CHANGED
@@ -1,31 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "reviewer/arguments"
4
- require_relative "reviewer/configuration"
5
- require_relative "reviewer/loader"
6
- require_relative "reviewer/tool"
7
- require_relative "reviewer/tools"
8
- require_relative "reviewer/version"
9
-
3
+ require 'active_support/core_ext/string'
4
+ require 'benchmark'
5
+
6
+ require_relative 'reviewer/configuration'
7
+ require_relative 'reviewer/arguments'
8
+ require_relative 'reviewer/loader'
9
+ require_relative 'reviewer/logger'
10
+ require_relative 'reviewer/runner'
11
+ require_relative 'reviewer/tool'
12
+ require_relative 'reviewer/tools'
13
+ require_relative 'reviewer/version'
14
+
15
+ # Primary interface for the reviewer tools
10
16
  module Reviewer
11
17
  class Error < StandardError; end
12
18
 
13
19
  class << self
14
- attr_writer :configuration
20
+ attr_writer :configuration, :logger
15
21
  end
16
22
 
17
23
  def self.review
18
- options = Arguments.new
19
- # TODO: Make it actually run the tools.
20
- puts "Running with the following options:"
21
- pp options
24
+ elapsed_time = Benchmark.realtime do
25
+ Tools.all.each do |tool|
26
+ next if tool.disabled?
27
+
28
+ exit_status = Runner.new(tool, :review).run
29
+
30
+ break unless exit_status <= tool.max_exit_status
31
+ end
32
+ end
33
+ puts "\n➤ Total Time: #{elapsed_time.round(3)}s\n"
22
34
  end
23
35
 
24
36
  def self.format
25
- options = Arguments.new
26
- # TODO: Make it actually run the tools.
27
- puts "Running with the following options:"
28
- pp options
37
+ # options = Arguments.new
38
+ Tools.all.each do |tool|
39
+ Runner.run(tool, :format)
40
+ end
29
41
  end
30
42
 
31
43
  def self.configuration
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'slop'
4
4
 
5
- # Handles option parsing for bin/review
6
5
  module Reviewer
6
+ # Handles option parsing for bin/review
7
7
  class Arguments
8
8
  attr_accessor :options
9
9
 
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reviewer
4
+ # Configuration for Reviewer
4
5
  class Configuration
5
6
  DEFAULT_CONFIGURATION_PATH = Dir.pwd.freeze
6
- DEFAULT_CONFIGURATION_FILE = '.reviewer.yml'.freeze
7
+ DEFAULT_CONFIGURATION_FILE = '.reviewer.yml'
7
8
 
8
9
  attr_accessor :file
9
10
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "yaml"
4
- require "active_support/core_ext/hash/indifferent_access"
3
+ require 'yaml'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
5
 
6
- # Provides a collection of the configured tools
7
6
  module Reviewer
7
+ # Provides a collection of the configured tools
8
8
  class Loader
9
9
  class MissingConfigurationError < StandardError; end
10
+
10
11
  class InvalidConfigurationError < StandardError; end
11
12
 
12
13
  attr_reader :configuration
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorize'
4
+
5
+ module Reviewer
6
+ # Clean formatter for logging to $stdout
7
+ class StandardOutFormatter < ::Logger::Formatter
8
+ def call(_severity, _time, _progname, message)
9
+ "#{message}\n"
10
+ end
11
+ end
12
+
13
+ # Logger for $stdout
14
+ class Logger < ::Logger
15
+ SUCCESS = 'Success'
16
+ FAILURE = 'Failure ·'
17
+ PROMPT = '$'
18
+
19
+ def initialize(formatter = StandardOutFormatter.new)
20
+ super($stdout)
21
+ @formatter = formatter
22
+ end
23
+
24
+ def running(tool)
25
+ info "\n#{tool.name}".bold + ' · '.light_black + tool.description
26
+ end
27
+
28
+ def command(cmd)
29
+ info "#{PROMPT} #{cmd}".light_black
30
+ end
31
+
32
+ def rerunning(tool)
33
+ info "\n\nRe-running #{tool.name} verbosely:"
34
+ end
35
+
36
+ def success(elapsed_time)
37
+ info SUCCESS.green.bold + " (#{elapsed_time.round(3)}s)".green
38
+ end
39
+
40
+ def failure(message)
41
+ info "#{FAILURE} #{message}".red.bold
42
+ end
43
+
44
+ def guidance(summary, details)
45
+ info " #{summary}" if summary
46
+ info " #{details}".light_black if details
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Reviewer
6
+ # Handles running, benchmarking, and printing output for a command
7
+ class Runner
8
+ COMMAND_NOT_FOUND_EXIT_STATUS_CODE = 127
9
+
10
+ attr_accessor :tool, :command
11
+
12
+ attr_reader :elapsed_time, :stdout, :stderr, :status, :exit_status, :logger
13
+
14
+ def initialize(tool, command, logger: Logger.new)
15
+ @tool = tool
16
+ @command = command
17
+ @logger = logger
18
+ end
19
+
20
+ def run
21
+ logger.running(tool)
22
+
23
+ @elapsed_time = Benchmark.realtime do
24
+ prepare
25
+ review
26
+ end
27
+
28
+ print_result
29
+ exit_status
30
+ end
31
+
32
+ private
33
+
34
+ def shell_out(cmd)
35
+ @stdout, @stderr, @status = Open3.capture3(cmd)
36
+ @exit_status = status.exitstatus
37
+
38
+ logger.command(cmd) unless status.success?
39
+ end
40
+
41
+ def prepare
42
+ shell_out(tool.preparation_command) if tool.prepare_command?
43
+ end
44
+
45
+ def review
46
+ shell_out(tool.review_command(seed: seed))
47
+ end
48
+
49
+ def format
50
+ shell_out(tool.format_command) if tool.format_command?
51
+ end
52
+
53
+ def review_verbosely
54
+ cmd = tool.review_command(:no_silence, seed: seed)
55
+ logger.rerunning(tool)
56
+ logger.command(cmd)
57
+ system(cmd)
58
+ end
59
+
60
+ def print_result
61
+ if status.success?
62
+ # Outputs success details
63
+ logger.success(elapsed_time)
64
+ else
65
+ recovery_guidance
66
+ end
67
+ end
68
+
69
+ def recovery_guidance
70
+ logger.failure(error_message)
71
+ if missing_executable?
72
+ missing_executable_guidance
73
+ else
74
+ review_verbosely
75
+ end
76
+ end
77
+
78
+ def error_message
79
+ if missing_executable?
80
+ "Missing executable for '#{tool}'"
81
+ else
82
+ "Exit Status #{exit_status}"
83
+ end
84
+ end
85
+
86
+ def missing_executable_guidance
87
+ logger.guidance('Installation Command:', tool.installation_command) if tool.install_command?
88
+ logger.guidance('Installation Help:', tool.settings.links[:install]) if tool.install_link?
89
+ end
90
+
91
+ def missing_executable?
92
+ (@exit_status == COMMAND_NOT_FOUND_EXIT_STATUS_CODE) ||
93
+ stderr.include?("can't find executable")
94
+ end
95
+
96
+ def seed
97
+ # Keep the same seed for each instance so re-running generates the same results as the failure.
98
+ # Otherwise, re-running after the failure will change the seed and show different results.
99
+ @seed ||= Random.rand(100_000)
100
+ end
101
+ end
102
+ end
data/lib/reviewer/tool.rb CHANGED
@@ -1,38 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string"
4
- require_relative "tool/command"
5
- require_relative "tool/env"
6
- require_relative "tool/flags"
7
- require_relative "tool/settings"
8
- require_relative "tool/verbosity"
9
-
10
- # Provides an instance of a specific tool
3
+ require_relative 'tool/command'
4
+ require_relative 'tool/env'
5
+ require_relative 'tool/flags'
6
+ require_relative 'tool/settings'
7
+ require_relative 'tool/verbosity'
8
+
11
9
  module Reviewer
10
+ # Provides an instance of a specific tool
12
11
  class Tool
13
12
  attr_reader :settings
14
13
 
14
+ delegate :name,
15
+ :description,
16
+ :enabled?,
17
+ :disabled?,
18
+ :max_exit_status,
19
+ :prepare_command?,
20
+ :install_command?,
21
+ :format_command?,
22
+ :install_link?,
23
+ to: :settings
24
+
15
25
  def initialize(tool)
16
26
  @settings = Settings.new(tool)
17
27
  end
18
28
 
29
+ def to_s
30
+ name
31
+ end
32
+
19
33
  def installation_command(verbosity_level = :no_silence)
20
34
  command_string(:install, verbosity_level: verbosity_level)
21
35
  end
22
36
 
23
- def preparation_command(verbosity_level = :no_silence)
24
- command_string(:prepare, verbosity_level: verbosity_level)
37
+ def preparation_command(verbosity_level = :total_silence)
38
+ command_string(:prepare, verbosity_level: verbosity_level)
25
39
  end
26
40
 
27
- def review_command(verbosity_level = :total_silence)
28
- command_string(:review, verbosity_level: verbosity_level)
41
+ def review_command(verbosity_level = :total_silence, seed: nil)
42
+ command_string(:review, verbosity_level: verbosity_level).gsub('$SEED', seed.to_s)
29
43
  end
30
44
 
31
45
  def format_command(verbosity_level = :no_silence)
32
46
  command_string(:format, verbosity_level: verbosity_level)
33
47
  end
34
48
 
35
-
36
49
  private
37
50
 
38
51
  def command_string(command_type, verbosity_level: :no_silence)
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Assembles tool tool_settings into a usable command string
4
3
  module Reviewer
5
4
  class Tool
5
+ # Assembles tool tool_settings into a usable command string
6
6
  class Command
7
7
  class InvalidTypeError < StandardError; end
8
+
8
9
  class NotConfiguredError < StandardError; end
9
10
 
10
11
  TYPES = %i[install prepare review format].freeze
@@ -21,9 +22,9 @@ module Reviewer
21
22
 
22
23
  def to_s
23
24
  to_a
24
- .map(&:strip)
25
- .join(' ')
26
- .strip
25
+ .map(&:strip) # Remove extra spaces on the components
26
+ .join(' ') # Merge the components
27
+ .strip # Strip extra spaces from the end result
27
28
  end
28
29
 
29
30
  def to_a
@@ -44,17 +45,18 @@ module Reviewer
44
45
  end
45
46
 
46
47
  def flags
47
- # :review commands are the only commands that use flags (except the :quiet_flag)
48
- return nil unless review?
48
+ # :review commands are the only commands that use flags
49
+ # And if no flags are configured, this won't do much
50
+ # Flags for 'quiet' are handled separately by design and excluded from this check.
51
+ return nil unless review? && tool_settings.flags.any?
49
52
 
50
53
  Flags.new(tool_settings.flags).to_s
51
54
  end
52
55
 
53
56
  def verbosity
54
- Verbosity.new(tool_settings.quiet_flag, level: verbosity_level).to_s
57
+ Verbosity.new(tool_settings.quiet_option, level: verbosity_level).to_s
55
58
  end
56
59
 
57
-
58
60
  private
59
61
 
60
62
  def review?
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Assembles tool environment variables into a single string or array
4
3
  module Reviewer
5
4
  class Tool
5
+ # Assembles tool environment variables into a single string or array
6
6
  class Env
7
7
  attr_reader :env_pairs
8
8
 
@@ -20,7 +20,6 @@ module Reviewer
20
20
  env
21
21
  end
22
22
 
23
-
24
23
  private
25
24
 
26
25
  def env(key, value)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Assembles tool flag settings into a single string or array
4
3
  module Reviewer
5
4
  class Tool
5
+ # Assembles tool flag settings into a single string or array
6
6
  class Flags
7
7
  attr_reader :flag_pairs
8
8
 
@@ -20,7 +20,6 @@ module Reviewer
20
20
  flags
21
21
  end
22
22
 
23
-
24
23
  private
25
24
 
26
25
  def flag(key, value)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Converts/casts tool configuration values and provides default values if not set
4
3
  module Reviewer
5
4
  class Tool
5
+ # Converts/casts tool configuration values and provides default values if not set
6
6
  class Settings
7
7
  class MissingReviewCommandError < StandardError; end
8
8
 
@@ -14,17 +14,33 @@ module Reviewer
14
14
 
15
15
  # Ideally, folks would fill out everything, but realistically, the 'review' command is the only required value.
16
16
  # If the key is missing, or maybe there was a typo, fail right away.
17
- raise MissingReviewCommandError, "'#{name}' does not have a 'review' key under 'commands' in your tools configuration" unless commands.key?(:review)
17
+ raise MissingReviewCommandError, "'#{key}' does not have a 'review' key under 'commands' in `#{Reviewer.configuration.file}`" unless commands.key?(:review)
18
18
  end
19
19
 
20
20
  def disabled?
21
- config.fetch(:disabled) { false }
21
+ config.fetch(:disabled, false)
22
22
  end
23
23
 
24
24
  def enabled?
25
25
  !disabled?
26
26
  end
27
27
 
28
+ def prepare_command?
29
+ commands.key?(:prepare) && commands[:prepare].present?
30
+ end
31
+
32
+ def install_command?
33
+ commands.key?(:install) && commands[:install].present?
34
+ end
35
+
36
+ def format_command?
37
+ commands.key?(:format) && commands[:format].present?
38
+ end
39
+
40
+ def install_link?
41
+ links.key?(:install) && links[:install].present?
42
+ end
43
+
28
44
  def key
29
45
  tool.to_sym
30
46
  end
@@ -58,11 +74,11 @@ module Reviewer
58
74
  end
59
75
 
60
76
  def max_exit_status
61
- commands.fetch(:max_exit_status) { 0 }
77
+ commands.fetch(:max_exit_status, 0)
62
78
  end
63
79
 
64
- def quiet_flag
65
- commands.fetch(:quiet_flag) { '' }
80
+ def quiet_option
81
+ commands.fetch(:quiet_option, '')
66
82
  end
67
83
  end
68
84
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Assembles tool settings and provided context for silencing output
4
3
  module Reviewer
5
4
  class Tool
5
+ # Assembles tool settings and provided context for silencing output
6
6
  class Verbosity
7
7
  class InvalidLevelError < StandardError; end
8
8
  # :total_silence = Use the quiet flag and send everything to dev/null.
@@ -11,20 +11,20 @@ module Reviewer
11
11
  # :tool_silence = Just the quiet flag
12
12
  # :no_silence = Let the output scroll for eternity
13
13
  LEVELS = %i[total_silence tool_silence no_silence].freeze
14
- SEND_TO_DEV_NULL = "> /dev/null".freeze
14
+ SEND_TO_DEV_NULL = '> /dev/null'
15
15
 
16
16
  attr_reader :flag, :level
17
17
 
18
- def initialize(flag, level: :total_silence)
18
+ def initialize(flag, level: :tool_silence)
19
19
  @flag = flag
20
20
 
21
- raise InvalidLevelError, "Invalid Verbosity Level: '#{level}'" unless LEVELS.include?(level)
21
+ raise InvalidLevelError, "Invalid Verbosity Level: '#{level}'" unless LEVELS.include?(level)
22
22
 
23
23
  @level = level
24
24
  end
25
25
 
26
26
  def to_s
27
- to_a.join(' ').strip
27
+ to_a.map(&:strip).join(' ').strip
28
28
  end
29
29
 
30
30
  def to_a
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Provides a collection of the configured tools
4
3
  module Reviewer
4
+ # Provides a collection of the configured tools
5
5
  module Tools
6
6
  def self.all
7
- []
8
- end
9
-
10
- def self.enabled
11
- []
12
- end
13
-
14
- def self.disabled
15
- []
7
+ tools = []
8
+ Reviewer.configuration.tools.each_key do |key|
9
+ tools << Tool.new(key)
10
+ end
11
+ tools
16
12
  end
17
13
  end
18
14
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reviewer
4
- VERSION = "0.1.1"
4
+ VERSION = '0.1.2'
5
5
  end
data/reviewer.gemspec CHANGED
@@ -1,36 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/reviewer/version"
3
+ require_relative 'lib/reviewer/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "reviewer"
6
+ spec.name = 'reviewer'
7
7
  spec.version = Reviewer::VERSION
8
- spec.authors = ["Garrett Dimon"]
9
- spec.email = ["email@garrettdimon.com"]
8
+ spec.authors = ['Garrett Dimon']
9
+ spec.email = ['email@garrettdimon.com']
10
10
 
11
- spec.summary = "Provides a unified approach to managing automated code quality tools."
12
- spec.description = "Provides a unified approach to managing automated code quality tools."
13
- spec.homepage = "https://github.com/garrettdimon/reviewer"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
11
+ spec.summary = 'Provides a unified approach to managing automated code quality tools.'
12
+ spec.description = 'Provides a unified approach to managing automated code quality tools.'
13
+ spec.homepage = 'https://github.com/garrettdimon/reviewer'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.3')
16
16
 
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/garrettdimon/reviewer"
19
- spec.metadata["changelog_uri"] = "https://github.com/garrettdimon/reviewer/CHANGELOG.md"
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/garrettdimon/reviewer'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/garrettdimon/reviewer/CHANGELOG.md'
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
23
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
25
  end
26
- spec.bindir = "exe"
26
+ spec.bindir = 'exe'
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
28
+ spec.require_paths = ['lib']
29
29
 
30
- # Uncomment to register a new dependency of your gem
31
- spec.add_dependency "activesupport"
32
- spec.add_dependency "slop"
30
+ spec.add_dependency 'activesupport'
31
+ spec.add_dependency 'colorize'
32
+ spec.add_dependency 'slop'
33
33
 
34
- # For more information and examples about making a new gem, checkout our
35
- # guide at: https://bundler.io/guides/creating_gem.html
34
+ spec.add_development_dependency 'bundler-audit'
35
+ spec.add_development_dependency 'rubocop'
36
+ spec.add_development_dependency 'rubocop-minitest'
37
+ spec.add_development_dependency 'rubocop-rake'
36
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reviewer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garrett Dimon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-18 00:00:00.000000000 Z
11
+ date: 2021-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: slop
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,62 @@ dependencies:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler-audit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
41
111
  description: Provides a unified approach to managing automated code quality tools.
42
112
  email:
43
113
  - email@garrettdimon.com
@@ -47,6 +117,10 @@ extra_rdoc_files: []
47
117
  files:
48
118
  - ".github/workflows/main.yml"
49
119
  - ".gitignore"
120
+ - ".reviewer.example.yml"
121
+ - ".reviewer.yml"
122
+ - ".rubocop.yml"
123
+ - ".ruby-version"
50
124
  - CHANGELOG.md
51
125
  - CODE_OF_CONDUCT.md
52
126
  - Gemfile
@@ -55,12 +129,15 @@ files:
55
129
  - README.md
56
130
  - Rakefile
57
131
  - bin/console
58
- - bin/review
132
+ - bin/fmt
133
+ - bin/rvw
59
134
  - bin/setup
60
135
  - lib/reviewer.rb
61
136
  - lib/reviewer/arguments.rb
62
137
  - lib/reviewer/configuration.rb
63
138
  - lib/reviewer/loader.rb
139
+ - lib/reviewer/logger.rb
140
+ - lib/reviewer/runner.rb
64
141
  - lib/reviewer/tool.rb
65
142
  - lib/reviewer/tool/command.rb
66
143
  - lib/reviewer/tool/env.rb
@@ -85,14 +162,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
162
  requirements:
86
163
  - - ">="
87
164
  - !ruby/object:Gem::Version
88
- version: 2.4.0
165
+ version: 2.7.3
89
166
  required_rubygems_version: !ruby/object:Gem::Requirement
90
167
  requirements:
91
168
  - - ">="
92
169
  - !ruby/object:Gem::Version
93
170
  version: '0'
94
171
  requirements: []
95
- rubygems_version: 3.2.16
172
+ rubygems_version: 3.1.6
96
173
  signing_key:
97
174
  specification_version: 4
98
175
  summary: Provides a unified approach to managing automated code quality tools.