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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/main.yml +79 -11
  4. data/.github/workflows/release.yml +98 -0
  5. data/.gitignore +1 -1
  6. data/.inch.yml +3 -1
  7. data/.reek.yml +175 -0
  8. data/.reviewer.example.yml +7 -2
  9. data/.reviewer.yml +166 -40
  10. data/.rubocop.yml +34 -2
  11. data/CHANGELOG.md +42 -2
  12. data/Gemfile +39 -1
  13. data/Gemfile.lock +291 -70
  14. data/LICENSE.txt +20 -4
  15. data/README.md +310 -21
  16. data/RELEASING.md +190 -0
  17. data/Rakefile +117 -0
  18. data/dependency_decisions.yml +61 -0
  19. data/exe/fmt +1 -1
  20. data/exe/rvw +1 -1
  21. data/lib/reviewer/arguments/files.rb +47 -20
  22. data/lib/reviewer/arguments/keywords.rb +34 -41
  23. data/lib/reviewer/arguments/tags.rb +11 -11
  24. data/lib/reviewer/arguments.rb +100 -29
  25. data/lib/reviewer/batch/formatter.rb +87 -0
  26. data/lib/reviewer/batch.rb +32 -48
  27. data/lib/reviewer/capabilities.rb +81 -0
  28. data/lib/reviewer/command/string/env.rb +12 -6
  29. data/lib/reviewer/command/string/flags.rb +2 -4
  30. data/lib/reviewer/command/string.rb +47 -12
  31. data/lib/reviewer/command.rb +65 -10
  32. data/lib/reviewer/configuration/loader.rb +70 -0
  33. data/lib/reviewer/configuration.rb +6 -3
  34. data/lib/reviewer/context.rb +15 -0
  35. data/lib/reviewer/doctor/config_check.rb +46 -0
  36. data/lib/reviewer/doctor/environment_check.rb +58 -0
  37. data/lib/reviewer/doctor/formatter.rb +75 -0
  38. data/lib/reviewer/doctor/keyword_check.rb +85 -0
  39. data/lib/reviewer/doctor/opportunity_check.rb +88 -0
  40. data/lib/reviewer/doctor/report.rb +63 -0
  41. data/lib/reviewer/doctor/tool_inventory.rb +41 -0
  42. data/lib/reviewer/doctor.rb +28 -0
  43. data/lib/reviewer/history.rb +10 -17
  44. data/lib/reviewer/output/formatting.rb +40 -0
  45. data/lib/reviewer/output/printer.rb +70 -9
  46. data/lib/reviewer/output.rb +37 -78
  47. data/lib/reviewer/prompt.rb +38 -0
  48. data/lib/reviewer/report/formatter.rb +124 -0
  49. data/lib/reviewer/report.rb +100 -0
  50. data/lib/reviewer/runner/failed_files.rb +66 -0
  51. data/lib/reviewer/runner/formatter.rb +103 -0
  52. data/lib/reviewer/runner/guidance.rb +79 -0
  53. data/lib/reviewer/runner/result.rb +150 -0
  54. data/lib/reviewer/runner/strategies/captured.rb +98 -23
  55. data/lib/reviewer/runner/strategies/passthrough.rb +2 -11
  56. data/lib/reviewer/runner.rb +126 -40
  57. data/lib/reviewer/session/formatter.rb +87 -0
  58. data/lib/reviewer/session.rb +208 -0
  59. data/lib/reviewer/setup/catalog.rb +233 -0
  60. data/lib/reviewer/setup/detector.rb +61 -0
  61. data/lib/reviewer/setup/formatter.rb +94 -0
  62. data/lib/reviewer/setup/gemfile_lock.rb +55 -0
  63. data/lib/reviewer/setup/generator.rb +54 -0
  64. data/lib/reviewer/setup/tool_block.rb +112 -0
  65. data/lib/reviewer/setup.rb +41 -0
  66. data/lib/reviewer/shell/result.rb +14 -15
  67. data/lib/reviewer/shell/timer.rb +40 -35
  68. data/lib/reviewer/shell.rb +41 -12
  69. data/lib/reviewer/tool/conversions.rb +20 -0
  70. data/lib/reviewer/tool/file_resolver.rb +54 -0
  71. data/lib/reviewer/tool/settings.rb +88 -44
  72. data/lib/reviewer/tool/test_file_mapper.rb +73 -0
  73. data/lib/reviewer/tool/timing.rb +78 -0
  74. data/lib/reviewer/tool.rb +88 -69
  75. data/lib/reviewer/tools.rb +47 -33
  76. data/lib/reviewer/version.rb +1 -1
  77. data/lib/reviewer.rb +109 -50
  78. data/reviewer.gemspec +16 -19
  79. metadata +101 -142
  80. data/lib/reviewer/conversions.rb +0 -16
  81. data/lib/reviewer/guidance.rb +0 -77
  82. data/lib/reviewer/keywords/git/staged.rb +0 -64
  83. data/lib/reviewer/keywords/git.rb +0 -14
  84. data/lib/reviewer/keywords.rb +0 -9
  85. data/lib/reviewer/loader.rb +0 -59
  86. data/lib/reviewer/output/scrubber.rb +0 -48
  87. data/lib/reviewer/output/token.rb +0 -85
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reviewer
4
- VERSION = '0.1.5'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/reviewer.rb CHANGED
@@ -5,86 +5,82 @@ require 'forwardable'
5
5
  # require 'logger'
