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 +4 -4
- data/.github/workflows/main.yml +1 -1
- data/.reviewer.example.yml +47 -0
- data/.reviewer.yml +36 -0
- data/.rubocop.yml +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +37 -1
- data/README.md +22 -2
- data/Rakefile +5 -5
- data/bin/console +4 -4
- data/bin/fmt +5 -0
- data/bin/{review → rvw} +0 -0
- data/lib/reviewer.rb +28 -16
- data/lib/reviewer/arguments.rb +1 -1
- data/lib/reviewer/configuration.rb +2 -1
- data/lib/reviewer/loader.rb +4 -3
- data/lib/reviewer/logger.rb +49 -0
- data/lib/reviewer/runner.rb +102 -0
- data/lib/reviewer/tool.rb +26 -13
- data/lib/reviewer/tool/command.rb +10 -8
- data/lib/reviewer/tool/env.rb +1 -2
- data/lib/reviewer/tool/flags.rb +1 -2
- data/lib/reviewer/tool/settings.rb +22 -6
- data/lib/reviewer/tool/verbosity.rb +5 -5
- data/lib/reviewer/tools.rb +6 -10
- data/lib/reviewer/version.rb +1 -1
- data/reviewer.gemspec +21 -19
- metadata +82 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64e0b63ddf470414a26b5903508646ace97b1b0ee6e2b0244e7233d9e6717652
|
4
|
+
data.tar.gz: 97b9d1d998959319791022b37f00fde7b6424411c728e98fb8109c352078088d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da483ff2104b138d463c1688731c3eb83ecb8778105af38efbe98f6c7597f9aa4a069341580a3fc7bb34833cf83119d64967a56398e0cea4f97ae7bebc2ae5f2
|
7
|
+
data.tar.gz: f9f1106bf11209abd1a5af2d3ad151413a1026cbe43a4a5db171414d335df7cae9c7ab8d922e661da0625240163d55906eccf9b8fe03a245869f97b00bc94ce8
|
data/.github/workflows/main.yml
CHANGED
@@ -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
|
3
|
+
source 'https://rubygems.org'
|
4
4
|
|
5
5
|
# Specify your gem's dependencies in reviewer.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
gem
|
8
|
+
gem 'rake', '~> 13.0'
|
9
9
|
|
10
|
-
gem
|
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.
|
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
|
-
|
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
|
-
|
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
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
5
|
|
6
6
|
Rake::TestTask.new(:test) do |t|
|
7
|
-
t.libs <<
|
8
|
-
t.libs <<
|
9
|
-
t.test_files = FileList[
|
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
|
5
|
-
require
|
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
|
11
|
+
# require 'pry'
|
12
12
|
# Pry.start
|
13
13
|
|
14
|
-
require
|
14
|
+
require 'irb'
|
15
15
|
IRB.start(__FILE__)
|
data/bin/fmt
ADDED
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
data/lib/reviewer/arguments.rb
CHANGED
@@ -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'
|
7
|
+
DEFAULT_CONFIGURATION_FILE = '.reviewer.yml'
|
7
8
|
|
8
9
|
attr_accessor :file
|
9
10
|
|
data/lib/reviewer/loader.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
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
|
-
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
|
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 = :
|
24
|
-
|
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
|
48
|
-
|
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.
|
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?
|
data/lib/reviewer/tool/env.rb
CHANGED
@@ -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)
|
data/lib/reviewer/tool/flags.rb
CHANGED
@@ -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, "'#{
|
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
|
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
|
77
|
+
commands.fetch(:max_exit_status, 0)
|
62
78
|
end
|
63
79
|
|
64
|
-
def
|
65
|
-
commands.fetch(:
|
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 =
|
14
|
+
SEND_TO_DEV_NULL = '> /dev/null'
|
15
15
|
|
16
16
|
attr_reader :flag, :level
|
17
17
|
|
18
|
-
def initialize(flag, level: :
|
18
|
+
def initialize(flag, level: :tool_silence)
|
19
19
|
@flag = flag
|
20
20
|
|
21
|
-
raise InvalidLevelError, "Invalid Verbosity Level: '#{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
|
data/lib/reviewer/tools.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
10
|
-
|
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
|
data/lib/reviewer/version.rb
CHANGED
data/reviewer.gemspec
CHANGED
@@ -1,36 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'lib/reviewer/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'reviewer'
|
7
7
|
spec.version = Reviewer::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
8
|
+
spec.authors = ['Garrett Dimon']
|
9
|
+
spec.email = ['email@garrettdimon.com']
|
10
10
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new(
|
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[
|
18
|
-
spec.metadata[
|
19
|
-
spec.metadata[
|
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 =
|
26
|
+
spec.bindir = 'exe'
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = [
|
28
|
+
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
|
31
|
-
spec.add_dependency
|
32
|
-
spec.add_dependency
|
30
|
+
spec.add_dependency 'activesupport'
|
31
|
+
spec.add_dependency 'colorize'
|
32
|
+
spec.add_dependency 'slop'
|
33
33
|
|
34
|
-
|
35
|
-
|
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.
|
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
|
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/
|
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.
|
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.
|
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.
|