reviewer 0.1.5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/main.yml +79 -11
- data/.github/workflows/release.yml +98 -0
- data/.gitignore +1 -1
- data/.inch.yml +3 -1
- data/.reek.yml +175 -0
- data/.reviewer.example.yml +7 -2
- data/.reviewer.yml +166 -40
- data/.rubocop.yml +34 -2
- data/CHANGELOG.md +42 -2
- data/Gemfile +39 -1
- data/Gemfile.lock +291 -70
- data/LICENSE.txt +20 -4
- data/README.md +310 -21
- data/RELEASING.md +190 -0
- data/Rakefile +117 -0
- data/dependency_decisions.yml +61 -0
- data/exe/fmt +1 -1
- data/exe/rvw +1 -1
- data/lib/reviewer/arguments/files.rb +47 -20
- data/lib/reviewer/arguments/keywords.rb +34 -41
- data/lib/reviewer/arguments/tags.rb +11 -11
- data/lib/reviewer/arguments.rb +100 -29
- data/lib/reviewer/batch/formatter.rb +87 -0
- data/lib/reviewer/batch.rb +32 -48
- data/lib/reviewer/capabilities.rb +81 -0
- data/lib/reviewer/command/string/env.rb +12 -6
- data/lib/reviewer/command/string/flags.rb +2 -4
- data/lib/reviewer/command/string.rb +47 -12
- data/lib/reviewer/command.rb +65 -10
- data/lib/reviewer/configuration/loader.rb +70 -0
- data/lib/reviewer/configuration.rb +6 -3
- data/lib/reviewer/context.rb +15 -0
- data/lib/reviewer/doctor/config_check.rb +46 -0
- data/lib/reviewer/doctor/environment_check.rb +58 -0
- data/lib/reviewer/doctor/formatter.rb +75 -0
- data/lib/reviewer/doctor/keyword_check.rb +85 -0
- data/lib/reviewer/doctor/opportunity_check.rb +88 -0
- data/lib/reviewer/doctor/report.rb +63 -0
- data/lib/reviewer/doctor/tool_inventory.rb +41 -0
- data/lib/reviewer/doctor.rb +28 -0
- data/lib/reviewer/history.rb +10 -17
- data/lib/reviewer/output/formatting.rb +40 -0
- data/lib/reviewer/output/printer.rb +70 -9
- data/lib/reviewer/output.rb +37 -78
- data/lib/reviewer/prompt.rb +38 -0
- data/lib/reviewer/report/formatter.rb +124 -0
- data/lib/reviewer/report.rb +100 -0
- data/lib/reviewer/runner/failed_files.rb +66 -0
- data/lib/reviewer/runner/formatter.rb +103 -0
- data/lib/reviewer/runner/guidance.rb +79 -0
- data/lib/reviewer/runner/result.rb +150 -0
- data/lib/reviewer/runner/strategies/captured.rb +98 -23
- data/lib/reviewer/runner/strategies/passthrough.rb +2 -11
- data/lib/reviewer/runner.rb +126 -40
- data/lib/reviewer/session/formatter.rb +87 -0
- data/lib/reviewer/session.rb +208 -0
- data/lib/reviewer/setup/catalog.rb +233 -0
- data/lib/reviewer/setup/detector.rb +61 -0
- data/lib/reviewer/setup/formatter.rb +94 -0
- data/lib/reviewer/setup/gemfile_lock.rb +55 -0
- data/lib/reviewer/setup/generator.rb +54 -0
- data/lib/reviewer/setup/tool_block.rb +112 -0
- data/lib/reviewer/setup.rb +41 -0
- data/lib/reviewer/shell/result.rb +14 -15
- data/lib/reviewer/shell/timer.rb +40 -35
- data/lib/reviewer/shell.rb +41 -12
- data/lib/reviewer/tool/conversions.rb +20 -0
- data/lib/reviewer/tool/file_resolver.rb +54 -0
- data/lib/reviewer/tool/settings.rb +88 -44
- data/lib/reviewer/tool/test_file_mapper.rb +73 -0
- data/lib/reviewer/tool/timing.rb +78 -0
- data/lib/reviewer/tool.rb +88 -69
- data/lib/reviewer/tools.rb +47 -33
- data/lib/reviewer/version.rb +1 -1
- data/lib/reviewer.rb +109 -50
- data/reviewer.gemspec +16 -19
- metadata +101 -142
- data/lib/reviewer/conversions.rb +0 -16
- data/lib/reviewer/guidance.rb +0 -77
- data/lib/reviewer/keywords/git/staged.rb +0 -64
- data/lib/reviewer/keywords/git.rb +0 -14
- data/lib/reviewer/keywords.rb +0 -9
- data/lib/reviewer/loader.rb +0 -59
- data/lib/reviewer/output/scrubber.rb +0 -48
- data/lib/reviewer/output/token.rb +0 -85
data/exe/fmt
CHANGED
data/exe/rvw
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
3
5
|
module Reviewer
|
|
4
6
|
class Arguments
|
|
5
7
|
# Generates a Ruby-friendly list (Array) of files to run the command against from the provided
|
|
@@ -10,10 +12,13 @@ module Reviewer
|
|
|
10
12
|
alias raw provided
|
|
11
13
|
|
|
12
14
|
# Generates an instance of files from the provided arguments
|
|
13
|
-
# @param provided
|
|
14
|
-
# directly via the -f or --files flag on the command line
|
|
15
|
-
# @param keywords
|
|
16
|
-
# be translated to a list of files (
|
|
15
|
+
# @param provided [Array<String>] file arguments provided
|
|
16
|
+
# directly via the -f or --files flag on the command line
|
|
17
|
+
# @param keywords [Array<String>] reserved keywords that can potentially
|
|
18
|
+
# be translated to a list of files (e.g. 'staged', 'modified')
|
|
19
|
+
# @param output [Output] the console output handler
|
|
20
|
+
# @param on_git_error [Proc, nil] callback invoked with the error message
|
|
21
|
+
# when a git command fails (nil silently swallows the error)
|
|
17
22
|
#
|
|
18
23
|
# @example Using the `-f` flag: `rvw -f ./file.rb`
|
|
19
24
|
# reviewer = Reviewer::Arguments::Files.new(provided: ['./file.rb'], keywords: [])
|
|
@@ -23,24 +28,22 @@ module Reviewer
|
|
|
23
28
|
# reviewer.to_a # => ['./file.rb','./directory/file.rb']
|
|
24
29
|
#
|
|
25
30
|
# @return [self]
|
|
26
|
-
def initialize(provided:
|
|
31
|
+
def initialize(provided: [], keywords: [], output: Output.new, on_git_error: nil)
|
|
27
32
|
@provided = Array(provided)
|
|
28
33
|
@keywords = Array(keywords)
|
|
34
|
+
@output = output
|
|
35
|
+
@on_git_error = on_git_error
|
|
29
36
|
end
|
|
30
37
|
|
|
31
38
|
# Provides the full list of file/path values derived from the command-line arguments
|
|
32
39
|
#
|
|
33
40
|
# @return [Array<String>] full collection of the file arguments as a string
|
|
34
|
-
def to_a
|
|
35
|
-
file_list
|
|
36
|
-
end
|
|
41
|
+
def to_a = file_list
|
|
37
42
|
|
|
38
43
|
# Provides the full list of file/path values derived from the command-line arguments
|
|
39
44
|
#
|
|
40
|
-
# @return [String] comma-separated string of the derived
|
|
41
|
-
def to_s
|
|
42
|
-
to_a.join(',')
|
|
43
|
-
end
|
|
45
|
+
# @return [String] comma-separated string of the derived file values
|
|
46
|
+
def to_s = to_a.join(',')
|
|
44
47
|
|
|
45
48
|
# Summary of the state of the file arguments
|
|
46
49
|
#
|
|
@@ -75,19 +78,43 @@ module Reviewer
|
|
|
75
78
|
return [] unless keywords.any?
|
|
76
79
|
|
|
77
80
|
keywords.map do |keyword|
|
|
78
|
-
|
|
81
|
+
method_name = keyword.to_sym
|
|
82
|
+
next unless respond_to?(method_name, true)
|
|
79
83
|
|
|
80
|
-
send(
|
|
84
|
+
send(method_name)
|
|
81
85
|
end.flatten.compact.uniq
|
|
82
86
|
end
|
|
83
87
|
|
|
84
|
-
# If `staged` is passed as a keyword via the command-line, this will get the list of staged
|
|
85
|
-
# files via Git
|
|
86
|
-
#
|
|
87
|
-
# @return [Array] list of the currently staged files
|
|
88
88
|
def staged
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
git_files(%w[diff --staged --name-only])
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def unstaged
|
|
93
|
+
git_files(%w[diff --name-only])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def modified
|
|
97
|
+
git_files(%w[diff --name-only HEAD])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def untracked
|
|
101
|
+
git_files(%w[ls-files --others --exclude-standard])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Executes a git command and returns the output as an array of file paths
|
|
105
|
+
# @param options [Array<String>] the git command options
|
|
106
|
+
#
|
|
107
|
+
# @return [Array<String>] the output lines from the command
|
|
108
|
+
def git_files(options)
|
|
109
|
+
command = (%w[git --no-pager] + options).join(' ')
|
|
110
|
+
stdout, stderr, status = Open3.capture3(command)
|
|
111
|
+
|
|
112
|
+
return stdout.split("\n").reject(&:empty?) if status.success?
|
|
113
|
+
|
|
114
|
+
raise SystemCallError.new("Git Error: #{stderr} (#{command})", status.exitstatus.to_i)
|
|
115
|
+
rescue SystemCallError => e
|
|
116
|
+
@on_git_error&.call(e.message)
|
|
117
|
+
[]
|
|
91
118
|
end
|
|
92
119
|
end
|
|
93
120
|
end
|
|
@@ -8,34 +8,37 @@ module Reviewer
|
|
|
8
8
|
# @!attribute provided
|
|
9
9
|
# @return [Array<String>] the keywords extracted from the command-line arguments
|
|
10
10
|
class Keywords
|
|
11
|
-
RESERVED = %w[staged].freeze
|
|
11
|
+
RESERVED = %w[staged unstaged modified untracked failed].freeze
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
attr_reader :provided
|
|
14
|
+
|
|
15
|
+
# Sets the tools collection after initialization when tools become available
|
|
16
|
+
# @param value [Tools] the configured tools collection
|
|
17
|
+
# @return [Tools] the tools collection
|
|
18
|
+
attr_writer :tools
|
|
14
19
|
|
|
15
20
|
alias raw provided
|
|
16
21
|
|
|
17
22
|
# Generates an instance of parsed keywords from the provided arguments
|
|
18
|
-
# @param
|
|
23
|
+
# @param provided [Array<String>] the leftover (non-flag) arguments from the command line
|
|
24
|
+
# @param tools [Tools] the collection of configured tools for keyword recognition
|
|
19
25
|
#
|
|
20
26
|
# @return [self]
|
|
21
|
-
def initialize(*provided)
|
|
27
|
+
def initialize(*provided, tools: nil)
|
|
22
28
|
@provided = Array(provided.flatten)
|
|
29
|
+
@tools = tools
|
|
23
30
|
end
|
|
24
31
|
|
|
25
|
-
#
|
|
32
|
+
# Provides the full list of raw keyword arguments explicitly passed via command-line as an array
|
|
26
33
|
#
|
|
27
|
-
# @return [Array] full collection of the provided keyword arguments
|
|
28
|
-
def to_a
|
|
29
|
-
provided
|
|
30
|
-
end
|
|
34
|
+
# @return [Array<String>] full collection of the provided keyword arguments
|
|
35
|
+
def to_a = provided
|
|
31
36
|
|
|
32
37
|
# Provides the full list of raw keyword arguments explicitly passed via command-line as a
|
|
33
38
|
# comma-separated string
|
|
34
39
|
#
|
|
35
|
-
# @return [String] comma-separated list of the
|
|
36
|
-
def to_s
|
|
37
|
-
to_a.join(',')
|
|
38
|
-
end
|
|
40
|
+
# @return [String] comma-separated list of the keyword arguments as a string
|
|
41
|
+
def to_s = to_a.join(',')
|
|
39
42
|
|
|
40
43
|
# Summary of the state of keyword arguments based on how Reviewer parsed them
|
|
41
44
|
#
|
|
@@ -53,52 +56,47 @@ module Reviewer
|
|
|
53
56
|
end
|
|
54
57
|
alias inspect to_h
|
|
55
58
|
|
|
59
|
+
# Whether the `failed` keyword was provided
|
|
60
|
+
#
|
|
61
|
+
# @return [Boolean] true if the `failed` keyword is present
|
|
62
|
+
def failed? = provided.include?('failed')
|
|
63
|
+
|
|
56
64
|
# Extracts reserved keywords from the provided arguments
|
|
57
65
|
#
|
|
58
66
|
# @return [Array<String>] intersection of provided arguments and reserved keywords
|
|
59
|
-
def reserved
|
|
60
|
-
intersection_with RESERVED
|
|
61
|
-
end
|
|
67
|
+
def reserved = intersection_with(RESERVED)
|
|
62
68
|
|
|
63
69
|
# Extracts keywords that match configured tags for enabled tools
|
|
64
70
|
#
|
|
65
71
|
# @return [Array<String>] intersection of provided arguments and configured tags for tools
|
|
66
|
-
def for_tags
|
|
67
|
-
intersection_with configured_tags
|
|
68
|
-
end
|
|
72
|
+
def for_tags = intersection_with(configured_tags)
|
|
69
73
|
|
|
70
74
|
# Extracts keywords that match configured tool keys
|
|
71
75
|
#
|
|
72
76
|
# @return [Array<String>] intersection of provided arguments and configured tool names
|
|
73
|
-
def for_tool_names
|
|
74
|
-
intersection_with configured_tool_names
|
|
75
|
-
end
|
|
77
|
+
def for_tool_names = intersection_with(configured_tool_names)
|
|
76
78
|
|
|
77
79
|
# Extracts keywords that match any possible recognized keyword values
|
|
78
80
|
#
|
|
79
81
|
# @return [Array<String>] intersection of provided arguments and recognizable keywords
|
|
80
|
-
def recognized
|
|
81
|
-
intersection_with possible
|
|
82
|
-
end
|
|
82
|
+
def recognized = intersection_with(possible)
|
|
83
83
|
|
|
84
84
|
# Extracts keywords that don't match any possible recognized keyword values
|
|
85
85
|
#
|
|
86
86
|
# @return [Array<String>] leftover keywords that weren't recognized
|
|
87
|
-
def unrecognized
|
|
88
|
-
(provided - recognized).uniq.sort
|
|
89
|
-
end
|
|
87
|
+
def unrecognized = (provided - recognized).uniq.sort
|
|
90
88
|
|
|
91
89
|
# Provides the complete list of all recognized keywords based on configuration
|
|
92
90
|
#
|
|
93
|
-
# @return [Array<String>] all keywords that Reviewer can
|
|
94
|
-
def possible
|
|
95
|
-
(RESERVED + configured_tags + configured_tool_names).uniq.sort
|
|
96
|
-
end
|
|
91
|
+
# @return [Array<String>] all keywords that Reviewer can recognize
|
|
92
|
+
def possible = (RESERVED + configured_tags + configured_tool_names).uniq.sort
|
|
97
93
|
|
|
98
94
|
# Provides the complete list of all configured tags for enabled tools
|
|
99
95
|
#
|
|
100
96
|
# @return [Array<String>] all unique configured tags
|
|
101
97
|
def configured_tags
|
|
98
|
+
return [] unless tools
|
|
99
|
+
|
|
102
100
|
tools.enabled.map(&:tags).flatten.uniq.sort
|
|
103
101
|
end
|
|
104
102
|
|
|
@@ -106,6 +104,8 @@ module Reviewer
|
|
|
106
104
|
#
|
|
107
105
|
# @return [Array<String>] all unique configured tools
|
|
108
106
|
def configured_tool_names
|
|
107
|
+
return [] unless tools
|
|
108
|
+
|
|
109
109
|
# We explicitly don't sort the tool names list because Reviewer uses the configuration order
|
|
110
110
|
# to determine the execution order. So not sorting maintains the predicted order it will run
|
|
111
111
|
# in and leaves the option to sort to the consuming code if needed
|
|
@@ -114,20 +114,13 @@ module Reviewer
|
|
|
114
114
|
|
|
115
115
|
private
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
# @return [Array<Reviewer::Tool>] collection of all currently enabled tools
|
|
120
|
-
def tools
|
|
121
|
-
@tools ||= Reviewer.tools
|
|
122
|
-
end
|
|
117
|
+
attr_reader :tools
|
|
123
118
|
|
|
124
119
|
# Syntactic sugar for finding intersections with valid keywords
|
|
125
120
|
# @param values [Array<String>] the collection to use for finding intersecting values
|
|
126
121
|
#
|
|
127
122
|
# @return [Array<String>] the list of intersecting values
|
|
128
|
-
def intersection_with(values)
|
|
129
|
-
(values & provided).uniq.sort
|
|
130
|
-
end
|
|
123
|
+
def intersection_with(values) = (values & provided).uniq.sort
|
|
131
124
|
end
|
|
132
125
|
end
|
|
133
126
|
end
|
|
@@ -4,15 +4,19 @@ module Reviewer
|
|
|
4
4
|
class Arguments
|
|
5
5
|
# Handles the logic of translating tag arguments
|
|
6
6
|
class Tags
|
|
7
|
-
|
|
7
|
+
# @!attribute provided
|
|
8
|
+
# @return [Array<String>] tags explicitly provided via -t or --tags flag
|
|
9
|
+
# @!attribute keywords
|
|
10
|
+
# @return [Array<String>] tags derived from keyword arguments
|
|
11
|
+
attr_reader :provided, :keywords
|
|
8
12
|
|
|
9
13
|
alias raw provided
|
|
10
14
|
|
|
11
|
-
# Generates an
|
|
15
|
+
# Generates an instance of parsed tags from the provided arguments by merging tag arguments
|
|
12
16
|
# that were provided via either flags or keywords
|
|
13
|
-
# @param provided
|
|
17
|
+
# @param provided [Array<String>] tag arguments provided
|
|
14
18
|
# directly via the -t or --tags flag on the command line.
|
|
15
|
-
# @param keywords
|
|
19
|
+
# @param keywords [Array, String] keywords that can potentially
|
|
16
20
|
# be translated to a list of tags based on the tags used in the configuration file
|
|
17
21
|
#
|
|
18
22
|
# @example Using keywords: `rvw ruby` (assuming a 'ruby' tag is defined)
|
|
@@ -23,7 +27,7 @@ module Reviewer
|
|
|
23
27
|
# Reviewer::Arguments::Tags.new.to_a # => ['css', 'ruby']
|
|
24
28
|
#
|
|
25
29
|
# @return [self]
|
|
26
|
-
def initialize(provided:
|
|
30
|
+
def initialize(provided: [], keywords: [])
|
|
27
31
|
@provided = Array(provided)
|
|
28
32
|
@keywords = Array(keywords)
|
|
29
33
|
end
|
|
@@ -31,16 +35,12 @@ module Reviewer
|
|
|
31
35
|
# Provides the full list of tags values derived from the command-line arguments
|
|
32
36
|
#
|
|
33
37
|
# @return [Array<String>] full collection of the tag arguments as a string
|
|
34
|
-
def to_a
|
|
35
|
-
tag_list
|
|
36
|
-
end
|
|
38
|
+
def to_a = tag_list
|
|
37
39
|
|
|
38
40
|
# Provides the full list of tag values derived from the command-line arguments
|
|
39
41
|
#
|
|
40
42
|
# @return [String] comma-separated string of the derived tag values
|
|
41
|
-
def to_s
|
|
42
|
-
to_a.join(',')
|
|
43
|
-
end
|
|
43
|
+
def to_s = to_a.join(',')
|
|
44
44
|
|
|
45
45
|
# Summary of the state of the tag arguments
|
|
46
46
|
#
|
data/lib/reviewer/arguments.rb
CHANGED
|
@@ -19,13 +19,18 @@ module Reviewer
|
|
|
19
19
|
# `rvw ruby staged`
|
|
20
20
|
#
|
|
21
21
|
class Arguments
|
|
22
|
-
|
|
22
|
+
# Valid output format options for the --format flag
|
|
23
|
+
KNOWN_FORMATS = %i[streaming summary json].freeze
|
|
24
|
+
|
|
25
|
+
# @!attribute options
|
|
26
|
+
# @return [Slop::Result] the parsed command-line options
|
|
27
|
+
attr_reader :options
|
|
23
28
|
|
|
24
29
|
attr_reader :output
|
|
25
30
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# @param
|
|
31
|
+
# Parses command-line arguments and makes them available as tags, files, and keywords.
|
|
32
|
+
# @param options [Array<String>] the command-line arguments to parse (defaults to ARGV)
|
|
33
|
+
# @param output [Output] the console output handler for displaying messages
|
|
29
34
|
#
|
|
30
35
|
# @example Using all options: `rvw keyword_one keyword_two --files ./example.rb,./example_test.rb --tags syntax`
|
|
31
36
|
# reviewer = Reviewer::Arguments.new
|
|
@@ -34,24 +39,40 @@ module Reviewer
|
|
|
34
39
|
# reviewer.keywords.to_a # => ['keyword_one', 'keyword_two']
|
|
35
40
|
#
|
|
36
41
|
# @return [self]
|
|
37
|
-
def initialize(options = ARGV)
|
|
38
|
-
@output =
|
|
39
|
-
@options = Slop.parse
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
def initialize(options = ARGV, output: Output.new)
|
|
43
|
+
@output = output
|
|
44
|
+
@options = Slop.parse(options) { |opts| configure_options(opts) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def configure_options(opts)
|
|
50
|
+
configure_input_options(opts)
|
|
51
|
+
configure_output_options(opts)
|
|
52
|
+
configure_info_options(opts)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def configure_input_options(opts)
|
|
56
|
+
opts.array '-f', '--files', 'a list of comma-separated files or paths', delimiter: ',', default: []
|
|
57
|
+
opts.array '-t', '--tags', 'a list of comma-separated tags', delimiter: ',', default: []
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def configure_output_options(opts)
|
|
61
|
+
opts.on '-r', '--raw', 'force raw output (no capturing)'
|
|
62
|
+
opts.on '-j', '--json', 'output results as JSON'
|
|
63
|
+
opts.string '--format', 'output format (streaming, summary, json)', default: 'streaming'
|
|
53
64
|
end
|
|
54
65
|
|
|
66
|
+
def configure_info_options(opts)
|
|
67
|
+
opts.on('-v', '--version', 'print the version')
|
|
68
|
+
opts.on('-h', '--help', 'print the help')
|
|
69
|
+
opts.on('-c', '--capabilities', 'output capabilities as JSON')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def session_formatter = @session_formatter ||= Session::Formatter.new(output)
|
|
73
|
+
|
|
74
|
+
public
|
|
75
|
+
|
|
55
76
|
# Converts the arguments to a hash for versatility
|
|
56
77
|
#
|
|
57
78
|
# @return [Hash] The files, tags, and keywords collected from the command line options
|
|
@@ -66,23 +87,73 @@ module Reviewer
|
|
|
66
87
|
|
|
67
88
|
# The tag arguments collected from the command line via the `-t` or `--tags` flag
|
|
68
89
|
#
|
|
69
|
-
# @return [Arguments::Tags]
|
|
70
|
-
def tags
|
|
71
|
-
@tags ||= Arguments::Tags.new(provided: options[:tags])
|
|
72
|
-
end
|
|
90
|
+
# @return [Arguments::Tags] a collection of the tag arguments collected from the command-line
|
|
91
|
+
def tags = @tags ||= Arguments::Tags.new(provided: options[:tags])
|
|
73
92
|
|
|
74
93
|
# The file arguments collected from the command line via the `-f` or `--files` flag
|
|
75
94
|
#
|
|
76
|
-
# @return [Arguments::Files]
|
|
95
|
+
# @return [Arguments::Files] a collection of the file arguments collected from the command-line
|
|
77
96
|
def files
|
|
78
|
-
@files ||= Arguments::Files.new(
|
|
97
|
+
@files ||= Arguments::Files.new(
|
|
98
|
+
provided: options[:files],
|
|
99
|
+
keywords: keywords.reserved,
|
|
100
|
+
output: output,
|
|
101
|
+
on_git_error: session_formatter.method(:git_error)
|
|
102
|
+
)
|
|
79
103
|
end
|
|
80
104
|
|
|
81
105
|
# The leftover arguments collected from the command line without being associated with a flag
|
|
82
106
|
#
|
|
83
|
-
# @return [Arguments::Keywords]
|
|
84
|
-
def keywords
|
|
85
|
-
|
|
107
|
+
# @return [Arguments::Keywords] a collection of the leftover arguments as keywords
|
|
108
|
+
def keywords = @keywords ||= Arguments::Keywords.new(options.arguments)
|
|
109
|
+
|
|
110
|
+
# Whether the --help flag was passed
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean] true if help was requested
|
|
113
|
+
def help? = options[:help]
|
|
114
|
+
|
|
115
|
+
# Whether the --version flag was passed
|
|
116
|
+
#
|
|
117
|
+
# @return [Boolean] true if version was requested
|
|
118
|
+
def version? = options[:version]
|
|
119
|
+
|
|
120
|
+
# Whether to force raw/passthrough output regardless of tool count
|
|
121
|
+
#
|
|
122
|
+
# @return [Boolean] true if raw output mode is requested
|
|
123
|
+
def raw? = options[:raw]
|
|
124
|
+
|
|
125
|
+
# Whether to output results as JSON
|
|
126
|
+
#
|
|
127
|
+
# @return [Boolean] true if JSON output mode is requested
|
|
128
|
+
def json? = options[:json]
|
|
129
|
+
|
|
130
|
+
# The output format for results
|
|
131
|
+
#
|
|
132
|
+
# @return [Symbol] the output format (:streaming, :summary, or :json)
|
|
133
|
+
def format
|
|
134
|
+
return :json if json?
|
|
135
|
+
|
|
136
|
+
value = options[:format].to_sym
|
|
137
|
+
return value if KNOWN_FORMATS.include?(value)
|
|
138
|
+
|
|
139
|
+
session_formatter.invalid_format(options[:format], KNOWN_FORMATS)
|
|
140
|
+
:streaming
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Whether output should be streamed directly (not captured for later formatting)
|
|
144
|
+
#
|
|
145
|
+
# @return [Boolean] true if in streaming mode
|
|
146
|
+
def streaming? = format == :streaming
|
|
147
|
+
|
|
148
|
+
# Determines the appropriate runner strategy based on CLI flags
|
|
149
|
+
#
|
|
150
|
+
# @param multiple_tools [Boolean] whether multiple tools are being run
|
|
151
|
+
# @return [Class] the strategy class (Captured or Passthrough)
|
|
152
|
+
def runner_strategy(multiple_tools:)
|
|
153
|
+
return Runner::Strategies::Passthrough if raw?
|
|
154
|
+
return Runner::Strategies::Captured unless streaming?
|
|
155
|
+
|
|
156
|
+
multiple_tools ? Runner::Strategies::Captured : Runner::Strategies::Passthrough
|
|
86
157
|
end
|
|
87
158
|
end
|
|
88
159
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../output/formatting'
|
|
4
|
+
|
|
5
|
+
module Reviewer
|
|
6
|
+
class Batch
|
|
7
|
+
# Display logic for batch execution: summary, run preview, missing tools
|
|
8
|
+
class Formatter
|
|
9
|
+
include Output::Formatting
|
|
10
|
+
|
|
11
|
+
attr_reader :output, :printer
|
|
12
|
+
private :output, :printer
|
|
13
|
+
|
|
14
|
+
# Creates a formatter for batch execution display
|
|
15
|
+
# @param output [Output] the console output handler
|
|
16
|
+
#
|
|
17
|
+
# @return [Formatter]
|
|
18
|
+
def initialize(output)
|
|
19
|
+
@output = output
|
|
20
|
+
@printer = output.printer
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Displays a one-line success summary with timing and tool count
|
|
24
|
+
# @param tool_count [Integer] the number of tools that ran
|
|
25
|
+
# @param seconds [Float] total elapsed time in seconds
|
|
26
|
+
#
|
|
27
|
+
# @return [void]
|
|
28
|
+
def summary(tool_count, seconds)
|
|
29
|
+
output.newline
|
|
30
|
+
printer.print(:success, CHECKMARK)
|
|
31
|
+
printer.print(:muted, " ~#{seconds.round(1)} seconds")
|
|
32
|
+
printer.print(:muted, " for #{tool_count} tools") if tool_count > 1
|
|
33
|
+
output.newline
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Displays a preview of which tools will run and their target files
|
|
37
|
+
# @param entries [Array<Hash>] each with :name and :files keys
|
|
38
|
+
#
|
|
39
|
+
# @return [void]
|
|
40
|
+
def run_summary(entries)
|
|
41
|
+
return if entries.empty?
|
|
42
|
+
|
|
43
|
+
entries.each { |entry| print_run_entry(entry) }
|
|
44
|
+
output.newline
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Displays a list of tools whose executables were not found, with install hints
|
|
48
|
+
# @param missing [Array<Runner::Result>] the results for missing tools
|
|
49
|
+
# @param tools [Array<Tool>] the tools that were in the batch
|
|
50
|
+
#
|
|
51
|
+
# @return [void]
|
|
52
|
+
def missing_tools(missing, tools:)
|
|
53
|
+
output.newline
|
|
54
|
+
printer.puts(:warning, "#{missing.size} not installed:")
|
|
55
|
+
tool_lookup = tools.to_h { |tool| [tool.key, tool] }
|
|
56
|
+
missing.each { |result| print_missing_hint(result.tool_name, tool_lookup[result.tool_key]) }
|
|
57
|
+
output.newline
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Displays a message when `rvw failed` is used but no tools failed in the last run
|
|
61
|
+
#
|
|
62
|
+
# @return [void]
|
|
63
|
+
def no_failures_to_retry
|
|
64
|
+
printer.puts(:muted, 'No failures to retry')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Displays a message when `rvw failed` is used but no previous run exists in history
|
|
68
|
+
#
|
|
69
|
+
# @return [void]
|
|
70
|
+
def no_previous_run
|
|
71
|
+
printer.puts(:muted, 'No previous run found')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def print_missing_hint(name, tool)
|
|
77
|
+
hint = tool&.installable? ? tool.install_command : ''
|
|
78
|
+
printer.puts(:muted, " #{name.ljust(22)}#{hint}")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def print_run_entry(entry)
|
|
82
|
+
printer.puts(:muted, entry[:name])
|
|
83
|
+
entry[:files].each { |file| printer.puts(:muted, " #{file}") }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|