6
6
  require 'rainbow'
7
7
 
8
- require_relative 'reviewer/conversions'
8
+ require_relative 'reviewer/configuration'
9
+ require_relative 'reviewer/configuration/loader'
10
+ require_relative 'reviewer/context'
11
+ require_relative 'reviewer/history'
12
+ require_relative 'reviewer/tool'
13
+ require_relative 'reviewer/tools'
9
14
 
10
15
  require_relative 'reviewer/arguments'
11
16
  require_relative 'reviewer/batch'
17
+ require_relative 'reviewer/capabilities'
12
18
  require_relative 'reviewer/command'
13
- require_relative 'reviewer/configuration'
14
- require_relative 'reviewer/guidance'
15
- require_relative 'reviewer/history'
16
- require_relative 'reviewer/keywords'
17
- require_relative 'reviewer/loader'
18
19
  require_relative 'reviewer/output'
20
+ require_relative 'reviewer/prompt'
21
+ require_relative 'reviewer/report'
19
22
  require_relative 'reviewer/runner'
23
+ require_relative 'reviewer/session'
20
24
  require_relative 'reviewer/shell'
21
- require_relative 'reviewer/tool'
22
- require_relative 'reviewer/tools'
25
+ require_relative 'reviewer/setup'
26
+ require_relative 'reviewer/doctor'
23
27
  require_relative 'reviewer/version'
24
28
 
25
29
  # Primary interface for the reviewer tools
26
30
  module Reviewer
31
+ # Base error class for all Reviewer errors
27
32
  class Error < StandardError; end
28
33
 
29
34
  class << self
30
- # Resets the loaded tools
31
- def reset!
32
- @tools = nil
33
- end
35
+ # Resets the loaded tools and arguments
36
+ def reset! = @tools = @arguments = @prompt = @output = @history = @configuration = nil
34
37
 
35
38
  # Runs the `review` command for the specified tools/files. Reviewer expects all configured
36
39
  # commands that are not disabled to have an entry for the `review` command.
37
- # @param clear_screen [boolean] clears the screen to reduce noise when true
38
40
  #
39
41
  # @return [void] Prints output to the console
40
- def review(clear_screen: false)
41
- perform(:review, clear_screen: clear_screen)
42
+ def review
43
+ handle_early_exits { exit build_session.review }
42
44
  end
43
45
 
44
46
  # Runs the `format` command for the specified tools/files for which it is configured.
45
- # @param clear_screen [boolean] clears the screen to reduce noise when true
46
47
  #
47
48
  # @return [void] Prints output to the console
48
- def format(clear_screen: false)
49
- perform(:format, clear_screen: clear_screen)
49
+ def format
50
+ handle_early_exits { exit build_session.format }
50
51
  end
51
52
 
52
53
  # The collection of arguments that were passed via the command line.
53
54
  #
54
55
  # @return [Reviewer::Arguments] exposes tags, files, and keywords from arguments
