rubocop_plus 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ # Temporarily disable. This cop has many false positives.
2
+ Style/AccessModifierDeclarations:
3
+ Enabled: false
4
+
5
+ # In ruby, you can define modules and classes like this:
6
+ #
7
+ # = Nested = = Compact =
8
+ # class Foo or class Foo::Bar
9
+ # class Bar end
10
+ # end
11
+ # end
12
+ #
13
+ # Style/ClassAndModuleChildren instructs rubocop to prefer 'nested' or 'compact'. The default is 'nested', but Rails typically uses
14
+ # 'compact'. Both are valid and useful strategies and there's no reason to strictly enforce one over the other.
15
+ # See https://github.com/roberts1000/rubocop_plus/issues/24
16
+ Style/ClassAndModuleChildren:
17
+ Enabled: false
18
+
19
+ # Style/EmptyMethod checks the formatting of empty methods. There are two formatting options:
20
+ #
21
+ # = expanded = vs = compact =
22
+ # def foo def foo; end
23
+ # end
24
+ #
25
+ # rubocop uses the `compact` style by default. rubocop_plus prefers the `expanded` style since it used by Rails and appears to be
26
+ # more common.
27
+ Style/EmptyMethod:
28
+ EnforcedStyle: expanded
29
+
30
+ # Frozen strings are a new feature (as of Ruby 2.3) and may become the default in a future version of Ruby. Disable this cop
31
+ # until more is known.
32
+ Style/FrozenStringLiteralComment:
33
+ Enabled: false
34
+
35
+ # Style/HashSyntax checks how hash are created. There are many ways to create a hash and they all have valid use cases. This cop has
36
+ # been disabled since it's hard to use a consistent strategy.
37
+ Style/HashSyntax:
38
+ Enabled: false
39
+
40
+ # Style/MixinUsage checks that "include" statements do not appear in the global namespace. Some 3rd party files violate this so
41
+ # we'll ignore them.
42
+ Style/MixinUsage:
43
+ Exclude:
44
+ - bin/update
45
+ - bin/setup
46
+ - spec/dummy/bin/update
47
+ - spec/dummy/bin/setup
48
+
49
+ # Style/PreferredHashMethods checks if hash methods like 'has_key?' or 'has_value?' are called, then recommends they be switched
50
+ # to 'key?' and 'value?'. rubocop_plus perfers the use of predicates on method names since they make the code questions more
51
+ # precise. Also, the Naming/PredicateName cop has been disabled in this file and that cop checks for a similar
52
+ # pattern on custom methods. For consistency, the more verbose form (like 'has_key?') is preferred when working with Hashes.
53
+ Style/PreferredHashMethods:
54
+ EnforcedStyle: verbose
55
+
56
+ # Style/StringLiterals enforces the use of single quotes around string literals. The major argument for using single quotes is
57
+ # they should be faster than double quotes (which need to be parsed for possible uses of interpolation). Also, they help reveal
58
+ # intention by alerting developers that there is no interpolation in the string. However, there is no performance difference
59
+ # between using single and double quoted strings (https://www.viget.com/articles/just-use-double-quoted-ruby-strings) and
60
+ # we consider any semantic advantages to be not worth the effort. We have disabled this cop and advocate that developers
61
+ # "try" to be consistent within an individual file.
62
+ Style/StringLiterals:
63
+ Enabled: false
64
+
65
+ # Style/SingleLineBlockParams requires parameters to have standard names in blocks. rubocop considers the following to be bad:
66
+ #
67
+ # [1, 2, 3].inject(0) { |sum, a| sum + a }
68
+ #
69
+ # Instead, this is preferred
70
+ #
71
+ # [1, 2, 3].inject(0) { |acc, elem| acc + elem }
72
+ #
73
+ # "acc" means "acc"umulator and "e" means "elem"ent. Forcing everyone to use the same variable names does standardizes things,
74
+ # but it can decrease readability. Unique variable names which impart meaning are better.
75
+ Style/SingleLineBlockParams:
76
+ Enabled: false
77
+
78
+ # Style/StderrPuts suggests using `warn` over `$stderr.puts`. Some 3rd party files violate this so we'll ignore them.
79
+ Style/StderrPuts:
80
+ Exclude:
81
+ - bin/yarn
82
+ - spec/dummy/bin/yarn
83
+
84
+ # Style/SymbolArray checks if %i or %I are used to create symbol arrays. rubocop recommends
85
+ #
86
+ # = Good = = Bad =
87
+ # %i[foo bar] [:foo, :bar]
88
+ #
89
+ # The direct symbol form is easier to read and follows Rails.
90
+ Style/SymbolArray:
91
+ Enabled: false
@@ -0,0 +1,22 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rails
4
+ - rubocop-rspec
5
+
6
+ AllCops:
7
+ Exclude: # skip all of the following....
8
+ - db/schema.rb # An auto-generated file
9
+ - spec/dummy/db/schema.rb # An auto-generated file
10
+ - lib/tasks/cucumber.rake # A 3rd-party auto-generated file
11
+ - vendor/**/* # Contains 3rd party libs; no need to check code that originated outside the project
12
+ - node_modules/**/* # Yarn 3rd party dependencies; no need to check code that originated outside the project
13
+ - client/**/* # It's mostly JavaScript, but it may contain 3rd party that was written outside of the project
14
+
15
+ inherit_from:
16
+ - group/layout.yml
17
+ - group/lint.yml
18
+ - group/metrics.yml
19
+ - group/naming.yml
20
+ - group/rails.yml
21
+ - group/rspec.yml
22
+ - group/style.yml
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script runs rubocop with some default output specifications. Output is written to a 'rubocop/' folder into the root
4
+ # of an application. This script can be invoked by running the following commands in the root of a ruby gem, rails engine
5
+ # or rails application:
6
+ #
7
+ # EXECUTION
8
+ #
9
+ # rubo # Run rubocop with the defaults.
10
+ # rubo -h # View the help file to see more options.
11
+ #
12
+ # EXIT STATUS
13
+ #
14
+ # See the bottom of the file for exit status codes and their meaning.
15
+
16
+ lib = File.expand_path('../lib', __dir__)
17
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
18
+
19
+ require "cri"
20
+ require 'commands/rubo'
21
+ require "commands/rubo/utils/cri_platform_monkey_patch"
22
+
23
+ # rubocop:disable Metrics/BlockLength
24
+ command = Cri::Command.define do
25
+ # name 'rubo'
26
+ usage 'rubo [options]'
27
+ # aliases :ds, :stuff
28
+ # summary 'foo'
29
+ description 'rubo is an executable installed by the rubocop_plus gem. It invokes rubocop with a custom set of ' \
30
+ "rules. The following status codes are returned:\n\n" \
31
+ "STATUS CODES\n\n" \
32
+ "0 - rubocop ran and results were written to the 'rubocop' folder........\n" \
33
+ "1 - the project root does not contain a .rubocop.yml file...............\n" \
34
+ "2 - the .rubocop.yml file does not have the correct content.............\n" \
35
+ "3 - the 'rubocop' command cound not be found (likely due to missing gem)\n" \
36
+ "4 - the output from the 'rubo' command is missing or corrupt............\n"
37
+
38
+ flag :h, :help, 'show help for this command' do |_value, cmd|
39
+ puts cmd.help
40
+ exit 0
41
+ end
42
+
43
+ flag :i, :init, "(re)initialize your project with starting files; this will overwrite existing files" do |_value, cmd|
44
+ RubocopPlus::Commands::Rubo.new({ validate: true }, {}, cmd).initialize_project
45
+ exit 0
46
+ end
47
+
48
+ # This option is helpful when we're printing results to places that don't support the terminal colors (like the Jenkins
49
+ # console output). It also helps other tools parse the results of a successful run since the output doesn't contain extra
50
+ # numeric characters.
51
+ flag nil, "no-color", "do not colorize the output"
52
+
53
+ # This method should return a proper exit status if there are errors determining the rubocop version.
54
+ flag nil, "rubocop-version", 'return the version of rubocop' do |_value, cmd|
55
+ rubo = RubocopPlus::Commands::Rubo.new({ validate: true }, {}, cmd)
56
+ rubo.check_if_rubocop_command_exists!
57
+ puts rubo.rubocop_version_name
58
+ exit 0
59
+ end
60
+
61
+ # This method should return a proper exit status if there are errors determining the total violations count.
62
+ flag :t, "total-violations", 'write the total violations' do |_value, cmd|
63
+ rubo = RubocopPlus::Commands::Rubo.new({ total_violations: true }, {}, cmd)
64
+ rubo.check_if_total_violations_count_still_present_and_valid!
65
+ puts rubo.total_violations_count
66
+ exit 0
67
+ end
68
+
69
+ # This method should return a proper exit status if there are validation errors.
70
+ flag nil, :validate, "make sure rubocop is runnable" do |_value, cmd|
71
+ RubocopPlus::Commands::Rubo.new({ validate: true }, {}, cmd).validate_pre_run!
72
+ puts "Everything looks great!"
73
+ exit 0
74
+ end
75
+
76
+ flag :v, :version, 'return the version of rubo' do |_value, _cmd|
77
+ require 'rubocop_plus/version'
78
+ puts RubocopPlus::VERSION
79
+ exit 0
80
+ end
81
+
82
+ run do |options, args, cmd|
83
+ RubocopPlus::Commands::Rubo.new(options, args, cmd).run
84
+ end
85
+ end
86
+ # rubocop:enable Metrics/BlockLength
87
+
88
+ begin
89
+ command.run(ARGV)
90
+ exit 0
91
+ # Raised when an application fails to include a .rubocop.yml file.
92
+ rescue RubocopPlus::Commands::MissingYml => e
93
+ warn e.message
94
+ exit 1
95
+ # Raised when a project has a .rubocop.yml file, but it doesn't contain the correct content to work with this gem.
96
+ rescue RubocopPlus::Commands::IncorrectYml => e
97
+ warn e.message
98
+ exit 2
99
+ # Raised when the needed version of the rubocop executable is not installed (like because the rubocop gem is not installed).
100
+ rescue RubocopPlus::Commands::NoRubocopCommand => e
101
+ warn e.message
102
+ exit 3
103
+ # Raised when there are issues with the output generated by rubo.
104
+ rescue RubocopPlus::Commands::BadOutput, RubocopPlus::Commands::OutputMissing => e
105
+ warn e.message
106
+ exit 4
107
+ end
@@ -0,0 +1,102 @@
1
+ require "rubocop_plus"
2
+
3
+ require_relative "rubo/utils/which"
4
+ require_relative "rubo/helpers/misc"
5
+ require_relative "rubo/helpers/output"
6
+ require_relative "rubo/helpers/validations"
7
+
8
+ require_relative "rubo/errors/missing_yml"
9
+ require_relative "rubo/errors/incorrect_yml"
10
+ require_relative "rubo/errors/no_rubocop_command"
11
+ require_relative "rubo/errors/bad_output"
12
+ require_relative "rubo/errors/output_missing"
13
+
14
+ module RubocopPlus
15
+ module Commands
16
+ # The main class for the rubo command. When rubo is invoked on the command line, this class is initiated and the 'run'
17
+ # method is called.
18
+ class Rubo < Cri::CommandRunner
19
+ def run
20
+ prepare_options
21
+ validate_pre_run!
22
+ write_starting_message
23
+ delete_rubocop_folder
24
+ invoke_rubocop
25
+ generate_total_violations_file
26
+ validate_post_run!
27
+ write_results_message
28
+ end
29
+
30
+ # Perform all of the checks to make sure rubo can actually run. This method is called by the 'run' method when
31
+ # 'rubo' is called. It's also called with 'rubo --validate' is called.
32
+ def validate_pre_run!
33
+ check_if_yml_present!
34
+ check_if_yml_has_correct_content!
35
+ check_if_rubocop_command_exists!
36
+ end
37
+
38
+ def validate_post_run!
39
+ check_if_results_exist!
40
+ end
41
+
42
+ def initialize_project
43
+ backup_rubocop_yml_if_present
44
+ template_path = File.expand_path('../templates/.rubocop.yml', __dir__)
45
+ FileUtils.cp(template_path, ".rubocop.yml")
46
+ puts ".rubocop.yml created"
47
+ end
48
+
49
+ # Execute rubocop with a tailored set of output files. Rails checks are activated in the default config/rubocop.yml file
50
+ # so we do not explicitly activate them there.
51
+ def invoke_rubocop
52
+ cmd = is_in_gemfile_dot_lock? ? "bundle exec rubocop" : "rubocop"
53
+ # Make sure we always use the specific version of rubocop. Without this line, the latest version of rubocop
54
+ # will be used if a user installs a version that is newer than what we want to use.
55
+ cmd += " _#{RubocopPlus::RUBOCOP_VERSION}_"
56
+ cmd += " --format simple --out #{style_issues_text_file_name}"
57
+ cmd += " --format html --out #{style_issues_html_file_name}"
58
+ cmd += " --format offenses --out #{style_counts_text_file_name}"
59
+ cmd += checkstyle_options
60
+ system cmd
61
+ end
62
+
63
+ # Generates the XML reports necessary to use the Checkstyle Plugin on Jenkins. It is only needed for the CI so return an
64
+ # empty string unless the --checkstyle option is present.
65
+ def checkstyle_options
66
+ return "" unless options[:checkstyle]
67
+
68
+ cmd = " --require rubocop/formatter/checkstyle_formatter"
69
+ cmd += " --format RuboCop::Formatter::CheckstyleFormatter"
70
+ cmd + " --out #{output_folder_name}/checkstyle.xml"
71
+ end
72
+
73
+ # While using SublimeText with the SFTP plugin, we noticed the SFTP plugin would not automatically download newer versions
74
+ # of the generated rubocop files at times. Rubocop should overwrite the files, but we goahead and explicity delete the
75
+ # folder in the hopes that will help resolve the file syncing issues for editors (we're not 100% sure this helps).
76
+ def delete_rubocop_folder
77
+ FileUtils.remove_dir(output_folder_name, true)
78
+ end
79
+
80
+ private
81
+
82
+ def backup_rubocop_yml_if_present
83
+ return unless File.file?(".rubocop.yml")
84
+
85
+ FileUtils.mv(".rubocop.yml", ".rubocop.yml.bak")
86
+ puts ".rubocop.yml renamed to .rubocop.yml.bak"
87
+ end
88
+
89
+ # The cri doesn't do a good job of preparing the options. Instead of having symbols like :"no-color", :no_color is better.
90
+ def prepare_options
91
+ normalize_options
92
+ String.allow_color = !options[:no_color]
93
+ end
94
+
95
+ def normalize_options
96
+ no_color = options.delete(:"no-color")
97
+ options[:no_color] = no_color.nil? ? false : no_color
98
+ options[:checkstyle] = false unless options.has_key?(:checkstyle)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,18 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # When the rubo command runs rubocop, it tells rubocop to output to a specific set of files. If those files aren't
4
+ # created, (or don't have the expected format), rubo will raise a BadOutput error.
5
+ class BadOutput < StandardError
6
+ def initialize(msg="")
7
+ @details = msg
8
+ super
9
+ end
10
+
11
+ def message
12
+ "Error\n\n" \
13
+ " The output in the rubocop folder does not look correct. This implies rubo wasn't able to run 'rubocop'\n" \
14
+ " for some reason: #{@details}.\n\n".rubo_red
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # The rubo command performs some sanity checking to make sure the current application is using a well defined
4
+ # .rubocop.yml. It problems are found, an IncorrectYml error is raised.
5
+ class IncorrectYml < StandardError
6
+ def message
7
+ "\n" \
8
+ " The .rubocop.yml file does not appear to have the correct configuration to read from the\n" \
9
+ " rubocop_plus gem. To correct the problem:\n" \
10
+ " 1. Rename your existing .rubocop.yml to .rubocop.yml.bak\n" \
11
+ " 2. Run the installer to generate a fresh .rubocop.yml\n" \
12
+ " rubo --init\n\n".rubo_red
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # The rubo command performs some sanity checking to make sure the current application is using a well defined
4
+ # .rubocop.yml. If the .rubocop.yml file is missing, a MissingYml error is raised.
5
+ class MissingYml < StandardError
6
+ def message
7
+ "\n The application does not have a .rubocop.yml file. Run the installer to generate one:\n" \
8
+ " rubo --init\n\n".rubo_red
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # The rubo command will check to make sure the `rubocop` command exists. When users install rubocop_plus, rubocop_plus
4
+ # will automatically install a version of rubocop. Users may delete rubocop at a later time. If rubocop isn't available
5
+ # on the system, NoRubocopCommand will be raised.
6
+ class NoRubocopCommand < StandardError
7
+ def message
8
+ "\n" \
9
+ " The 'rubocop' command is not available. Is the rubocop gem installed? Verify by executing\n" \
10
+ " 'gem list rubocop'. If rubocop is not listed, reinstall rubocop_plus.\n\n".rubo_red
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # The rubo command will generate some custom output files. If those files don't get created properly, rubo will raise
4
+ # OutputMissing.
5
+ class OutputMissing < StandardError
6
+ def initialize(msg="")
7
+ @message = msg
8
+ super
9
+ end
10
+
11
+ def message
12
+ @message.rubo_red
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,68 @@
1
+ module RubocopPlus
2
+ module Commands
3
+ # Miscellaneous helpers are grouped in this file.
4
+ class Rubo < Cri::CommandRunner
5
+ def rubocop_yml_present?
6
+ File.file?(".rubocop.yml")
7
+ end
8
+
9
+ # The Gemfile.lock is auto generated when the 'bundle' command is run. It doesn't contain superfluous comments or any
10
+ # references to a gem unless the gem is being used. However, many terms like 'rails' is used in multiple gem name so
11
+ # we need to be smart about checking boundaries. Each gem line in Gemfile.lock always starts with a couple spaces,
12
+ # followed by the gem name, followed by a single space or newline chracter.
13
+ def is_in_gemfile_dot_lock?
14
+ return false unless File.exist?("Gemfile.lock")
15
+
16
+ # Match logic
17
+ # ^ - match from beginning of string
18
+ # \s* - match 0-N white space characters
19
+ # rubocop_plus - match the gem_name exactly once
20
+ # \s - match one white space character (it will always be a space or a \n)
21
+ File.foreach("Gemfile.lock") { |line| return true if line =~ /^\s*rubocop_plus\s/ }
22
+ false
23
+ end
24
+
25
+ def installed_version_of_gem
26
+ Gem::Version.new(RubocopPlus::VERSION)
27
+ end
28
+
29
+ def rubocop_version_name
30
+ Gem::Version.new(RubocopPlus::RUBOCOP_VERSION)
31
+ end
32
+
33
+ def output_folder_name
34
+ "rubocop"
35
+ end
36
+
37
+ def style_issues_text_file_name
38
+ "#{output_folder_name}/style-issues.txt"
39
+ end
40
+
41
+ def style_issues_html_file_name
42
+ "#{output_folder_name}/style-issues.html"
43
+ end
44
+
45
+ def style_counts_text_file_name
46
+ "#{output_folder_name}/style-counts.txt"
47
+ end
48
+
49
+ def total_violations_count_text_file_name
50
+ "#{output_folder_name}/total-violations-count.txt"
51
+ end
52
+
53
+ # Perform some sanity checks to make sure .rubocop.yml has expected content.
54
+ def rubocop_yml_has_correct_content?
55
+ # If we're running from inside the rubocop_plus folder, ignore this check.
56
+ return true if Dir.pwd.include?("rubocop_plus")
57
+
58
+ text = File.read(".rubocop.yml")
59
+ text.include?("inherit_gem:") && text.include?("rubocop_plus:")
60
+ end
61
+
62
+ def rubocop_command_exists?
63
+ path = Which('rubocop')
64
+ !(path.nil? || path.empty?)
65
+ end
66
+ end
67
+ end
68
+ end