Skip to content

Commit d29357c

Browse files
authored
[Fix #9122] Add suggestion if any gems are loaded that have rubocop extensions (#9130)
The suggestion can be disabled by setting `AllCops/SuggestExtensions: false`
1 parent a9772af commit d29357c

9 files changed

+95
-2
lines changed

.rubocop.yml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ AllCops:
1515
- '.git/**/*'
1616
- 'bin/*'
1717
TargetRubyVersion: 2.4
18+
SuggestExtensions: false
1819

1920
Naming/PredicateName:
2021
# Method define macros for dynamically generated method.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#9122](https://github.com/rubocop-hq/rubocop/issues/9122): Added tip message if any gems are loaded that have RuboCop extensions. ([@dvandersluis][])

config/default.yml

+10
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ AllCops:
139139
# from the lock file.) If the Ruby version is still unresolved, RuboCop will
140140
# use the oldest officially supported Ruby version (currently Ruby 2.4).
141141
TargetRubyVersion: ~
142+
# Determines if a notification for extension libraries should be shown when
143+
# rubocop is run. Keys are the name of the extension, and values are an array
144+
# of gems in the Gemfile that the extension is suggested for, if not already
145+
# included.
146+
SuggestExtensions:
147+
rubocop-rails: [rails]
148+
rubocop-rspec: [rspec, rspec-rails]
149+
rubocop-minitest: [minitest]
150+
rubocop-sequel: [sequel]
151+
rubocop-rake: [rake]
142152

143153
#################### Bundler ###############################
144154

lib/rubocop.rb

+1
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@
649649
require_relative 'rubocop/cli/command/execute_runner'
650650
require_relative 'rubocop/cli/command/init_dotfile'
651651
require_relative 'rubocop/cli/command/show_cops'
652+
require_relative 'rubocop/cli/command/suggest_extensions'
652653
require_relative 'rubocop/cli/command/version'
653654
require_relative 'rubocop/config_regeneration'
654655
require_relative 'rubocop/options'

lib/rubocop/cli.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,14 @@ def execute_runners
6969
if @options[:auto_gen_config]
7070
run_command(:auto_gen_config)
7171
else
72-
run_command(:execute_runner)
72+
run_command(:execute_runner).tap { suggest_extensions }
7373
end
7474
end
7575

76+
def suggest_extensions
77+
run_command(:suggest_extensions)
78+
end
79+
7680
def validate_options_vs_config
7781
if @options[:parallel] &&
7882
!@config_store.for_pwd.for_all_cops['UseCache']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
class CLI
5+
module Command
6+
# Run all the selected cops and report the result.
7+
# @api private
8+
class SuggestExtensions < Base
9+
# Combination of short and long formatter names.
10+
INCLUDED_FORMATTERS = %w[p progress fu fuubar pa pacman].freeze
11+
12+
self.command_name = :suggest_extensions
13+
14+
def run
15+
return if skip? || extensions.none?
16+
17+
puts
18+
puts 'Tip: Based on detected gems, the following '\
19+
'RuboCop extension libraries might be helpful:'
20+
21+
extensions.each do |extension|
22+
puts " * #{extension} (http://github.com/rubocop-hq/#{extension})"
23+
end
24+
25+
puts
26+
puts 'You can opt out of this message by adding the following to your config:'
27+
puts ' AllCops:'
28+
puts ' SuggestExtensions: false'
29+
puts if @options[:display_time]
30+
end
31+
32+
private
33+
34+
def skip?
35+
# Disable outputting the notification:
36+
# 1. On CI
37+
# 2. When given RuboCop options that it doesn't make sense for
38+
# 3. For all formatters except specified in `INCLUDED_FORMATTERS'`
39+
ENV['CI'] ||
40+
@options[:only] || @options[:debug] || @options[:list_target_files] || @options[:out] ||
41+
!INCLUDED_FORMATTERS.include?(current_formatter)
42+
end
43+
44+
def current_formatter
45+
@options[:format] || @config_store.for_pwd.for_all_cops['DefaultFormatter'] || 'p'
46+
end
47+
48+
def extensions
49+
extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions']
50+
return [] unless extensions
51+
52+
extensions.select { |_, v| (v & dependent_gems).any? }.keys - dependent_gems
53+
end
54+
55+
def dependent_gems
56+
# This only includes gems in Gemfile, not in lockfile
57+
Bundler.load.dependencies.map(&:name)
58+
end
59+
60+
def puts(*args)
61+
output = (@options[:stderr] ? $stderr : $stdout)
62+
output.puts(*args)
63+
end
64+
end
65+
end
66+
end
67+
end

lib/rubocop/config_loader_resolver.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def merge(base_hash, derived_hash, **opts)
9292
keys_appearing_in_both.each do |key|
9393
if opts[:unset_nil] && derived_hash[key].nil?
9494
result.delete(key)
95-
elsif base_hash[key].is_a?(Hash)
95+
elsif merge_hashes?(base_hash, derived_hash, key)
9696
result[key] = merge(base_hash[key], derived_hash[key], **opts)
9797
elsif should_union?(base_hash, key, opts[:inherit_mode])
9898
result[key] = base_hash[key] | derived_hash[key]
@@ -164,6 +164,10 @@ def should_union?(base_hash, key, inherit_mode)
164164
inherit_mode['merge'].include?(key)
165165
end
166166

167+
def merge_hashes?(base_hash, derived_hash, key)
168+
base_hash[key].is_a?(Hash) && derived_hash[key].is_a?(Hash)
169+
end
170+
167171
def base_configs(path, inherit_from, file)
168172
configs = Array(inherit_from).compact.map do |f|
169173
ConfigLoader.load_file(inherited_file(path, f, file))

spec/rubocop/cli/cli_autocorrect_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
before do
99
RuboCop::ConfigLoader.default_configuration = nil
10+
RuboCop::ConfigLoader.default_configuration.for_all_cops['SuggestExtensions'] = false
1011
end
1112

1213
it 'does not correct ExtraSpacing in a hash that would be changed back' do

spec/rubocop/cli/cli_options_spec.rb

+4
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,10 @@ class SomeCop < Cop
766766
end
767767

768768
describe '-d/--debug' do
769+
before do
770+
RuboCop::ConfigLoader.default_configuration = nil
771+
end
772+
769773
it 'shows config files' do
770774
create_file('example1.rb', "\tputs 0")
771775
expect(cli.run(['--debug', 'example1.rb'])).to eq(1)

0 commit comments

Comments
 (0)