diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 84cfe7328d..5cfa65c839 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -471,7 +471,8 @@ module Homebrew end def check_throttle(formula, new_version) - throttled_rate = formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name) + throttled_rate = formula.livecheck.throttle + throttled_rate ||= formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name) return if throttled_rate.blank? formula_suffix = Version.new(new_version).patch.to_i diff --git a/Library/Homebrew/dev-cmd/bump.rb b/Library/Homebrew/dev-cmd/bump.rb index c1260fde51..cc19ca70be 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -276,7 +276,8 @@ module Homebrew ) if skip_info.present? - return "#{skip_info[:status]}#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}" + return "#{skip_info[:status]}" \ + "#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}" end version_info = Livecheck.latest_version( @@ -286,9 +287,13 @@ module Homebrew ) return "unable to get versions" if version_info.blank? - latest = version_info[:latest] - - Version.new(latest) + if !version_info.key?(:latest_throttled) + Version.new(version_info[:latest]) + elsif version_info[:latest_throttled].nil? + "unable to get throttled versions" + else + Version.new(version_info[:latest_throttled]) + end rescue => e "error: #{e}" end @@ -475,7 +480,7 @@ module Homebrew ohai title puts <<~EOS Current #{version_label} #{current_versions} - Latest livecheck version: #{new_versions} + Latest livecheck version: #{new_versions}#{" (throttled)" if formula_or_cask.livecheck.throttle} EOS puts <<~EOS unless skip_repology?(formula_or_cask) Latest Repology version: #{repology_latest} diff --git a/Library/Homebrew/livecheck.rb b/Library/Homebrew/livecheck.rb index 353607a414..761ac38b7b 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -29,6 +29,7 @@ class Livecheck @skip_msg = nil @strategy = nil @strategy_block = nil + @throttle = nil @url = nil end @@ -135,6 +136,23 @@ class Livecheck sig { returns(T.nilable(Proc)) } attr_reader :strategy_block + # Sets the `@throttle` instance variable to the provided `Integer` or returns + # the `@throttle` instance variable when no argument is provided. + sig { + params( + # Throttle rate of version patch number to use for bumpable versions. + rate: Integer, + ).returns(T.nilable(Integer)) + } + def throttle(rate = T.unsafe(nil)) + case rate + when nil + @throttle + when Integer + @throttle = rate + end + end + # Sets the `@url` instance variable to the provided argument or returns the # `@url` instance variable when no argument is provided. The argument can be # a `String` (a URL) or a supported `Symbol` corresponding to a URL in the @@ -171,6 +189,7 @@ class Livecheck "skip" => @skip, "skip_msg" => @skip_msg, "strategy" => @strategy, + "throttle" => @throttle, "url" => @url, } end diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 6285345d4c..965e9c3c8b 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -372,9 +372,10 @@ module Homebrew info[:version] = { current: current_str, latest: latest_str, + latest_throttled: version_info&.dig(:latest_throttled), outdated: is_outdated, newer_than_upstream: is_newer_than_upstream, - } + }.compact info[:meta] = { livecheckable: formula_or_cask.livecheckable?, } @@ -678,6 +679,7 @@ module Homebrew livecheck_regex = livecheck.regex || referenced_livecheck&.regex livecheck_strategy = livecheck.strategy || referenced_livecheck&.strategy livecheck_strategy_block = livecheck.strategy_block || referenced_livecheck&.strategy_block + livecheck_throttle = livecheck.throttle || referenced_livecheck&.throttle livecheck_url_string = livecheck_url_to_string( livecheck_url, @@ -695,6 +697,7 @@ module Homebrew puts "Cask: #{cask_name(formula_or_cask, full_name:)}" end puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}" + puts "Throttle: #{livecheck_throttle}" if livecheck_throttle livecheck_references.each do |ref_formula_or_cask| case ref_formula_or_cask @@ -826,6 +829,28 @@ module Homebrew latest: Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }), } + if livecheck_throttle + match_version_map.keep_if { |_match, version| version.patch.to_i.modulo(livecheck_throttle).zero? } + version_info[:latest_throttled] = if match_version_map.blank? + nil + else + Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }) + end + + if debug + puts + puts "Matched Throttled Versions:" + + if verbose + match_version_map.each do |match, version| + puts "#{match} => #{version.inspect}" + end + else + puts match_version_map.values.join(", ") + end + end + end + if json && verbose version_info[:meta] = {} @@ -854,6 +879,7 @@ module Homebrew version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] } if strategies.present? version_info[:meta][:regex] = regex.inspect if regex.present? version_info[:meta][:cached] = true if strategy_data[:cached] == true + version_info[:meta][:throttle] = livecheck_throttle if livecheck_throttle end return version_info diff --git a/Library/Homebrew/test/livecheck_spec.rb b/Library/Homebrew/test/livecheck_spec.rb index a3fd7e6dd4..f0136ca886 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -100,6 +100,17 @@ RSpec.describe Livecheck do end end + describe "#throttle" do + it "returns nil if not set" do + expect(livecheckable_f.throttle).to be_nil + end + + it "returns the Integer if set" do + livecheckable_f.throttle(10) + expect(livecheckable_f.throttle).to eq(10) + end + end + describe "#url" do let(:url_string) { "https://brew.sh" } @@ -143,6 +154,7 @@ RSpec.describe Livecheck do "skip" => false, "skip_msg" => nil, "strategy" => nil, + "throttle" => nil, "url" => nil, }, )