55
- def arguments
56
- @arguments ||= Arguments.new
57
- end
56
+ def arguments = @arguments ||= Arguments.new
58
57
 
59
58
  # An interface for the collection of configured tools for accessing subsets of tools
60
59
  # based on enabled/disabled, tags, keywords, etc.
61
60
  #
62
61
  # @return [Reviewer::Tools] exposes the set of tools to be run in a given context
63
- def tools
64
- @tools ||= Tools.new
65
- end
62
+ def tools = @tools ||= Tools.new(arguments: arguments, history: history, config_file: configuration.file)
66
63
 
67
64
  # The primary output method for Reviewer to consistently display success/failure details for a
68
65
  # unique run of each tool and the collective summary when relevant.
69
66
  #
70
67
  # @return [Reviewer::Output] prints formatted output to the console.
71
- def output
72
- @output ||= Output.new
73
- end
68
+ def output = @output ||= Output.new
74
69
 
75
70
  # A file store for sharing information across runs
76
71
  #
77
72
  # @return [Reviewer::History] a YAML::Store (or Pstore) containing data on tools
78
- def history
79
- @history ||= History.new
80
- end
73
+ def history = @history ||= History.new(file: configuration.history_file)
74
+
75
+ # An interactive prompt for yes/no questions
76
+ #
77
+ # @return [Reviewer::Prompt] prompt instance wrapping stdin/stdout
78
+ def prompt = @prompt ||= Prompt.new
81
79
 
82
80
  # Exposes the configuration options for Reviewer.
83
81
  #
84
82
  # @return [Reviewer::Configuration] configuration settings instance
85
- def configuration
86
- @configuration ||= Configuration.new
87
- end
83
+ def configuration = @configuration ||= Configuration.new
88
84
 
89
85
  # A block approach to configuring Reviewer.
90
86
  #
@@ -94,28 +90,91 @@ module Reviewer
94
90
  # end
95
91
  #
96
92
  # @return [Reviewer::Configuration] Reviewer configuration settings
97
- def configure
98
- yield(configuration)
99
- end
93
+ def configure = yield(configuration)
100
94
 
101
95
  private
102
96
 
103
- # Provides a consistent approach to running and benchmarking commmands and preventing further
104
- # execution of later tools if a command fails.
105
- # @param command_type [Symbol] the specific command to run for each tool
106
- # @param clear_screen [Boolean] if true, clears the screen before a run
107
- #
108
- # @example Run the `review` command for each relevant tool
109
- # perform(:review)
110
- #
111
- # @return [Hash] the exit status (in integer format) for each command run
112
- def perform(command_type, clear_screen: false)
113
- output.clear if clear_screen
97
+ def handle_early_exits
98
+ return show_help if arguments.help?
99
+ return show_version if arguments.version?
100
+ return Setup.run if subcommand?(:init)
101
+ return run_doctor if subcommand?(:doctor)
102
+ return run_capabilities if capabilities_flag?
103
+ return run_first_time_setup unless configuration.file.exist?
104
+
105
+ yield
106
+ end
114
107
 
