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 84cfe7328d57f..3d88405e7a15d 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -472,6 +472,7 @@ def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil 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 c1260fde51267..3917ceaed046f 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -248,7 +248,9 @@ def skip_ineligible_formulae(formula_or_cask) 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 @@ def livecheck_result(formula_or_cask) ) 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 @@ def livecheck_result(formula_or_cask) 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 @@ def retrieve_versions_by_arch(formula_or_cask:, repositories:, name:) 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 @@ def retrieve_and_display_info_and_open_pr(formula_or_cask, name, repositories, a 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 353607a4144c9..1022c4059cd5b 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -25,6 +25,7 @@ def initialize(package_or_resource) @referenced_cask_name = nil @referenced_formula_name = nil @regex = nil + @throttle = nil @skip = false @skip_msg = nil @strategy = nil @@ -87,6 +88,23 @@ def regex(pattern = T.unsafe(nil)) 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 @@ def to_hash "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 6285345d4c63e..ebaacf1b13f4c 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -826,6 +826,28 @@ def latest_version( 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 a3fd7e6dd4550..2540eb7da3edf 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -66,6 +66,17 @@ 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 @@ "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 ebaacf1b13f4c..965e9c3c8b742 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -372,9 +372,10 @@ def run_checks( 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 @@ def latest_version( 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 @@ def latest_version( 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 @@ def latest_version( 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 @@ def latest_version( 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 1022c4059cd5b..86364ec08c165 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -25,11 +25,11 @@ def initialize(package_or_resource) @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 @@ def regex(pattern = T.unsafe(nil)) 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 @@ def strategy(symbol = T.unsafe(nil), &block) 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 @@ def to_hash "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 2540eb7da3edf..f0136ca886e1b 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -66,17 +66,6 @@ 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 @@ 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 @@ "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 86364ec08c165..761ac38b7b250 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -141,7 +141,7 @@ def strategy(symbol = T.unsafe(nil), &block) 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 3d88405e7a15d..5cfa65c839c0a 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -471,8 +471,8 @@ def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil 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 3917ceaed046f..cc19ca70be6c7 100644 --- a/Library/Homebrew/dev-cmd/bump.rb +++ b/Library/Homebrew/dev-cmd/bump.rb @@ -248,9 +248,7 @@ def skip_ineligible_formulae(formula_or_cask) 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 @@ def livecheck_result(formula_or_cask) 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 @@ def livecheck_result(formula_or_cask) 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 @@ def retrieve_versions_by_arch(formula_or_cask:, repositories:, name:) 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"