From 2b151d30e79935808efb8b25e5231819ab4f149e Mon Sep 17 00:00:00 2001 From: Bevan Kay Date: Sat, 23 Aug 2025 12:54:06 +1000 Subject: [PATCH] rubocop: replace `:unsigned` automatically --- .../cask/deprecate_disable_unsigned_reason.rb | 47 +++++++++++++++++++ Library/Homebrew/rubocops/rubocop-cask.rb | 1 + .../deprecate_disable_unsigned_reason_spec.rb | 44 +++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 Library/Homebrew/rubocops/cask/deprecate_disable_unsigned_reason.rb create mode 100644 Library/Homebrew/test/rubocops/cask/deprecate_disable_unsigned_reason_spec.rb diff --git a/Library/Homebrew/rubocops/cask/deprecate_disable_unsigned_reason.rb b/Library/Homebrew/rubocops/cask/deprecate_disable_unsigned_reason.rb new file mode 100644 index 0000000000..5c49aef1b8 --- /dev/null +++ b/Library/Homebrew/rubocops/cask/deprecate_disable_unsigned_reason.rb @@ -0,0 +1,47 @@ +# typed: strict +# frozen_string_literal: true + +module RuboCop + module Cop + module Cask + # This cop checks for use of `because: :unsigned` in `deprecate!`/`disable!` + # and replaces it with the preferred `:fails_gatekeeper_check` reason. + # + # Example + # # bad + # deprecate! date: "2024-01-01", because: :unsigned + # disable! because: :unsigned + # + # # good + # deprecate! date: "2024-01-01", because: :fails_gatekeeper_check + # disable! because: :fails_gatekeeper_check + class DeprecateDisableUnsignedReason < Base + include CaskHelp + extend AutoCorrector + + STANZAS_TO_CHECK = [:deprecate!, :disable!].freeze + MESSAGE = "Use `:fails_gatekeeper_check` instead of `:unsigned` for deprecate!/disable! reason." + + sig { override.params(stanza_block: RuboCop::Cask::AST::StanzaBlock).void } + def on_cask_stanza_block(stanza_block) + stanzas = stanza_block.stanzas.select { |s| STANZAS_TO_CHECK.include?(s.stanza_name) } + stanzas.each do |stanza| + stanza_node = T.cast(stanza.stanza_node, RuboCop::AST::SendNode) + hash_node = stanza_node.last_argument + next unless hash_node&.hash_type? + + # find `because: :unsigned` pairs + T.cast(hash_node, RuboCop::AST::HashNode).each_pair do |key_node, value_node| + next if !key_node.sym_type? || key_node.value != :because + next if !value_node.sym_type? || value_node.value != :unsigned + + add_offense(value_node, message: MESSAGE) do |corrector| + corrector.replace(value_node.source_range, ":fails_gatekeeper_check") + end + end + end + end + end + end + end +end diff --git a/Library/Homebrew/rubocops/rubocop-cask.rb b/Library/Homebrew/rubocops/rubocop-cask.rb index f304b53f01..48e09ee0ed 100644 --- a/Library/Homebrew/rubocops/rubocop-cask.rb +++ b/Library/Homebrew/rubocops/rubocop-cask.rb @@ -26,3 +26,4 @@ require_relative "cask/uninstall_methods_order" require_relative "cask/url" require_relative "cask/url_legacy_comma_separators" require_relative "cask/variables" +require_relative "cask/deprecate_disable_unsigned_reason" diff --git a/Library/Homebrew/test/rubocops/cask/deprecate_disable_unsigned_reason_spec.rb b/Library/Homebrew/test/rubocops/cask/deprecate_disable_unsigned_reason_spec.rb new file mode 100644 index 0000000000..53359c7de6 --- /dev/null +++ b/Library/Homebrew/test/rubocops/cask/deprecate_disable_unsigned_reason_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require "rubocops/rubocop-cask" + +RSpec.describe RuboCop::Cop::Cask::DeprecateDisableUnsignedReason, :config do + it "flags and autocorrects deprecate! with :unsigned" do + expect_offense <<~CASK + cask "foo" do + deprecate! date: "2024-01-01", because: :unsigned + ^^^^^^^^^ Use `:fails_gatekeeper_check` instead of `:unsigned` for deprecate!/disable! reason. + end + CASK + + expect_correction <<~CASK + cask "foo" do + deprecate! date: "2024-01-01", because: :fails_gatekeeper_check + end + CASK + end + + it "flags and autocorrects disable! with :unsigned" do + expect_offense <<~CASK + cask "bar" do + disable! because: :unsigned + ^^^^^^^^^ Use `:fails_gatekeeper_check` instead of `:unsigned` for deprecate!/disable! reason. + end + CASK + + expect_correction <<~CASK + cask "bar" do + disable! because: :fails_gatekeeper_check + end + CASK + end + + it "ignores other reasons" do + expect_no_offenses <<~CASK + cask "baz" do + deprecate! date: "2024-01-01", because: :discontinued + disable! because: :no_longer_available + end + CASK + end +end