115
- results = Batch.new(command_type, tools.current).run
108
+ def subcommand?(name) = ARGV.first == name.to_s
109
+ def capabilities_flag? = ARGV.include?('--capabilities') || ARGV.include?('-c')
110
+
111
+ def show_help
112
+ output.help(help_text)
113
+ end
114
+
115
+ def help_text
116
+ <<~HELP
117
+ Usage: rvw [tool or tag ...] [keyword ...] [options]
118
+ fmt [tool or tag ...] [keyword ...] [options]
119
+
120
+ Commands:
121
+ rvw Run all enabled tools
122
+ rvw <tool> Run a single tool by its config key
123
+ rvw <tag> Run tools matching a tag
124
+ fmt Auto-fix with format commands
125
+ rvw init Generate .reviewer.yml from Gemfile.lock
126
+ rvw doctor Check configuration and tool health
127
+
128
+ Keywords:
129
+ staged Files staged for commit
130
+ unstaged Files with unstaged changes
131
+ modified All changed files (staged + unstaged)
132
+ untracked New files not yet tracked by git
133
+ failed Re-run only tools that failed last time
134
+
135
+ Options:
136
+ #{slop_options}
137
+
138
+ Examples:
139
+ rvw rubocop Run RuboCop only
140
+ rvw staged Review staged files across all tools
141
+ rvw -t security modified Run security-tagged tools on changed files
142
+ rvw tests -f test/user_test.rb Run tests on a specific file
143
+ rvw failed Re-run what failed last time
144
+ fmt rubocop Auto-fix with RuboCop
145
+ HELP
146
+ end
147
+
148
+ def slop_options
149
+ arguments.options.to_s.lines.drop(1).join.rstrip
150
+ end
151
+
152
+ def show_version
153
+ output.help(VERSION)
154
+ end
155
+
156
+ def run_capabilities
157
+ puts Capabilities.new(tools: tools).to_json
158
+ end
159
+
160
+ def run_doctor
161
+ report = Doctor.run(configuration: configuration, tools: tools)
162
+ Doctor::Formatter.new(output).print(report)
163
+ end
164
+
165
+ def run_first_time_setup
166
+ formatter = Setup::Formatter.new(output)
167
+ formatter.first_run_greeting
168
+ if prompt.yes?('Would you like to set it up now?')
169
+ Setup.run(configuration: configuration)
170
+ else
171
+ formatter.first_run_skip
172
+ end
173
+ end
116
174
 
117
- # Return the largest exit status
118
- exit results.values.max
175
+ def build_session
176
+ context = Context.new(arguments: arguments, output: output, history: history)
177
+ Session.new(context: context, tools: tools)
119
178
  end
120
179
  end
121
180
  end
data/reviewer.gemspec CHANGED
@@ -8,11 +8,13 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['Garrett Dimon']
9
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.'
11
+ spec.summary = 'Frictionless code quality. One command for all your review tools.'
12
+ spec.description = 'Run tests, linters, security audits, and formatters with a single command. ' \
13
+ 'Reviewer wraps your code quality tools into a consistent interface with ' \
14
+ 'git-aware file targeting, auto-detection, and multiple output formats.'
13
15
  spec.homepage = 'https://github.com/garrettdimon/reviewer'
14
16
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.9')
17
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.2')
16
18
 
17
19
  spec.metadata['homepage_uri'] = spec.homepage
18
20
  spec.metadata['bug_tracker_uri'] = 'https://github.com/garrettdimon/reviewer/issues'
@@ -31,21 +33,16 @@ Gem::Specification.new do |spec|
31
33
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
34
  spec.require_paths = ['lib']
33
35
 
34
- spec.add_dependency 'rainbow'
35
- spec.add_dependency 'slop'
36
+ spec.add_dependency 'benchmark', '~> 0.5'
37
+ spec.add_dependency 'pstore', '~> 0.2'
38
+ spec.add_dependency 'rainbow', '~> 3.1'
39
+ spec.add_dependency 'ruby-progressbar', '~> 1.13'
40
+ spec.add_dependency 'slop', '~> 4.10'
36
41
 
37
- spec.add_development_dependency 'bundler-audit'
38
- spec.add_development_dependency 'codecov'
39
- spec.add_development_dependency 'flay'
40
- spec.add_development_dependency 'flog'
41
- spec.add_development_dependency 'inch'
42
- spec.add_development_dependency 'minitest'
43
- spec.add_development_dependency 'minitest-heat'
44
- spec.add_development_dependency 'psych'
45
- spec.add_development_dependency 'reek'
46
- spec.add_development_dependency 'rubocop'
47
- spec.add_development_dependency 'rubocop-minitest'
48
- spec.add_development_dependency 'rubocop-rake'
49
- spec.add_development_dependency 'simplecov'
50
- spec.add_development_dependency 'yard'
42
+ spec.add_development_dependency 'minitest', '~> 5.27'
43
+ spec.add_development_dependency 'minitest-heat', '~> 2.1'
44
+ spec.add_development_dependency 'rdoc', '~> 7.1'
45
+ spec.add_development_dependency 'simplecov', '~> 0.22'
46
+ spec.add_development_dependency 'simplecov_json_formatter', '~> 0.1'
47
+ spec.add_development_dependency 'yard', '~> 0.9'
51
48
  end