diff --git a/Library/Homebrew/rubocops/cask/on_system_conditionals.rb b/Library/Homebrew/rubocops/cask/on_system_conditionals.rb index 42c741aa63..cb3abd0a79 100644 --- a/Library/Homebrew/rubocops/cask/on_system_conditionals.rb +++ b/Library/Homebrew/rubocops/cask/on_system_conditionals.rb @@ -39,6 +39,9 @@ module RuboCop audit_on_system_blocks(stanza.stanza_node, stanza.stanza_name) end + + audit_arch_conditionals(cask_body) + simplify_sha256_stanzas end private @@ -46,6 +49,33 @@ module RuboCop attr_reader :cask_block def_delegators :cask_block, :toplevel_stanzas, :cask_body + + def simplify_sha256_stanzas + nodes = {} + + sha256_on_arch_stanzas(cask_body) do |node, method, value| + nodes[method.to_s.delete_prefix("on_").to_sym] = { node: node, value: value } + end + + return if !nodes.key?(:arm) || !nodes.key?(:intel) + + offending_node(nodes[:arm][:node]) + replacement_string = "sha256 arm: #{nodes[:arm][:value].inspect}, intel: #{nodes[:intel][:value].inspect}" + + problem "Use `#{replacement_string}` instead of nesting the `sha256` stanzas in " \ + "`on_intel` and `on_arm` blocks" do |corrector| + corrector.replace(nodes[:arm][:node].source_range, replacement_string) + corrector.replace(nodes[:intel][:node].source_range, "") + end + end + + def_node_search :sha256_on_arch_stanzas, <<~PATTERN + $(block + (send nil? ${:on_intel :on_arm}) + (args) + (send nil? :sha256 + (str $_))) + PATTERN end end end diff --git a/Library/Homebrew/rubocops/cask/on_system_conditionals.rbi b/Library/Homebrew/rubocops/cask/on_system_conditionals.rbi new file mode 100644 index 0000000000..3ca40d52d9 --- /dev/null +++ b/Library/Homebrew/rubocops/cask/on_system_conditionals.rbi @@ -0,0 +1,17 @@ +# typed: strict + +module RuboCop + module Cop + module Cask + class OnSystemConditionals < Base + sig { + params( + base_node: Parser::AST::Node, + block: T.proc.params(node: Parser::AST::Node, method: Symbol, value: String).void, + ).void + } + def sha256_on_arch_stanzas(base_node, &block); end + end + end + end +end diff --git a/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb b/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb index c1c7b1aa33..a815225b27 100644 --- a/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/on_system_conditionals_spec.rb @@ -13,8 +13,10 @@ describe RuboCop::Cop::Cask::OnSystemConditionals do context "when there are no on_system blocks" do let(:source) do <<-CASK.undent - postflight do - foobar + cask 'foo' do + postflight do + foobar + end end CASK end @@ -137,4 +139,127 @@ describe RuboCop::Cop::Cask::OnSystemConditionals do include_examples "autocorrects source" end end + + context "when auditing `sha256` stanzas inside on_arch blocks" do + context "when there are no on_arch blocks" do + let(:source) do + <<-CASK.undent + cask 'foo' do + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + CASK + end + + include_examples "does not report any offenses" + end + + context "when the proper `sha256` stanza is used" do + let(:source) do + <<-CASK.undent + cask 'foo' do + sha256 arm: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94", + intel: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + CASK + end + + include_examples "does not report any offenses" + end + + context "when the `sha256` stanza needs to be removed from the on_arch blocks" do + let(:source) do + <<-CASK.undent + cask 'foo' do + on_intel do + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + on_arm do + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK + end + let(:correct_source) do + <<-CASK.undent + cask 'foo' do + #{" "} + sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + CASK + end + let(:offense_source) do + <<-CASK.undent + on_arm do + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + CASK + end + let(:expected_offenses) do + [{ + message: 'Use `sha256 arm: "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b", ' \ + 'intel: "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94"` instead of ' \ + "nesting the `sha256` stanzas in `on_intel` and `on_arm` blocks", + severity: :convention, + line: 5, + column: 2, + source: offense_source.strip, + }] + end + + include_examples "reports offenses" + + include_examples "autocorrects source" + end + + context "when there is only one on_arch block" do + let(:source) do + <<-CASK.undent + cask 'foo' do + on_intel do + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + end + CASK + end + + include_examples "does not report any offenses" + end + + context "when there is also a `version` stanza inside the on_arch blocks" do + let(:source) do + <<-CASK.undent + cask 'foo' do + on_intel do + version "1.0.0" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + on_arm do + version "2.0.0" + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK + end + + include_examples "does not report any offenses" + end + + context "when there is also a `version` stanza inside only a single on_arch block" do + let(:source) do + <<-CASK.undent + cask 'foo' do + on_intel do + version "2.0.0" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + end + on_arm do + sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + end + end + CASK + end + + include_examples "does not report any offenses" + end + end end