reviewer 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.flayignore +1 -0
- data/.github/workflows/main.yml +11 -3
- data/.gitignore +5 -0
- data/.reviewer.example.yml +27 -23
- data/.reviewer.yml +58 -5
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +54 -29
- data/README.md +5 -50
- data/exe/fmt +1 -1
- data/exe/rvw +1 -1
- data/lib/reviewer.rb +39 -26
- data/lib/reviewer/arguments.rb +25 -9
- data/lib/reviewer/arguments/files.rb +37 -5
- data/lib/reviewer/arguments/keywords.rb +23 -9
- data/lib/reviewer/arguments/tags.rb +26 -3
- data/lib/reviewer/batch.rb +64 -0
- data/lib/reviewer/command.rb +100 -0
- data/lib/reviewer/command/string.rb +72 -0
- data/lib/reviewer/command/string/env.rb +40 -0
- data/lib/reviewer/command/string/flags.rb +40 -0
- data/lib/reviewer/command/string/verbosity.rb +51 -0
- data/lib/reviewer/command/verbosity.rb +65 -0
- data/lib/reviewer/configuration.rb +24 -4
- data/lib/reviewer/conversions.rb +27 -0
- data/lib/reviewer/guidance.rb +73 -0
- data/lib/reviewer/history.rb +38 -0
- data/lib/reviewer/keywords.rb +9 -0
- data/lib/reviewer/keywords/git.rb +14 -0
- data/lib/reviewer/keywords/git/staged.rb +48 -0
- data/lib/reviewer/loader.rb +2 -3
- data/lib/reviewer/output.rb +92 -0
- data/lib/reviewer/printer.rb +25 -0
- data/lib/reviewer/runner.rb +43 -72
- data/lib/reviewer/runner/strategies/quiet.rb +90 -0
- data/lib/reviewer/runner/strategies/verbose.rb +63 -0
- data/lib/reviewer/shell.rb +58 -0
- data/lib/reviewer/shell/result.rb +69 -0
- data/lib/reviewer/shell/timer.rb +57 -0
- data/lib/reviewer/tool.rb +109 -40
- data/lib/reviewer/tool/settings.rb +18 -32
- data/lib/reviewer/tools.rb +38 -3
- data/lib/reviewer/version.rb +1 -1
- data/reviewer.gemspec +10 -2
- metadata +143 -16
- data/lib/reviewer/arguments/keywords/git.rb +0 -16
- data/lib/reviewer/arguments/keywords/git/staged.rb +0 -64
- data/lib/reviewer/logger.rb +0 -62
- data/lib/reviewer/tool/command.rb +0 -80
- data/lib/reviewer/tool/env.rb +0 -38
- data/lib/reviewer/tool/flags.rb +0 -38
- data/lib/reviewer/tool/verbosity.rb +0 -39
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'command/string'
|
4
|
+
require_relative 'command/verbosity'
|
5
|
+
|
6
|
+
module Reviewer
|
7
|
+
# The core funtionality to translate a tool, command type, and verbosity into a runnable command
|
8
|
+
class Command
|
9
|
+
include Conversions
|
10
|
+
|
11
|
+
SEED_SUBSTITUTION_VALUE = '$SEED'
|
12
|
+
|
13
|
+
attr_reader :tool, :type
|
14
|
+
|
15
|
+
# Creates an instance of the Command class to synthesize a command string using the tool,
|
16
|
+
# command type, and verbosity.
|
17
|
+
# @param tool [Tool, Symbol] a tool or tool key to use to look up the command and options
|
18
|
+
# @param type [Symbol] the desired command type (:install, :prepare, :review, :format)
|
19
|
+
# @param verbosity = Verbosity::TOTAL_SILENCE [Symbol] the desired verbosity for the command
|
20
|
+
#
|
21
|
+
# @return [Command] the intersection of a tool, command type, and verbosity
|
22
|
+
def initialize(tool, type, verbosity = Verbosity::TOTAL_SILENCE)
|
23
|
+
@tool = Tool(tool)
|
24
|
+
@type = type.to_sym
|
25
|
+
@verbosity = Verbosity(verbosity)
|
26
|
+
end
|
27
|
+
|
28
|
+
# The final command string with all of the conditions appled
|
29
|
+
#
|
30
|
+
# @return [String] the final, valid command string to run
|
31
|
+
def string
|
32
|
+
@string ||= seed_substitution? ? seeded_string : raw_string
|
33
|
+
end
|
34
|
+
alias to_s string
|
35
|
+
|
36
|
+
# Getter for @verbosity. Since the setter is custom, the getter needs to be explicitly declared.
|
37
|
+
# Otherwise, using `attr_accessor` and then overriding the setter muddies the waters.
|
38
|
+
#
|
39
|
+
# @return [Verbosity] the current verbosity setting for the command
|
40
|
+
def verbosity # rubocop:disable Style/TrivialAccessors
|
41
|
+
@verbosity
|
42
|
+
end
|
43
|
+
|
44
|
+
# Override verbosity assignment to clear the related memoized values when verbosity changes
|
45
|
+
# @param verbosity [Verbosity, Symbol] the desired verbosity for the command
|
46
|
+
#
|
47
|
+
# @return [Verbosity] the updated verbosity level for the command
|
48
|
+
def verbosity=(verbosity)
|
49
|
+
# Unmemoize string since the verbosity has been changed
|
50
|
+
@raw_string = nil
|
51
|
+
@string = nil
|
52
|
+
|
53
|
+
@verbosity = Verbosity(verbosity)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Generates a seed that can be re-used across runs so that the results are consistent across
|
57
|
+
# related runs for tools that would otherwise change the seed automatically every run.
|
58
|
+
# Since not all tools will use the seed, there's no need to generate it in the initializer.
|
59
|
+
# Instead, it's memoized if it's used.
|
60
|
+
#
|
61
|
+
# @return [Integer] a random integer to pass to tools that use seeds
|
62
|
+
def seed
|
63
|
+
@seed ||= Random.rand(100_000)
|
64
|
+
|
65
|
+
# Store the seed for reference
|
66
|
+
Reviewer.history.set(tool.key, :last_seed, @seed)
|
67
|
+
|
68
|
+
@seed
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# The raw command string before any substitutions. For example, since seeds need to remain
|
74
|
+
# consistent from one run to the next, they're
|
75
|
+
#
|
76
|
+
# @return [type] [description]
|
77
|
+
def raw_string
|
78
|
+
@raw_string ||= String.new(
|
79
|
+
type,
|
80
|
+
tool_settings: tool.settings,
|
81
|
+
verbosity: verbosity
|
82
|
+
).to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
# The version of the command with the SEED_SUBSTITUTION_VALUE replaced
|
86
|
+
#
|
87
|
+
# @return [String] the command string with the SEED_SUBSTITUTION_VALUE replaced
|
88
|
+
def seeded_string
|
89
|
+
# Update the string with the memoized seed value
|
90
|
+
raw_string.gsub(SEED_SUBSTITUTION_VALUE, seed.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Determines if the raw command string has a SEED_SUBSTITUTION_VALUE that needs replacing
|
94
|
+
#
|
95
|
+
# @return [Boolean] true if the raw command string contains the SEED_SUBSTITUTION_VALUE
|
96
|
+
def seed_substitution?
|
97
|
+
raw_string.include?(SEED_SUBSTITUTION_VALUE)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'string/env'
|
4
|
+
require_relative 'string/flags'
|
5
|
+
require_relative 'string/verbosity'
|
6
|
+
|
7
|
+
module Reviewer
|
8
|
+
class Command
|
9
|
+
# Assembles tool tool_settings into a usable command string for the command type and verbosity
|
10
|
+
class String
|
11
|
+
include Conversions
|
12
|
+
|
13
|
+
attr_reader :command_type, :tool_settings, :verbosity
|
14
|
+
|
15
|
+
def initialize(command_type, tool_settings:, verbosity: nil)
|
16
|
+
@command_type = command_type
|
17
|
+
@tool_settings = tool_settings
|
18
|
+
@verbosity = Verbosity(verbosity)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
to_a
|
23
|
+
.map(&:strip) # Remove extra spaces on the components
|
24
|
+
.join(' ') # Merge the components
|
25
|
+
.strip # Strip extra spaces from the end result
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_a
|
29
|
+
[
|
30
|
+
env_variables,
|
31
|
+
body,
|
32
|
+
flags,
|
33
|
+
verbosity_options
|
34
|
+
].compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def env_variables
|
38
|
+
Env.new(tool_settings.env).to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
def body
|
42
|
+
tool_settings.commands.fetch(command_type)
|
43
|
+
end
|
44
|
+
|
45
|
+
def flags
|
46
|
+
# Flags to be used for `review` commands.
|
47
|
+
# 1. The `review` commands are the only commands that use flags
|
48
|
+
# 2. If no flags are configured, this won't do much
|
49
|
+
#
|
50
|
+
# Note: Since verbosity is handled separately, flags for 'quiet' are handled separately at a
|
51
|
+
# lower level by design and excluded from this check. They are not included with the other
|
52
|
+
# configured flags.
|
53
|
+
return nil unless flags?
|
54
|
+
|
55
|
+
Flags.new(tool_settings.flags).to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def verbosity_options
|
59
|
+
Verbosity.new(tool_settings.quiet_option, level: verbosity.level).to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Determines whether the string needs flags added
|
65
|
+
#
|
66
|
+
# @return [Boolean] true if it's a review command and it has flags configured
|
67
|
+
def flags?
|
68
|
+
command_type == :review && tool_settings.flags.any?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reviewer
|
4
|
+
class Command
|
5
|
+
class String
|
6
|
+
# Assembles tool environment variables into a single string or array
|
7
|
+
class Env
|
8
|
+
attr_reader :env_pairs
|
9
|
+
|
10
|
+
def initialize(env_pairs)
|
11
|
+
@env_pairs = env_pairs
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
to_a.compact.join(' ')
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
env = []
|
20
|
+
env_pairs.each { |key, value| env << env(key, value) }
|
21
|
+
env
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def env(key, value)
|
27
|
+
return nil if key.to_s.strip.empty? || value.to_s.strip.empty?
|
28
|
+
|
29
|
+
value = needs_quotes?(value) ? "'#{value}'" : value
|
30
|
+
|
31
|
+
"#{key.to_s.strip.upcase}=#{value.to_s.strip}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def needs_quotes?(value)
|
35
|
+
value.is_a?(::String) && value.include?(' ')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reviewer
|
4
|
+
class Command
|
5
|
+
class String
|
6
|
+
# Assembles tool flag settings into a single string or array
|
7
|
+
class Flags
|
8
|
+
attr_reader :flag_pairs
|
9
|
+
|
10
|
+
def initialize(flag_pairs)
|
11
|
+
@flag_pairs = flag_pairs
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
to_a.join(' ')
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
flags = []
|
20
|
+
flag_pairs.each { |key, value| flags << flag(key, value) }
|
21
|
+
flags
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def flag(key, value)
|
27
|
+
dash = key.to_s.size == 1 ? '-' : '--'
|
28
|
+
|
29
|
+
value = needs_quotes?(value) ? "'#{value}'" : value
|
30
|
+
|
31
|
+
"#{dash}#{key} #{value}".strip
|
32
|
+
end
|
33
|
+
|
34
|
+
def needs_quotes?(value)
|
35
|
+
value.is_a?(::String) && value.include?(' ')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reviewer
|
4
|
+
class Command
|
5
|
+
class String
|
6
|
+
# Assembles tool settings and provided context for silencing output
|
7
|
+
class Verbosity
|
8
|
+
include ::Reviewer::Conversions
|
9
|
+
|
10
|
+
# Even when tools provide a quiet flag, not all treat it as complete silence. In order to
|
11
|
+
# ensure no extraneous noise is written to the console in some contexts, command output
|
12
|
+
# occasionally needs to be sent to dev null to ensure there's no clutter.
|
13
|
+
SEND_TO_DEV_NULL = '> /dev/null'
|
14
|
+
|
15
|
+
attr_reader :flag, :level
|
16
|
+
|
17
|
+
# A wrapper for translating a desired verbosity into the correct strings to append to the
|
18
|
+
# command so that any output is appropriately silenced for the context under which it's
|
19
|
+
# currently being executed.
|
20
|
+
# @param flag [String] the tool-level flag to be used for silencing output
|
21
|
+
# @param level: Reviewer::Command::Verbosity::TOOL_SILENCE [Symbol] the target level for
|
22
|
+
# silence for the the command
|
23
|
+
#
|
24
|
+
# @return [type] [description]
|
25
|
+
def initialize(flag, level: Reviewer::Command::Verbosity::TOOL_SILENCE)
|
26
|
+
@flag = String(flag)
|
27
|
+
@level = Verbosity(level)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Converts the verbosity to a string that can be appended to a command string
|
31
|
+
#
|
32
|
+
# @return [String] the string to be appended to commands to ensure the correct verbosity
|
33
|
+
def to_s
|
34
|
+
to_a.map(&:strip).join(' ').strip
|
35
|
+
end
|
36
|
+
|
37
|
+
# Collection of values to be joined to ensure the correct verbosity
|
38
|
+
#
|
39
|
+
# @return [Array<String>] the values that need to be joined to ensure the correct verbosity
|
40
|
+
# for the context
|
41
|
+
def to_a
|
42
|
+
case level.key
|
43
|
+
when Reviewer::Command::Verbosity::TOTAL_SILENCE then [flag, SEND_TO_DEV_NULL].compact
|
44
|
+
when Reviewer::Command::Verbosity::TOOL_SILENCE then [flag].compact
|
45
|
+
else []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reviewer
|
4
|
+
class Command
|
5
|
+
# Defines the possible verbosity options for running commands
|
6
|
+
class Verbosity
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
class InvalidLevelError < ArgumentError; end
|
10
|
+
|
11
|
+
# Use the quiet flag and send everything to dev/null.
|
12
|
+
# For some tools "quiet" means "less noisy" rather than truly silent.
|
13
|
+
# So in those cases, dev/null handles lingering noise.
|
14
|
+
TOTAL_SILENCE = :total_silence
|
15
|
+
|
16
|
+
# Just the quiet flag for the tool. Basically, let the tool determine the useful output.
|
17
|
+
TOOL_SILENCE = :tool_silence
|
18
|
+
|
19
|
+
# Let the output scroll for eternity
|
20
|
+
NO_SILENCE = :no_silence
|
21
|
+
|
22
|
+
# For validation and casting purposes
|
23
|
+
LEVELS = [
|
24
|
+
TOTAL_SILENCE,
|
25
|
+
TOOL_SILENCE,
|
26
|
+
NO_SILENCE
|
27
|
+
].freeze
|
28
|
+
|
29
|
+
attr_accessor :level
|
30
|
+
|
31
|
+
# Create an instance of verbosity
|
32
|
+
# @param level [Symbol] one of the values of verbosity defined by LEVELS
|
33
|
+
#
|
34
|
+
# @return [Command::Verbosity] an instance of verbosity
|
35
|
+
def initialize(level)
|
36
|
+
@level = level.to_sym
|
37
|
+
|
38
|
+
verify_level!
|
39
|
+
end
|
40
|
+
|
41
|
+
def <=>(other)
|
42
|
+
level <=> other.level
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
level.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_i
|
50
|
+
LEVELS.index(level)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_sym
|
54
|
+
level
|
55
|
+
end
|
56
|
+
alias key to_sym
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def verify_level!
|
61
|
+
raise InvalidLevelError, "Invalid Verbosity Level: '#{level}'" unless LEVELS.include?(level)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,16 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
|
3
5
|
module Reviewer
|
4
6
|
# Configuration values container for Reviewer
|
5
7
|
class Configuration
|
6
8
|
DEFAULT_PATH = Dir.pwd.freeze
|
7
|
-
DEFAULT_FILE_NAME = '.reviewer.yml'
|
8
|
-
DEFAULT_FILE = "#{DEFAULT_PATH}/#{DEFAULT_FILE_NAME}"
|
9
9
|
|
10
|
-
|
10
|
+
DEFAULT_CONFIG_FILE_NAME = '.reviewer.yml'
|
11
|
+
DEFAULT_HISTORY_FILE_NAME = '.reviewer_history.yml'
|
12
|
+
|
13
|
+
DEFAULT_CONFIG_LOCATION = "#{DEFAULT_PATH}/#{DEFAULT_CONFIG_FILE_NAME}"
|
14
|
+
DEFAULT_HISTORY_LOCATION = "#{DEFAULT_PATH}/#{DEFAULT_HISTORY_FILE_NAME}"
|
15
|
+
|
16
|
+
attr_accessor :file, :history_file, :printer
|
11
17
|
|
12
18
|
def initialize
|
13
|
-
@file =
|
19
|
+
@file = Pathname(DEFAULT_CONFIG_LOCATION)
|
20
|
+
@history_file = Pathname(DEFAULT_HISTORY_LOCATION)
|
21
|
+
@printer = ::Reviewer::Printer.new
|
22
|
+
|
23
|
+
# Future Configuration Options:
|
24
|
+
# - seed_substitution_value(string): Currently a constant of `$SEED` in Reviewer::Command, but
|
25
|
+
# may need to be configurable in case any command-line strings have other legitimate uses
|
26
|
+
# for the value such that it may need to be override. Ideally, it woudl be changed to3
|
27
|
+
# something obscure enough that conflicts wouldn't happen, but you never know
|
28
|
+
# - benchmark_everything(:dev, :optimize): Use the `time_up` gem to measure and show all the results
|
29
|
+
# for each tool and step to help identify and reduce bottlenecks. It would mainly be a flag
|
30
|
+
# for use in development, but it could also help folks troubleshoot their speed in finer
|
31
|
+
# detail than the standard Reviewer output
|
32
|
+
# - default_preparation_refresh(integer time): Right now, it's hard-coded at 6 hours, but that may require
|
33
|
+
# tuning for individual tools
|
14
34
|
end
|
15
35
|
end
|
16
36
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Reviewer
|
4
|
+
# Conversion functions for special types in Reviewer
|
5
|
+
module Conversions
|
6
|
+
def Tool(value) # rubocop:disable Naming/MethodName
|
7
|
+
case value
|
8
|
+
when Tool then value
|
9
|
+
when Symbol then Tool.new(value)
|
10
|
+
when String then Tool.new(value.to_sym)
|
11
|
+
else raise TypeError, "Cannot convert #{value} to Tool"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
module_function :Tool
|
15
|
+
|
16
|
+
def Verbosity(value) # rubocop:disable Naming/MethodName
|
17
|
+
case value
|
18
|
+
when Command::Verbosity then value
|
19
|
+
when Symbol then Command::Verbosity.new(value)
|
20
|
+
when String then Command::Verbosity.new(value.to_sym)
|
21
|
+
when Integer then Command::Verbosity.new(Command::Verbosity::LEVELS[value])
|
22
|
+
else raise TypeError, "Cannot convert #{value} to Verbosity"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
module_function :Verbosity
|
26
|
+
end
|
27
|
+
end
|