diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 276e4aabf66c7753ef3b667e0fd52909fa79c15d..07f9cc84fa5cd6e9cf084523c7958bb26977cca6 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -8,10 +8,10 @@ AllCops: require: ./Homebrew/rubocops.rb -Homebrew/CorrectBottleBlock: +FormulaAuditStrict/CorrectBottleBlock: Enabled: true -Homebrew/FormulaDesc: +FormulaAuditStrict/FormulaDesc: Enabled: true Homebrew/FormulaComponentsOrder: diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index d89c9b72f50054b818e7ed68ac04d37884707583..4410f0febc01a1f86fe11fe5c4475f896b3a8ddb 100644 --- a/Library/Homebrew/cmd/style.rb +++ b/Library/Homebrew/cmd/style.rb @@ -56,8 +56,18 @@ module Homebrew ] args << "--auto-correct" if fix + if options[:exclude].eql?(:FormulaAuditStrict) && !(options.key?(:except) || options.key?(:only)) + args << "--except" << :FormulaAuditStrict + end + + if options[:except] + cops_to_exclude = options[:except].select { |cop| RuboCop::Cop::Cop.registry.names.include?(cop) } + args << "--except" << cops_to_exclude.join(" ") unless cops_to_exclude.empty? + end + if options[:only] - args << "--only" << RuboCop::Cop::Cop.registry.with_department(options[:only]).names.join(" ") + cops_to_include = options[:only].select { |cop| RuboCop::Cop::Cop.registry.names.include?(cop) } + args << "--only" << cops_to_include.join(" ") unless cops_to_include.empty? end if files.nil? diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 2f4b37096ec93d8c739e97e3036e76ab431bf3c4..e96d4cf4cd7dadffb57d9ba73587b22e1a6ee571 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -27,6 +27,10 @@ #: #: If `--except` is passed, the methods named `audit_<method>` will not be run. #: +#: If `--only-cops` is passed, only the mentioned cops' violations would be checked. +#: +#: If `--except-cops` is passed, the mentioned cops' checks would be skipped. +#: #: `audit` exits with a non-zero status if any errors are found. This is useful, #: for instance, for implementing pre-commit hooks. @@ -69,16 +73,22 @@ module Homebrew files = ARGV.resolved_formulae.map(&:path) end + only_cops = ARGV.value("only-cops").to_s.split(",") + except_cops = ARGV.value("except-cops").to_s.split(",") + if !only_cops.empty? && !except_cops.empty? + odie "--only-cops and --except-cops cannot be used simulataneously!" + end + if strict options = { fix: ARGV.flag?("--fix"), realpath: true } - # Check style in a single batch run up front for performance - style_results = check_style_json(files, options) + else + options = { fix: ARGV.flag?("--fix"), realpath: true, exclude: :FormulaAuditStrict } end - if !strict - options = { fix: ARGV.flag?("--fix"), realpath: true, only: :Homebrew } - style_results = check_style_json(files, options) - end + options[:only] = only_cops unless only_cops.empty? + options[:except] = except_cops unless except_cops.empty? + # Check style in a single batch run up front for performance + style_results = check_style_json(files, options) ff.each do |f| options = { new_formula: new_formula, strict: strict, online: online } diff --git a/Library/Homebrew/rubocops/bottle_block_cop.rb b/Library/Homebrew/rubocops/bottle_block_cop.rb index 141d87b358f63e93b94004b609678548040fa44f..2d6289cbb9af570b04e0fc2eaa14f1cb8b794bed 100644 --- a/Library/Homebrew/rubocops/bottle_block_cop.rb +++ b/Library/Homebrew/rubocops/bottle_block_cop.rb @@ -2,7 +2,7 @@ require_relative "./extend/formula_cop" module RuboCop module Cop - module Homebrew + module FormulaAuditStrict # This cop audits `bottle` block in Formulae # # - `rebuild` should be used instead of `revision` in `bottle` block diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index 11e5d93d39010b50ba486d2721233ee45ebd165e..4120be6efe667a95c4f9d8c734807b1445f934a7 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -1,213 +1,211 @@ module RuboCop module Cop - module Homebrew - class FormulaCop < Cop - @registry = Cop.registry - - # This method is called by RuboCop and is the main entry point - def on_class(node) - file_path = processed_source.buffer.name - return unless file_path_allowed?(file_path) - class_node, parent_class_node, body = *node - return unless formula_class?(parent_class_node) - return unless respond_to?(:audit_formula) - @formula_name = class_name(class_node) - audit_formula(node, class_node, parent_class_node, body) - end + class FormulaCop < Cop + @registry = Cop.registry + + # This method is called by RuboCop and is the main entry point + def on_class(node) + file_path = processed_source.buffer.name + return unless file_path_allowed?(file_path) + class_node, parent_class_node, body = *node + return unless formula_class?(parent_class_node) + return unless respond_to?(:audit_formula) + @formula_name = class_name(class_node) + audit_formula(node, class_node, parent_class_node, body) + end - # Checks for regex match of pattern in the node and - # Sets the appropriate instance variables to report the match - def regex_match_group(node, pattern) - string_repr = string_content(node) - match_object = string_repr.match(pattern) - return unless match_object - node_begin_pos = start_column(node) - line_begin_pos = line_start_column(node) - @column = node_begin_pos + match_object.begin(0) - line_begin_pos + 1 - @length = match_object.to_s.length - @line_no = line_number(node) - @source_buf = source_buffer(node) - @offense_source_range = source_range(@source_buf, @line_no, @column, @length) - @offensive_node = node - match_object - end + # Checks for regex match of pattern in the node and + # Sets the appropriate instance variables to report the match + def regex_match_group(node, pattern) + string_repr = string_content(node) + match_object = string_repr.match(pattern) + return unless match_object + node_begin_pos = start_column(node) + line_begin_pos = line_start_column(node) + @column = node_begin_pos + match_object.begin(0) - line_begin_pos + 1 + @length = match_object.to_s.length + @line_no = line_number(node) + @source_buf = source_buffer(node) + @offense_source_range = source_range(@source_buf, @line_no, @column, @length) + @offensive_node = node + match_object + end - # Returns method_node matching method_name - def find_node_method_by_name(node, method_name) - return if node.nil? - node.each_child_node(:send) do |method_node| - next unless method_node.method_name == method_name - @offensive_node = method_node - @offense_source_range = method_node.source_range - return method_node - end - # If not found then, parent node becomes the offensive node - @offensive_node = node.parent - @offense_source_range = node.parent.source_range - nil - end + # Returns method_node matching method_name + def find_node_method_by_name(node, method_name) + return if node.nil? + node.each_child_node(:send) do |method_node| + next unless method_node.method_name == method_name + @offensive_node = method_node + @offense_source_range = method_node.source_range + return method_node + end + # If not found then, parent node becomes the offensive node + @offensive_node = node.parent + @offense_source_range = node.parent.source_range + nil + end - # Returns an array of method call nodes matching method_name inside node - def find_method_calls_by_name(node, method_name) - return if node.nil? - node.each_child_node(:send).select { |method_node| method_name == method_node.method_name } - end + # Returns an array of method call nodes matching method_name inside node + def find_method_calls_by_name(node, method_name) + return if node.nil? + node.each_child_node(:send).select { |method_node| method_name == method_node.method_name } + end - # Returns a block named block_name inside node - def find_block(node, block_name) - return if node.nil? - node.each_child_node(:block) do |block_node| - next if block_node.method_name != block_name - @offensive_node = block_node - @offense_source_range = block_node.source_range - return block_node - end - # If not found then, parent node becomes the offensive node - @offensive_node = node.parent - @offense_source_range = node.parent.source_range - nil - end + # Returns a block named block_name inside node + def find_block(node, block_name) + return if node.nil? + node.each_child_node(:block) do |block_node| + next if block_node.method_name != block_name + @offensive_node = block_node + @offense_source_range = block_node.source_range + return block_node + end + # If not found then, parent node becomes the offensive node + @offensive_node = node.parent + @offense_source_range = node.parent.source_range + nil + end - # Returns an array of block nodes named block_name inside node - def find_blocks(node, block_name) - return if node.nil? - node.each_child_node(:block).select { |block_node| block_name == block_node.method_name } - end + # Returns an array of block nodes named block_name inside node + def find_blocks(node, block_name) + return if node.nil? + node.each_child_node(:block).select { |block_node| block_name == block_node.method_name } + end - # Returns a method definition node with method_name - def find_method_def(node, method_name) - return if node.nil? - node.each_child_node(:def) do |def_node| - def_method_name = method_name(def_node) - next unless method_name == def_method_name - @offensive_node = def_node - @offense_source_range = def_node.source_range - return def_node - end - # If not found then, parent node becomes the offensive node - @offensive_node = node.parent - @offense_source_range = node.parent.source_range - nil - end + # Returns a method definition node with method_name + def find_method_def(node, method_name) + return if node.nil? + node.each_child_node(:def) do |def_node| + def_method_name = method_name(def_node) + next unless method_name == def_method_name + @offensive_node = def_node + @offense_source_range = def_node.source_range + return def_node + end + # If not found then, parent node becomes the offensive node + @offensive_node = node.parent + @offense_source_range = node.parent.source_range + nil + end - # Check if a method is called inside a block - def method_called_in_block?(node, method_name) - block_body = node.children[2] - block_body.each_child_node(:send) do |call_node| - next unless call_node.method_name == method_name - @offensive_node = call_node - @offense_source_range = call_node.source_range - return true - end - false + # Check if a method is called inside a block + def method_called_in_block?(node, method_name) + block_body = node.children[2] + block_body.each_child_node(:send) do |call_node| + next unless call_node.method_name == method_name + @offensive_node = call_node + @offense_source_range = call_node.source_range + return true end + false + end - # Check if method_name is called among the direct children nodes in the given node - def method_called?(node, method_name) - node.each_child_node(:send) do |call_node| - next unless call_node.method_name == method_name - @offensive_node = call_node - @offense_source_range = call_node.source_range - return true - end - false + # Check if method_name is called among the direct children nodes in the given node + def method_called?(node, method_name) + node.each_child_node(:send) do |call_node| + next unless call_node.method_name == method_name + @offensive_node = call_node + @offense_source_range = call_node.source_range + return true end + false + end - # Checks for precedence, returns the first pair of precedence violating nodes - def check_precedence(first_nodes, next_nodes) - next_nodes.each do |each_next_node| - first_nodes.each do |each_first_node| - if component_precedes?(each_first_node, each_next_node) - return [each_first_node, each_next_node] - end + # Checks for precedence, returns the first pair of precedence violating nodes + def check_precedence(first_nodes, next_nodes) + next_nodes.each do |each_next_node| + first_nodes.each do |each_first_node| + if component_precedes?(each_first_node, each_next_node) + return [each_first_node, each_next_node] end end - nil end + nil + end - # If first node does not precede next_node, sets appropriate instance variables for reporting - def component_precedes?(first_node, next_node) - return false if line_number(first_node) < line_number(next_node) - @offense_source_range = first_node.source_range - @offensive_node = first_node - true - end + # If first node does not precede next_node, sets appropriate instance variables for reporting + def component_precedes?(first_node, next_node) + return false if line_number(first_node) < line_number(next_node) + @offense_source_range = first_node.source_range + @offensive_node = first_node + true + end - # Returns the array of arguments of the method_node - def parameters(method_node) - return unless method_node.send_type? - method_node.method_args - end + # Returns the array of arguments of the method_node + def parameters(method_node) + return unless method_node.send_type? + method_node.method_args + end - # Returns the begin position of the node's line in source code - def line_start_column(node) - node.source_range.source_buffer.line_range(node.loc.line).begin_pos - end + # Returns the begin position of the node's line in source code + def line_start_column(node) + node.source_range.source_buffer.line_range(node.loc.line).begin_pos + end - # Returns the begin position of the node in source code - def start_column(node) - node.source_range.begin_pos - end + # Returns the begin position of the node in source code + def start_column(node) + node.source_range.begin_pos + end - # Returns the line number of the node - def line_number(node) - node.loc.line - end + # Returns the line number of the node + def line_number(node) + node.loc.line + end - # Returns the class node's name, nil if not a class node - def class_name(node) - @offensive_node = node - @offense_source_range = node.source_range - node.const_name - end + # Returns the class node's name, nil if not a class node + def class_name(node) + @offensive_node = node + @offense_source_range = node.source_range + node.const_name + end - # Returns the method name for a def node - def method_name(node) - node.children[0] if node.def_type? - end + # Returns the method name for a def node + def method_name(node) + node.children[0] if node.def_type? + end - # Returns the node size in the source code - def size(node) - node.source_range.size - end + # Returns the node size in the source code + def size(node) + node.source_range.size + end - # Returns the block length of the block node - def block_size(block) - block_length(block) - end + # Returns the block length of the block node + def block_size(block) + block_length(block) + end - # Source buffer is required as an argument to report style violations - def source_buffer(node) - node.source_range.source_buffer - end + # Source buffer is required as an argument to report style violations + def source_buffer(node) + node.source_range.source_buffer + end - # Returns the string representation if node is of type str - def string_content(node) - node.str_content if node.type == :str - end + # Returns the string representation if node is of type str + def string_content(node) + node.str_content if node.type == :str + end - # Returns printable component name - def format_component(component_node) - return component_node.method_name if component_node.send_type? || component_node.block_type? - method_name(component_node) if component_node.def_type? - end + # Returns printable component name + def format_component(component_node) + return component_node.method_name if component_node.send_type? || component_node.block_type? + method_name(component_node) if component_node.def_type? + end - def problem(msg) - add_offense(@offensive_node, @offense_source_range, msg) - end + def problem(msg) + add_offense(@offensive_node, @offense_source_range, msg) + end - private + private - def formula_class?(parent_class_node) - parent_class_node && parent_class_node.const_name == "Formula" - end + def formula_class?(parent_class_node) + parent_class_node && parent_class_node.const_name == "Formula" + end - def file_path_allowed?(file_path) - paths_to_exclude = [%r{/Library/Homebrew/compat/}, - %r{/Library/Homebrew/test/}] - return true if file_path.nil? # file_path is nil when source is directly passed to the cop eg., in specs - file_path !~ Regexp.union(paths_to_exclude) - end + def file_path_allowed?(file_path) + paths_to_exclude = [%r{/Library/Homebrew/compat/}, + %r{/Library/Homebrew/test/}] + return true if file_path.nil? # file_path is nil when source is directly passed to the cop eg., in specs + file_path !~ Regexp.union(paths_to_exclude) end end end diff --git a/Library/Homebrew/rubocops/formula_desc_cop.rb b/Library/Homebrew/rubocops/formula_desc_cop.rb index 7d69a48e7ac301e1c044709f866f620dbf8cf9fc..d72fa53cc30f2f4005b2a737290b0f0452fdd140 100644 --- a/Library/Homebrew/rubocops/formula_desc_cop.rb +++ b/Library/Homebrew/rubocops/formula_desc_cop.rb @@ -3,7 +3,7 @@ require_relative "../extend/string" module RuboCop module Cop - module Homebrew + module FormulaAuditStrict # This cop audits `desc` in Formulae # # - Checks for existence of `desc` diff --git a/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb b/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb index 5be2d6cf506129b45cce44eff9915fbbac06a972..a7ae0c6ac9237cc957603e5a930614172d40ad53 100644 --- a/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb +++ b/Library/Homebrew/test/rubocops/bottle_block_cop_spec.rb @@ -3,7 +3,7 @@ require "rubocop/rspec/support" require_relative "../../extend/string" require_relative "../../rubocops/bottle_block_cop" -describe RuboCop::Cop::Homebrew::CorrectBottleBlock do +describe RuboCop::Cop::FormulaAuditStrict::CorrectBottleBlock do subject(:cop) { described_class.new } context "When auditing Bottle Block" do diff --git a/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb index 04c4c27da6257122a366cc20477a4a77d16ec033..7a3026703298f74c465f0f3eca22086f7af65136 100644 --- a/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb +++ b/Library/Homebrew/test/rubocops/formula_desc_cop_spec.rb @@ -3,7 +3,7 @@ require "rubocop/rspec/support" require_relative "../../extend/string" require_relative "../../rubocops/formula_desc_cop" -describe RuboCop::Cop::Homebrew::FormulaDesc do +describe RuboCop::Cop::FormulaAuditStrict::FormulaDesc do subject(:cop) { described_class.new } context "When auditing formula desc" do diff --git a/docs/Manpage.md b/docs/Manpage.md index 1f8906c8a289d1e2dad7b091ab91bd8aa130c567..4e173668a3858602df928d2eb2cdacda5c73f16d 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -635,6 +635,10 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note If `--except` is passed, the methods named `audit_`method`` will not be run. + If `--only-cops` is passed, only the mentioned cops' violations would be checked. + + If `--except-cops` is passed, the mentioned cops' checks would be skipped. + `audit` exits with a non-zero status if any errors are found. This is useful, for instance, for implementing pre-commit hooks. diff --git a/manpages/brew.1 b/manpages/brew.1 index 34cd7c5ed8343bde50182b989dee44ef5f50b685..e4b17e3b9591ff14affffb7d933301436198aedc 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -662,6 +662,12 @@ If \fB\-\-only\fR is passed, only the methods named \fBaudit_<method>\fR will be If \fB\-\-except\fR is passed, the methods named \fBaudit_<method>\fR will not be run\. . .IP +If \fB\-\-only\-cops\fR is passed, only the mentioned cops\' violations would be checked\. +. +.IP +If \fB\-\-except\-cops\fR is passed, the mentioned cops\' checks would be skipped\. +. +.IP \fBaudit\fR exits with a non\-zero status if any errors are found\. This is useful, for instance, for implementing pre\-commit hooks\. . .TP