From bfec6eecac45fddd704daf87bce9bbcfd590d015 Mon Sep 17 00:00:00 2001 From: Michael Cho Date: Tue, 19 Mar 2024 11:17:00 -0400 Subject: [PATCH 1/5] livecheck: support throttle DSL Signed-off-by: Michael Cho --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 1 + Library/Homebrew/dev-cmd/bump.rb | 29 +++++++++++++++------ Library/Homebrew/livecheck.rb | 19 ++++++++++++++ Library/Homebrew/livecheck/livecheck.rb | 22 ++++++++++++++++ Library/Homebrew/test/livecheck_spec.rb | 12 +++++++++ 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 84cfe7328d..3d88405e7a 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -472,6 +472,7 @@ module Homebrew def check_throttle(formula, new_version) throttled_rate = formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name) + throttled_rate ||= formula.livecheck.throttle 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..3917ceaed0 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -248,7 +248,9 @@ module Homebrew end sig { - params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T.any(Version, String)) + params( + formula_or_cask: T.any(Formula, Cask::Cask), + ).returns([T.any(Version, String), T.nilable(T.any(Version, String))]) } def livecheck_result(formula_or_cask) name = Livecheck.package_or_resource_name(formula_or_cask) @@ -276,7 +278,9 @@ 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?}", + nil end version_info = Livecheck.latest_version( @@ -284,13 +288,20 @@ module Homebrew referenced_formula_or_cask:, json: true, full_name: false, verbose: true, debug: false ) - return "unable to get versions" if version_info.blank? + return "unable to get versions", nil if version_info.blank? - latest = version_info[:latest] + latest = Version.new(version_info[:latest]) + latest_throttled = if !version_info.key?(:latest_throttled) + nil + elsif version_info[:latest_throttled].nil? + "unable to get throttled versions" + else + Version.new(version_info[:latest_throttled]) + end - Version.new(latest) + [latest, latest_throttled] rescue => e - "error: #{e}" + ["error: #{e}", nil] end sig { @@ -349,7 +360,9 @@ module Homebrew current_version_value = Version.new(loaded_formula_or_cask.version) end - livecheck_latest = livecheck_result(loaded_formula_or_cask) + livecheck_latest, livecheck_latest_throttled = livecheck_result(loaded_formula_or_cask) + # TODO: Pass down `livecheck_latest` info to print output for throttled formulae or casks + livecheck_latest = livecheck_latest_throttled if livecheck_latest_throttled new_version_value = if (livecheck_latest.is_a?(Version) && livecheck_latest >= current_version_value) || current_version_value == "latest" @@ -475,7 +488,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..1022c4059c 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -25,6 +25,7 @@ class Livecheck @referenced_cask_name = nil @referenced_formula_name = nil @regex = nil + @throttle = nil @skip = false @skip_msg = nil @strategy = nil @@ -87,6 +88,23 @@ class Livecheck end end + # 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: T.nilable(Integer), + ).returns(T.nilable(Integer)) + } + def throttle(rate = T.unsafe(nil)) + case rate + when nil + @throttle + when Integer + @throttle = rate + end + end + # Sets the `@skip` instance variable to `true` and sets the `@skip_msg` # instance variable if a `String` is provided. `@skip` is used to indicate # that the formula/cask/resource should be skipped and the `skip_msg` very @@ -168,6 +186,7 @@ class Livecheck "cask" => @referenced_cask_name, "formula" => @referenced_formula_name, "regex" => @regex, + "throttle" => @throttle, "skip" => @skip, "skip_msg" => @skip_msg, "strategy" => @strategy, diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 6285345d4c..ebaacf1b13 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -826,6 +826,28 @@ module Homebrew latest: Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }), } + if (throttle = livecheck.throttle || referenced_livecheck&.throttle) + match_version_map.keep_if { |_match, version| version.patch.to_i.modulo(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] = {} diff --git a/Library/Homebrew/test/livecheck_spec.rb b/Library/Homebrew/test/livecheck_spec.rb index a3fd7e6dd4..2540eb7da3 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -66,6 +66,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 "#skip" do it "sets @skip to true when no argument is provided" do expect(livecheckable_f.skip).to be true @@ -140,6 +151,7 @@ RSpec.describe Livecheck do "cask" => nil, "formula" => nil, "regex" => nil, + "throttle" => nil, "skip" => false, "skip_msg" => nil, "strategy" => nil, From 25d07c38385d2d7fb1237ce080d3aa8be0d4c63b Mon Sep 17 00:00:00 2001 From: Sam Ford <1584702+samford@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:50:14 -0400 Subject: [PATCH 2/5] livecheck: Add throttle info to debug, JSON output --- Library/Homebrew/livecheck/livecheck.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index ebaacf1b13..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,8 +829,8 @@ module Homebrew latest: Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(formula_or_cask, v) }), } - if (throttle = livecheck.throttle || referenced_livecheck&.throttle) - match_version_map.keep_if { |_match, version| version.patch.to_i.modulo(throttle).zero? } + 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 @@ -876,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 From 7681621cd49444d2ce76aae17d018ee45319347e Mon Sep 17 00:00:00 2001 From: Sam Ford <1584702+samford@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:19:35 -0400 Subject: [PATCH 3/5] livecheck: Reorder throttle --- Library/Homebrew/livecheck.rb | 38 ++++++++++++------------- Library/Homebrew/test/livecheck_spec.rb | 24 ++++++++-------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Library/Homebrew/livecheck.rb b/Library/Homebrew/livecheck.rb index 1022c4059c..86364ec08c 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -25,11 +25,11 @@ class Livecheck @referenced_cask_name = nil @referenced_formula_name = nil @regex = nil - @throttle = nil @skip = false @skip_msg = nil @strategy = nil @strategy_block = nil + @throttle = nil @url = nil end @@ -88,23 +88,6 @@ class Livecheck end end - # 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: T.nilable(Integer), - ).returns(T.nilable(Integer)) - } - def throttle(rate = T.unsafe(nil)) - case rate - when nil - @throttle - when Integer - @throttle = rate - end - end - # Sets the `@skip` instance variable to `true` and sets the `@skip_msg` # instance variable if a `String` is provided. `@skip` is used to indicate # that the formula/cask/resource should be skipped and the `skip_msg` very @@ -153,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: T.nilable(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 @@ -186,10 +186,10 @@ class Livecheck "cask" => @referenced_cask_name, "formula" => @referenced_formula_name, "regex" => @regex, - "throttle" => @throttle, "skip" => @skip, "skip_msg" => @skip_msg, "strategy" => @strategy, + "throttle" => @throttle, "url" => @url, } end diff --git a/Library/Homebrew/test/livecheck_spec.rb b/Library/Homebrew/test/livecheck_spec.rb index 2540eb7da3..f0136ca886 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -66,17 +66,6 @@ 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 "#skip" do it "sets @skip to true when no argument is provided" do expect(livecheckable_f.skip).to be true @@ -111,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" } @@ -151,10 +151,10 @@ RSpec.describe Livecheck do "cask" => nil, "formula" => nil, "regex" => nil, - "throttle" => nil, "skip" => false, "skip_msg" => nil, "strategy" => nil, + "throttle" => nil, "url" => nil, }, ) From 0f063921c5f2e619cdf508956b0d77158155f1b6 Mon Sep 17 00:00:00 2001 From: Sam Ford <1584702+samford@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:37:27 -0400 Subject: [PATCH 4/5] livecheck: Update throttle rate parameter type Co-authored-by: Markus Reiter --- Library/Homebrew/livecheck.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/livecheck.rb b/Library/Homebrew/livecheck.rb index 86364ec08c..761ac38b7b 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -141,7 +141,7 @@ class Livecheck sig { params( # Throttle rate of version patch number to use for bumpable versions. - rate: T.nilable(Integer), + rate: Integer, ).returns(T.nilable(Integer)) } def throttle(rate = T.unsafe(nil)) From 43e2e288698435584cffc749ada3a261a663ffc7 Mon Sep 17 00:00:00 2001 From: Michael Cho Date: Thu, 21 Mar 2024 09:12:14 -0400 Subject: [PATCH 5/5] dev-cmd/bump-formula-pr: clean up unused code Signed-off-by: Michael Cho --- Library/Homebrew/dev-cmd/bump-formula-pr.rb | 4 ++-- Library/Homebrew/dev-cmd/bump.rb | 22 +++++++-------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 3d88405e7a..5cfa65c839 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -471,8 +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.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 3917ceaed0..cc19ca70be 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -248,9 +248,7 @@ module Homebrew end sig { - params( - formula_or_cask: T.any(Formula, Cask::Cask), - ).returns([T.any(Version, String), T.nilable(T.any(Version, String))]) + params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T.any(Version, String)) } def livecheck_result(formula_or_cask) name = Livecheck.package_or_resource_name(formula_or_cask) @@ -279,8 +277,7 @@ module Homebrew if skip_info.present? return "#{skip_info[:status]}" \ - "#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}", - nil + "#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}" end version_info = Livecheck.latest_version( @@ -288,20 +285,17 @@ module Homebrew referenced_formula_or_cask:, json: true, full_name: false, verbose: true, debug: false ) - return "unable to get versions", nil if version_info.blank? + return "unable to get versions" if version_info.blank? - latest = Version.new(version_info[:latest]) - latest_throttled = if !version_info.key?(:latest_throttled) - nil + 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 - - [latest, latest_throttled] rescue => e - ["error: #{e}", nil] + "error: #{e}" end sig { @@ -360,9 +354,7 @@ module Homebrew current_version_value = Version.new(loaded_formula_or_cask.version) end - livecheck_latest, livecheck_latest_throttled = livecheck_result(loaded_formula_or_cask) - # TODO: Pass down `livecheck_latest` info to print output for throttled formulae or casks - livecheck_latest = livecheck_latest_throttled if livecheck_latest_throttled + livecheck_latest = livecheck_result(loaded_formula_or_cask) new_version_value = if (livecheck_latest.is_a?(Version) && livecheck_latest >= current_version_value) || current_version_value == "latest"