From b6eb9453204f0b4910956aeb9b1aee1974a132d1 Mon Sep 17 00:00:00 2001 From: Sam Ford <1584702+samford@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:04:38 -0500 Subject: [PATCH] livecheck: Add Options class This adds a `Livecheck::Options` class, which is intended to house various configuration options that are set in `livecheck` blocks, conditionally set by livecheck at runtime, etc. The general idea is that when we add features involving configurations options (e.g., for livecheck, strategies, curl, etc.), we can make changes to `Options` without needing to modify parameters for strategy `find_versions` methods, `Strategy` methods like `page_headers` and `page_content`, etc. This is something that I've been trying to improve over the years and `Options` should help to reduce maintenance overhead in this area while also strengthening type signatures. `Options` replaces the existing `homebrew_curl` option (which related strategies pass to `Strategy` methods and on to `curl_args`) and the new `url_options` (which contains `post_form` or `post_json` values that are used to make `POST` requests). I recently added `url_options` as a temporary way of enabling `POST` support without `Options` but this restores the original `Options`-based implementation. Along the way, I added a `homebrew_curl` parameter to the `url` DSL method, allowing us to set an explicit value in `livecheck` blocks. This is something that we've needed in some cases but I also intend to replace implicit/inferred `homebrew_curl` usage with explicit values in `livecheck` blocks once this is available for use. My intention is to eventually remove the implicit behavior and only rely on explicit values. That will align with how `homebrew_curl` options work for other URLs and makes the behavior clear just from looking at the `livecheck` block. Lastly, this removes the `unused` rest parameter from `find_versions` methods. I originally added `unused` as a way of handling parameters that some `find_versions` methods have but others don't (e.g., `cask` in `ExtractPlist`), as this allowed us to pass various arguments to `find_versions` methods without worrying about whether a particular parameter is available. This isn't an ideal solution and I originally wanted to handle this situation by only passing expected arguments to `find_versions` methods but there was a technical issue standing in the way. I recently found an answer to the issue, so this also replaces the existing `ExtractPlist` special case with generic logic that checks the parameters for a strategy's `find_versions` method and only passes expected arguments. Replacing the aforementioned `find_versions` parameters with `Options` ensures that the remaining parameters are fairly consistent across strategies and any differences are handled by the aforementioned logic. Outside of `ExtractPlist`, the only other difference is that some `find_versions` methods have a `provided_content` parameter but that's currently only used by tests (though it's intended for caching support in the future). I will be renaming that parameter to `content` in an upcoming PR and expanding it to the other strategies, which should make them all consistent outside of `ExtractPlist`. --- Library/Homebrew/livecheck.rb | 48 ++++---- Library/Homebrew/livecheck/livecheck.rb | 79 ++++++++----- Library/Homebrew/livecheck/options.rb | 110 ++++++++++++++++++ Library/Homebrew/livecheck/strategy.rb | 45 +++---- Library/Homebrew/livecheck/strategy/apache.rb | 18 ++- .../Homebrew/livecheck/strategy/bitbucket.rb | 18 ++- Library/Homebrew/livecheck/strategy/cpan.rb | 18 ++- Library/Homebrew/livecheck/strategy/crate.rb | 15 +-- .../livecheck/strategy/electron_builder.rb | 7 +- .../livecheck/strategy/extract_plist.rb | 5 +- Library/Homebrew/livecheck/strategy/git.rb | 5 +- .../livecheck/strategy/github_latest.rb | 5 +- .../livecheck/strategy/github_releases.rb | 5 +- Library/Homebrew/livecheck/strategy/gnome.rb | 17 +-- Library/Homebrew/livecheck/strategy/gnu.rb | 18 ++- .../Homebrew/livecheck/strategy/hackage.rb | 18 ++- .../livecheck/strategy/header_match.rb | 19 ++- Library/Homebrew/livecheck/strategy/json.rb | 15 +-- .../Homebrew/livecheck/strategy/launchpad.rb | 18 ++- Library/Homebrew/livecheck/strategy/npm.rb | 18 ++- .../Homebrew/livecheck/strategy/page_match.rb | 15 +-- Library/Homebrew/livecheck/strategy/pypi.rb | 7 +- .../livecheck/strategy/sourceforge.rb | 17 +-- .../Homebrew/livecheck/strategy/sparkle.rb | 21 ++-- Library/Homebrew/livecheck/strategy/xml.rb | 15 +-- Library/Homebrew/livecheck/strategy/xorg.rb | 13 ++- Library/Homebrew/livecheck/strategy/yaml.rb | 15 +-- .../Homebrew/test/livecheck/options_spec.rb | 106 +++++++++++++++++ .../Homebrew/test/livecheck/strategy_spec.rb | 22 +++- Library/Homebrew/test/livecheck_spec.rb | 33 +++--- 30 files changed, 515 insertions(+), 250 deletions(-) create mode 100644 Library/Homebrew/livecheck/options.rb create mode 100644 Library/Homebrew/test/livecheck/options_spec.rb diff --git a/Library/Homebrew/livecheck.rb b/Library/Homebrew/livecheck.rb index efdf5339fe..98a48ce49d 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -2,6 +2,7 @@ # frozen_string_literal: true require "livecheck/constants" +require "livecheck/options" require "cask/cask" # The {Livecheck} class implements the DSL methods used in a formula's, cask's @@ -15,6 +16,10 @@ require "cask/cask" class Livecheck extend Forwardable + # Options to modify livecheck's behavior. + sig { returns(Homebrew::Livecheck::Options) } + attr_reader :options + # A very brief description of why the formula/cask/resource is skipped (e.g. # `No longer developed or maintained`). sig { returns(T.nilable(String)) } @@ -24,13 +29,10 @@ class Livecheck sig { returns(T.nilable(Proc)) } attr_reader :strategy_block - # Options used by `Strategy` methods to modify `curl` behavior. - sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) } - attr_reader :url_options - sig { params(package_or_resource: T.any(Cask::Cask, T.class_of(Formula), Resource)).void } def initialize(package_or_resource) @package_or_resource = package_or_resource + @options = T.let(Homebrew::Livecheck::Options.new, Homebrew::Livecheck::Options) @referenced_cask_name = T.let(nil, T.nilable(String)) @referenced_formula_name = T.let(nil, T.nilable(String)) @regex = T.let(nil, T.nilable(Regexp)) @@ -40,7 +42,6 @@ class Livecheck @strategy_block = T.let(nil, T.nilable(Proc)) @throttle = T.let(nil, T.nilable(Integer)) @url = T.let(nil, T.any(NilClass, String, Symbol)) - @url_options = T.let(nil, T.nilable(T::Hash[Symbol, T.untyped])) end # Sets the `@referenced_cask_name` instance variable to the provided `String` @@ -169,16 +170,22 @@ class Livecheck sig { params( # URL to check for version information. - url: T.any(String, Symbol), - post_form: T.nilable(T::Hash[Symbol, String]), - post_json: T.nilable(T::Hash[Symbol, String]), + url: T.any(String, Symbol), + homebrew_curl: T.nilable(T::Boolean), + post_form: T.nilable(T::Hash[Symbol, String]), + post_json: T.nilable(T::Hash[Symbol, String]), ).returns(T.nilable(T.any(String, Symbol))) } - def url(url = T.unsafe(nil), post_form: nil, post_json: nil) + def url(url = T.unsafe(nil), homebrew_curl: nil, post_form: nil, post_json: nil) raise ArgumentError, "Only use `post_form` or `post_json`, not both" if post_form && post_json - options = { post_form:, post_json: }.compact - @url_options = options if options.present? + if homebrew_curl || post_form || post_json + @options = @options.merge({ + homebrew_curl:, + post_form:, + post_json:, + }.compact) + end case url when nil @@ -190,6 +197,7 @@ class Livecheck end end + delegate url_options: :@options delegate version: :@package_or_resource delegate arch: :@package_or_resource private :version, :arch @@ -198,15 +206,15 @@ class Livecheck sig { returns(T::Hash[String, T.untyped]) } def to_hash { - "cask" => @referenced_cask_name, - "formula" => @referenced_formula_name, - "regex" => @regex, - "skip" => @skip, - "skip_msg" => @skip_msg, - "strategy" => @strategy, - "throttle" => @throttle, - "url" => @url, - "url_options" => @url_options, + "options" => @options.to_hash, + "cask" => @referenced_cask_name, + "formula" => @referenced_formula_name, + "regex" => @regex, + "skip" => @skip, + "skip_msg" => @skip_msg, + "strategy" => @strategy, + "throttle" => @throttle, + "url" => @url, } end end diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index d6be1c623c..fb3c4946da 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -34,6 +34,24 @@ module Homebrew @livecheck_strategy_names[strategy_class] ||= Utils.demodulize(strategy_class.name) end + sig { returns(T::Hash[T::Class[T.anything], T::Array[Symbol]]) } + private_class_method def self.livecheck_find_versions_parameters + return T.must(@livecheck_find_versions_parameters) if defined?(@livecheck_find_versions_parameters) + + # Cache strategy `find_versions` method parameters, to avoid repeating + # this work + @livecheck_find_versions_parameters = T.let({}, T.nilable(T::Hash[T::Class[T.anything], T::Array[Symbol]])) + Strategy.constants.sort.each do |const_symbol| + constant = Strategy.const_get(const_symbol) + next unless constant.is_a?(Class) + + T.must(@livecheck_find_versions_parameters)[constant] = + T::Utils.signature_for_method(constant.method(:find_versions)) + &.parameters&.map(&:second) + end + T.must(@livecheck_find_versions_parameters).freeze + end + # Uses `formulae_and_casks_to_check` to identify taps in use other than # homebrew/core and homebrew/cask and loads strategies from them. sig { params(formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)]).void } @@ -613,8 +631,9 @@ module Homebrew livecheck = formula_or_cask.livecheck referenced_livecheck = referenced_formula_or_cask&.livecheck + livecheck_options = livecheck.options || referenced_livecheck&.options + livecheck_url_options = livecheck_options.url_options.compact livecheck_url = livecheck.url || referenced_livecheck&.url - livecheck_url_options = livecheck.url_options || referenced_livecheck&.url_options livecheck_regex = livecheck.regex || referenced_livecheck&.regex livecheck_strategy = livecheck.strategy || referenced_livecheck&.strategy livecheck_strategy_block = livecheck.strategy_block || referenced_livecheck&.strategy_block @@ -676,8 +695,8 @@ module Homebrew elsif original_url.present? && original_url != "None" puts "URL: #{original_url}" end - puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present? puts "URL (processed): #{url}" if url != original_url + puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present? if strategies.present? && verbose puts "Strategies: #{strategies.map { |s| livecheck_strategy_names(s) }.join(", ")}" end @@ -697,23 +716,25 @@ module Homebrew next if strategy.blank? - homebrew_curl = case strategy_name - when "PageMatch", "HeaderMatch" - use_homebrew_curl?(referenced_package, url) + if (livecheck_homebrew_curl = livecheck_options.homebrew_curl).nil? + case strategy_name + when "PageMatch", "HeaderMatch" + if (homebrew_curl = use_homebrew_curl?(referenced_package, url)) + livecheck_options = livecheck_options.merge({ homebrew_curl: }) + livecheck_homebrew_curl = homebrew_curl + end + end end - puts "Homebrew curl?: Yes" if debug && homebrew_curl.present? + puts "Homebrew curl?: #{livecheck_homebrew_curl ? "Yes" : "No"}" if debug && !livecheck_homebrew_curl.nil? - strategy_args = { - regex: livecheck_regex, - url_options: livecheck_url_options, - homebrew_curl:, - } - # TODO: Set `cask`/`url` args based on the presence of the keyword arg - # in the strategy's `#find_versions` method once we figure out why - # `strategy.method(:find_versions).parameters` isn't working as - # expected. - strategy_args[:cask] = cask if strategy_name == "ExtractPlist" && cask.present? - strategy_args[:url] = url + # Only use arguments that the strategy's `#find_versions` method + # supports + find_versions_parameters = T.must(livecheck_find_versions_parameters[strategy]) + strategy_args = {} + strategy_args[:cask] = cask if find_versions_parameters.include?(:cask) + strategy_args[:url] = url if find_versions_parameters.include?(:url) + strategy_args[:regex] = livecheck_regex if find_versions_parameters.include?(:regex) + strategy_args[:options] = livecheck_options if find_versions_parameters.include?(:options) strategy_args.compact! strategy_data = strategy.find_versions(**strategy_args, &livecheck_strategy_block) @@ -813,7 +834,6 @@ module Homebrew end version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url] version_info[:meta][:url][:options] = livecheck_url_options if livecheck_url_options.present? - version_info[:meta][:url][:homebrew_curl] = homebrew_curl if homebrew_curl.present? end version_info[:meta][:strategy] = strategy_name if strategy.present? version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names(s) } if strategies.present? @@ -860,9 +880,10 @@ module Homebrew resource_version_info = {} livecheck = resource.livecheck + livecheck_options = livecheck.options + livecheck_url_options = livecheck_options.url_options.compact livecheck_reference = livecheck.formula livecheck_url = livecheck.url - livecheck_url_options = livecheck.url_options livecheck_regex = livecheck.regex livecheck_strategy = livecheck.strategy livecheck_strategy_block = livecheck.strategy_block @@ -902,8 +923,8 @@ module Homebrew elsif original_url.present? && original_url != "None" puts "URL: #{original_url}" end - puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present? puts "URL (processed): #{url}" if url != original_url + puts "URL Options: #{livecheck_url_options}" if livecheck_url_options.present? if strategies.present? && verbose puts "Strategies: #{strategies.map { |s| livecheck_strategy_names(s) }.join(", ")}" end @@ -926,16 +947,22 @@ module Homebrew puts if debug && strategy.blank? && livecheck_reference != :parent next if strategy.blank? && livecheck_reference != :parent + if debug && !(livecheck_homebrew_curl = livecheck_options.homebrew_curl).nil? + puts "Homebrew curl?: #{livecheck_homebrew_curl ? "Yes" : "No"}" + end + if livecheck_reference == :parent match_version_map = { formula_latest => Version.new(formula_latest) } cached = true else - strategy_args = { - url:, - regex: livecheck_regex, - url_options: livecheck_url_options, - homebrew_curl: false, - }.compact + # Only use arguments that the strategy's `#find_versions` method + # supports + find_versions_parameters = T.must(livecheck_find_versions_parameters[strategy]) + strategy_args = {} + strategy_args[:url] = url if find_versions_parameters.include?(:url) + strategy_args[:regex] = livecheck_regex if find_versions_parameters.include?(:regex) + strategy_args[:options] = livecheck_options if find_versions_parameters.include?(:options) + strategy_args.compact! strategy_data = strategy.find_versions(**strategy_args, &livecheck_strategy_block) match_version_map = strategy_data[:matches] diff --git a/Library/Homebrew/livecheck/options.rb b/Library/Homebrew/livecheck/options.rb new file mode 100644 index 0000000000..8e8c421758 --- /dev/null +++ b/Library/Homebrew/livecheck/options.rb @@ -0,0 +1,110 @@ +# typed: strict +# frozen_string_literal: true + +module Homebrew + module Livecheck + # Options to modify livecheck's behavior. These primarily come from + # `livecheck` blocks but they can also be set by livecheck at runtime. + # + # Option values use a `nil` default to indicate that the value has not been + # set. + class Options + # Whether to use brewed curl. + sig { returns(T.nilable(T::Boolean)) } + attr_reader :homebrew_curl + + # Form data to use when making a `POST` request. + sig { returns(T.nilable(T::Hash[Symbol, String])) } + attr_reader :post_form + + # JSON data to use when making a `POST` request. + sig { returns(T.nilable(T::Hash[Symbol, String])) } + attr_reader :post_json + + # @param homebrew_curl whether to use brewed curl + # @param post_form form data to use when making a `POST` request + # @param post_json JSON data to use when making a `POST` request + sig { + params( + homebrew_curl: T.nilable(T::Boolean), + post_form: T.nilable(T::Hash[Symbol, String]), + post_json: T.nilable(T::Hash[Symbol, String]), + ).void + } + def initialize(homebrew_curl: nil, post_form: nil, post_json: nil) + @homebrew_curl = homebrew_curl + @post_form = post_form + @post_json = post_json + end + + # Returns a `Hash` of options that are provided as arguments to `url`. + sig { returns(T::Hash[Symbol, T.untyped]) } + def url_options + { + homebrew_curl:, + post_form:, + post_json:, + } + end + + # Returns a `Hash` of all instance variables, using `Symbol` keys. + sig { returns(T::Hash[Symbol, T.untyped]) } + def to_h + { + homebrew_curl:, + post_form:, + post_json:, + } + end + + # Returns a `Hash` of all instance variables, using `String` keys. + sig { returns(T::Hash[String, T.untyped]) } + def to_hash + { + "homebrew_curl" => @homebrew_curl, + "post_form" => @post_form, + "post_json" => @post_json, + } + end + + # Returns a new object formed by merging `other` values with a copy of + # `self`. + # + # `nil` values are removed from `other` before merging if it is an + # `Options` object, as these are unitiailized values. This ensures that + # existing values in `self` aren't unexpectedly overwritten with defaults. + sig { params(other: T.any(Options, T::Hash[Symbol, T.untyped])).returns(Options) } + def merge(other) + return dup if other.empty? + + this_hash = to_h + other_hash = other.is_a?(Options) ? other.to_h.compact : other + return dup if this_hash == other_hash + + new_options = this_hash.merge(other_hash) + Options.new(**new_options) + end + + sig { params(other: T.untyped).returns(T::Boolean) } + def ==(other) + instance_of?(other.class) && + @homebrew_curl == other.homebrew_curl && + @post_form == other.post_form && + @post_json == other.post_json + end + alias eql? == + + # Whether the object has only default values. + sig { returns(T::Boolean) } + def empty? + @homebrew_curl.nil? && @post_form.nil? && @post_json.nil? + end + + # Whether the object has any non-default values. + sig { returns(T::Boolean) } + def present? + !@homebrew_curl.nil? || !@post_form.nil? || !@post_json.nil? + end + end + end +end diff --git a/Library/Homebrew/livecheck/strategy.rb b/Library/Homebrew/livecheck/strategy.rb index d591a7b7e9..56d0ecb168 100644 --- a/Library/Homebrew/livecheck/strategy.rb +++ b/Library/Homebrew/livecheck/strategy.rb @@ -2,6 +2,7 @@ # frozen_string_literal: true require "utils/curl" +require "livecheck/options" module Homebrew module Livecheck @@ -193,23 +194,16 @@ module Homebrew # collected into an array of hashes. # # @param url [String] the URL to fetch - # @param url_options [Hash] options to modify curl behavior - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Array] - sig { - params( - url: String, - url_options: T::Hash[Symbol, T.untyped], - homebrew_curl: T::Boolean, - ).returns(T::Array[T::Hash[String, String]]) - } - def self.page_headers(url, url_options: {}, homebrew_curl: false) + sig { params(url: String, options: Options).returns(T::Array[T::Hash[String, String]]) } + def self.page_headers(url, options: Options.new) headers = [] - if url_options[:post_form].present? || url_options[:post_json].present? + if options.post_form || options.post_json curl_post_args = ["--request", "POST", *post_args( - post_form: url_options[:post_form], - post_json: url_options[:post_json], + post_form: options.post_form, + post_json: options.post_json, )] end @@ -221,7 +215,7 @@ module Homebrew MAX_REDIRECTIONS.to_s, url, wanted_headers: ["location", "content-disposition"], - use_homebrew_curl: homebrew_curl, + use_homebrew_curl: options.homebrew_curl || false, user_agent:, **DEFAULT_CURL_OPTIONS, ) @@ -242,21 +236,14 @@ module Homebrew # array with the error message instead. # # @param url [String] the URL of the content to check - # @param url_options [Hash] options to modify curl behavior - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] - sig { - params( - url: String, - url_options: T::Hash[Symbol, T.untyped], - homebrew_curl: T::Boolean, - ).returns(T::Hash[Symbol, T.untyped]) - } - def self.page_content(url, url_options: {}, homebrew_curl: false) - if url_options[:post_form].present? || url_options[:post_json].present? + sig { params(url: String, options: Options).returns(T::Hash[Symbol, T.untyped]) } + def self.page_content(url, options: Options.new) + if options.post_form || options.post_json curl_post_args = ["--request", "POST", *post_args( - post_form: url_options[:post_form], - post_json: url_options[:post_json], + post_form: options.post_form, + post_json: options.post_json, )] end @@ -266,7 +253,9 @@ module Homebrew *curl_post_args, *PAGE_CONTENT_CURL_ARGS, url, **DEFAULT_CURL_OPTIONS, - use_homebrew_curl: homebrew_curl || !curl_supports_fail_with_body?, + use_homebrew_curl: options.homebrew_curl || + !curl_supports_fail_with_body? || + false, user_agent: ) next unless status.success? diff --git a/Library/Homebrew/livecheck/strategy/apache.rb b/Library/Homebrew/livecheck/strategy/apache.rb index 9c3554d398..f42c50495c 100644 --- a/Library/Homebrew/livecheck/strategy/apache.rb +++ b/Library/Homebrew/livecheck/strategy/apache.rb @@ -85,19 +85,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/bitbucket.rb b/Library/Homebrew/livecheck/strategy/bitbucket.rb index 56a53b18c5..47928faf59 100644 --- a/Library/Homebrew/livecheck/strategy/bitbucket.rb +++ b/Library/Homebrew/livecheck/strategy/bitbucket.rb @@ -93,19 +93,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/cpan.rb b/Library/Homebrew/livecheck/strategy/cpan.rb index 828e4034d3..528817e911 100644 --- a/Library/Homebrew/livecheck/strategy/cpan.rb +++ b/Library/Homebrew/livecheck/strategy/cpan.rb @@ -72,19 +72,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/crate.rb b/Library/Homebrew/livecheck/strategy/crate.rb index e37e3da27d..fbe7a862fa 100644 --- a/Library/Homebrew/livecheck/strategy/crate.rb +++ b/Library/Homebrew/livecheck/strategy/crate.rb @@ -73,19 +73,18 @@ module Homebrew # @param regex [Regexp, nil] a regex for matching versions in content # @param provided_content [String, nil] content to check instead of # fetching - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - homebrew_curl: T::Boolean, - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) match_data = { matches: {}, regex:, url: } match_data[:cached] = true if provided_content.is_a?(String) @@ -97,13 +96,7 @@ module Homebrew content = if provided_content provided_content else - match_data.merge!( - Strategy.page_content( - match_data[:url], - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(match_data[:url], options:)) match_data[:content] end return match_data unless content diff --git a/Library/Homebrew/livecheck/strategy/electron_builder.rb b/Library/Homebrew/livecheck/strategy/electron_builder.rb index ef1c935c58..b499ac892b 100644 --- a/Library/Homebrew/livecheck/strategy/electron_builder.rb +++ b/Library/Homebrew/livecheck/strategy/electron_builder.rb @@ -34,17 +34,18 @@ module Homebrew # @param regex [Regexp, nil] a regex used for matching versions # @param provided_content [String, nil] content to use in place of # fetching via `Strategy#page_content` + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) if regex.present? && block.blank? raise ArgumentError, "#{Utils.demodulize(name)} only supports a regex when using a `strategy` block" @@ -54,7 +55,7 @@ module Homebrew url:, regex:, provided_content:, - **unused, + options:, &block || proc { |yaml| yaml["version"] } ) end diff --git a/Library/Homebrew/livecheck/strategy/extract_plist.rb b/Library/Homebrew/livecheck/strategy/extract_plist.rb index be35992c4c..c35217a9db 100644 --- a/Library/Homebrew/livecheck/strategy/extract_plist.rb +++ b/Library/Homebrew/livecheck/strategy/extract_plist.rb @@ -79,17 +79,18 @@ module Homebrew # @param url [String, nil] an alternative URL to check for version # information # @param regex [Regexp, nil] a regex for use in a strategy block + # @param options [Options] options to modify behavior # @return [Hash] sig { params( cask: Cask::Cask, url: T.nilable(String), regex: T.nilable(Regexp), - _unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(cask:, url: nil, regex: nil, **_unused, &block) + def self.find_versions(cask:, url: nil, regex: nil, options: Options.new, &block) if regex.present? && block.blank? raise ArgumentError, "#{Utils.demodulize(name)} only supports a regex when using a `strategy` block" diff --git a/Library/Homebrew/livecheck/strategy/git.rb b/Library/Homebrew/livecheck/strategy/git.rb index b263404888..3af4e8f2c1 100644 --- a/Library/Homebrew/livecheck/strategy/git.rb +++ b/Library/Homebrew/livecheck/strategy/git.rb @@ -186,16 +186,17 @@ module Homebrew # # @param url [String] the URL of the Git repository to check # @param regex [Regexp, nil] a regex used for matching versions + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), - _unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **_unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) match_data = { matches: {}, regex:, url: } tags_data = tag_info(url, regex) diff --git a/Library/Homebrew/livecheck/strategy/github_latest.rb b/Library/Homebrew/livecheck/strategy/github_latest.rb index 4655ce1d1f..387239cae0 100644 --- a/Library/Homebrew/livecheck/strategy/github_latest.rb +++ b/Library/Homebrew/livecheck/strategy/github_latest.rb @@ -70,16 +70,17 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: Regexp, - _unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: GithubReleases::DEFAULT_REGEX, **_unused, &block) + def self.find_versions(url:, regex: GithubReleases::DEFAULT_REGEX, options: Options.new, &block) match_data = { matches: {}, regex:, url: } generated = generate_input_values(url) diff --git a/Library/Homebrew/livecheck/strategy/github_releases.rb b/Library/Homebrew/livecheck/strategy/github_releases.rb index a37b3a5611..aec819f2fb 100644 --- a/Library/Homebrew/livecheck/strategy/github_releases.rb +++ b/Library/Homebrew/livecheck/strategy/github_releases.rb @@ -124,16 +124,17 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: Regexp, - _unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: DEFAULT_REGEX, **_unused, &block) + def self.find_versions(url:, regex: DEFAULT_REGEX, options: Options.new, &block) match_data = { matches: {}, regex:, url: } generated = generate_input_values(url) diff --git a/Library/Homebrew/livecheck/strategy/gnome.rb b/Library/Homebrew/livecheck/strategy/gnome.rb index 9a8828d992..dd3a83e46e 100644 --- a/Library/Homebrew/livecheck/strategy/gnome.rb +++ b/Library/Homebrew/livecheck/strategy/gnome.rb @@ -74,22 +74,23 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) version_data = PageMatch.find_versions( - url: generated[:url], - regex: regex || generated[:regex], - **unused, + url: generated[:url], + regex: regex || generated[:regex], + options:, &block ) diff --git a/Library/Homebrew/livecheck/strategy/gnu.rb b/Library/Homebrew/livecheck/strategy/gnu.rb index 027c689506..3abd9bc15f 100644 --- a/Library/Homebrew/livecheck/strategy/gnu.rb +++ b/Library/Homebrew/livecheck/strategy/gnu.rb @@ -84,19 +84,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/hackage.rb b/Library/Homebrew/livecheck/strategy/hackage.rb index fea597c1a0..21143f7cf1 100644 --- a/Library/Homebrew/livecheck/strategy/hackage.rb +++ b/Library/Homebrew/livecheck/strategy/hackage.rb @@ -70,19 +70,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/header_match.rb b/Library/Homebrew/livecheck/strategy/header_match.rb index e6f2c3a3aa..b64e781056 100644 --- a/Library/Homebrew/livecheck/strategy/header_match.rb +++ b/Library/Homebrew/livecheck/strategy/header_match.rb @@ -67,25 +67,20 @@ module Homebrew # # @param url [String] the URL to fetch # @param regex [Regexp, nil] a regex used for matching versions - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - homebrew_curl: T::Boolean, - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) match_data = { matches: {}, regex:, url: } - headers = Strategy.page_headers( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ) + headers = Strategy.page_headers(url, options:) # Merge the headers from all responses into one hash merged_headers = headers.reduce(&:merge) diff --git a/Library/Homebrew/livecheck/strategy/json.rb b/Library/Homebrew/livecheck/strategy/json.rb index af681d9730..546bb3814d 100644 --- a/Library/Homebrew/livecheck/strategy/json.rb +++ b/Library/Homebrew/livecheck/strategy/json.rb @@ -94,19 +94,18 @@ module Homebrew # @param regex [Regexp, nil] a regex used for matching versions # @param provided_content [String, nil] page content to use in place of # fetching via `Strategy#page_content` - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - homebrew_curl: T::Boolean, - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) raise ArgumentError, "#{Utils.demodulize(name)} requires a `strategy` block" if block.blank? match_data = { matches: {}, regex:, url: } @@ -116,13 +115,7 @@ module Homebrew match_data[:cached] = true provided_content else - match_data.merge!( - Strategy.page_content( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(url, options:)) match_data[:content] end return match_data if content.blank? diff --git a/Library/Homebrew/livecheck/strategy/launchpad.rb b/Library/Homebrew/livecheck/strategy/launchpad.rb index 8fc33cfea1..c47679b856 100644 --- a/Library/Homebrew/livecheck/strategy/launchpad.rb +++ b/Library/Homebrew/livecheck/strategy/launchpad.rb @@ -67,19 +67,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: Regexp, - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: Regexp, + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: DEFAULT_REGEX, **unused, &block) + def self.find_versions(url:, regex: DEFAULT_REGEX, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex:, **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex:, + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/npm.rb b/Library/Homebrew/livecheck/strategy/npm.rb index b020e6a48e..8f12088d29 100644 --- a/Library/Homebrew/livecheck/strategy/npm.rb +++ b/Library/Homebrew/livecheck/strategy/npm.rb @@ -65,19 +65,25 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) - PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block) + PageMatch.find_versions( + url: generated[:url], + regex: regex || generated[:regex], + options:, + &block + ) end end end diff --git a/Library/Homebrew/livecheck/strategy/page_match.rb b/Library/Homebrew/livecheck/strategy/page_match.rb index 36397cd387..601930ba84 100644 --- a/Library/Homebrew/livecheck/strategy/page_match.rb +++ b/Library/Homebrew/livecheck/strategy/page_match.rb @@ -77,19 +77,18 @@ module Homebrew # @param regex [Regexp, nil] a regex used for matching versions # @param provided_content [String, nil] page content to use in place of # fetching via `Strategy#page_content` - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - homebrew_curl: T::Boolean, - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) if regex.blank? && block.blank? raise ArgumentError, "#{Utils.demodulize(name)} requires a regex or `strategy` block" end @@ -101,13 +100,7 @@ module Homebrew match_data[:cached] = true provided_content else - match_data.merge!( - Strategy.page_content( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(url, options:)) match_data[:content] end return match_data if content.blank? diff --git a/Library/Homebrew/livecheck/strategy/pypi.rb b/Library/Homebrew/livecheck/strategy/pypi.rb index 8711a2264a..b13042abe8 100644 --- a/Library/Homebrew/livecheck/strategy/pypi.rb +++ b/Library/Homebrew/livecheck/strategy/pypi.rb @@ -79,17 +79,18 @@ module Homebrew # @param regex [Regexp] a regex used for matching versions in content # @param provided_content [String, nil] content to check instead of # fetching + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) match_data = { matches: {}, regex:, url: } generated = generate_input_values(url) @@ -99,7 +100,7 @@ module Homebrew url: generated[:url], regex:, provided_content:, - **unused, + options:, &block || DEFAULT_BLOCK ) end diff --git a/Library/Homebrew/livecheck/strategy/sourceforge.rb b/Library/Homebrew/livecheck/strategy/sourceforge.rb index 539000b4f2..9096ae8629 100644 --- a/Library/Homebrew/livecheck/strategy/sourceforge.rb +++ b/Library/Homebrew/livecheck/strategy/sourceforge.rb @@ -84,22 +84,23 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) PageMatch.find_versions( - url: generated[:url] || url, - regex: regex || generated[:regex], - **unused, + url: generated[:url] || url, + regex: regex || generated[:regex], + options:, &block ) end diff --git a/Library/Homebrew/livecheck/strategy/sparkle.rb b/Library/Homebrew/livecheck/strategy/sparkle.rb index fac81a6a79..051880d320 100644 --- a/Library/Homebrew/livecheck/strategy/sparkle.rb +++ b/Library/Homebrew/livecheck/strategy/sparkle.rb @@ -214,18 +214,17 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp, nil] a regex for use in a strategy block - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - homebrew_curl: T::Boolean, - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) if regex.present? && block.blank? raise ArgumentError, "#{Utils.demodulize(name)} only supports a regex when using a `strategy` block" @@ -233,13 +232,7 @@ module Homebrew match_data = { matches: {}, regex:, url: } - match_data.merge!( - Strategy.page_content( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(url, options:)) content = match_data.delete(:content) return match_data if content.blank? diff --git a/Library/Homebrew/livecheck/strategy/xml.rb b/Library/Homebrew/livecheck/strategy/xml.rb index 08096a5102..2971014b87 100644 --- a/Library/Homebrew/livecheck/strategy/xml.rb +++ b/Library/Homebrew/livecheck/strategy/xml.rb @@ -134,19 +134,18 @@ module Homebrew # @param regex [Regexp, nil] a regex used for matching versions # @param provided_content [String, nil] page content to use in place of # fetching via `Strategy#page_content` - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - homebrew_curl: T::Boolean, - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) raise ArgumentError, "#{Utils.demodulize(name)} requires a `strategy` block" if block.blank? match_data = { matches: {}, regex:, url: } @@ -156,13 +155,7 @@ module Homebrew match_data[:cached] = true provided_content else - match_data.merge!( - Strategy.page_content( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(url, options:)) match_data[:content] end return match_data if content.blank? diff --git a/Library/Homebrew/livecheck/strategy/xorg.rb b/Library/Homebrew/livecheck/strategy/xorg.rb index ab5f4cef66..ac93e2726b 100644 --- a/Library/Homebrew/livecheck/strategy/xorg.rb +++ b/Library/Homebrew/livecheck/strategy/xorg.rb @@ -109,16 +109,17 @@ module Homebrew # # @param url [String] the URL of the content to check # @param regex [Regexp] a regex used for matching versions in content + # @param options [Options] options to modify behavior # @return [Hash] sig { params( - url: String, - regex: T.nilable(Regexp), - unused: T.untyped, - block: T.nilable(Proc), + url: String, + regex: T.nilable(Regexp), + options: Options, + block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, **unused, &block) + def self.find_versions(url:, regex: nil, options: Options.new, &block) generated = generate_input_values(url) generated_url = generated[:url] @@ -128,7 +129,7 @@ module Homebrew url: generated_url, regex: regex || generated[:regex], provided_content: cached_content, - **unused, + options:, &block ) diff --git a/Library/Homebrew/livecheck/strategy/yaml.rb b/Library/Homebrew/livecheck/strategy/yaml.rb index 0c89a14e17..e791cd81e2 100644 --- a/Library/Homebrew/livecheck/strategy/yaml.rb +++ b/Library/Homebrew/livecheck/strategy/yaml.rb @@ -94,19 +94,18 @@ module Homebrew # @param regex [Regexp, nil] a regex used for matching versions # @param provided_content [String, nil] page content to use in place of # fetching via `Strategy#page_content` - # @param homebrew_curl [Boolean] whether to use brewed curl with the URL + # @param options [Options] options to modify behavior # @return [Hash] sig { params( url: String, regex: T.nilable(Regexp), provided_content: T.nilable(String), - homebrew_curl: T::Boolean, - unused: T.untyped, + options: Options, block: T.nilable(Proc), ).returns(T::Hash[Symbol, T.untyped]) } - def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **unused, &block) + def self.find_versions(url:, regex: nil, provided_content: nil, options: Options.new, &block) raise ArgumentError, "#{Utils.demodulize(name)} requires a `strategy` block" if block.blank? match_data = { matches: {}, regex:, url: } @@ -116,13 +115,7 @@ module Homebrew match_data[:cached] = true provided_content else - match_data.merge!( - Strategy.page_content( - url, - url_options: unused.fetch(:url_options, {}), - homebrew_curl:, - ), - ) + match_data.merge!(Strategy.page_content(url, options:)) match_data[:content] end return match_data if content.blank? diff --git a/Library/Homebrew/test/livecheck/options_spec.rb b/Library/Homebrew/test/livecheck/options_spec.rb new file mode 100644 index 0000000000..38be0f0b9b --- /dev/null +++ b/Library/Homebrew/test/livecheck/options_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require "livecheck/options" + +RSpec.describe Homebrew::Livecheck::Options do + subject(:options) { described_class } + + let(:post_hash) do + { + empty: "", + boolean: "true", + number: "1", + string: "a + b = c", + } + end + let(:args) do + { + homebrew_curl: true, + post_form: post_hash, + post_json: post_hash, + } + end + let(:other_args) do + { + post_form: { something: "else" }, + } + end + let(:merged_hash) { args.merge(other_args) } + + describe "#url_options" do + it "returns a Hash of the options that are provided as arguments to the `url` DSL method" do + expect(options.new.url_options).to eq({ + homebrew_curl: nil, + post_form: nil, + post_json: nil, + }) + end + end + + describe "#to_h" do + it "returns a Hash of all instance variables" do + expect(options.new.to_h).to eq({ + homebrew_curl: nil, + post_form: nil, + post_json: nil, + }) + end + end + + describe "#to_hash" do + it "returns a Hash of all instance variables, using String keys" do + expect(options.new.to_hash).to eq({ + "homebrew_curl" => nil, + "post_form" => nil, + "post_json" => nil, + }) + end + end + + describe "#merge" do + it "returns an Options object with merged values" do + expect(options.new(**args).merge(other_args)) + .to eq(options.new(**merged_hash)) + expect(options.new(**args).merge(options.new(**other_args))) + .to eq(options.new(**merged_hash)) + expect(options.new(**args).merge(args)) + .to eq(options.new(**args)) + end + end + + describe "#==" do + it "returns true if all instance variables are the same" do + obj_with_args1 = options.new(**args) + obj_with_args2 = options.new(**args) + expect(obj_with_args1 == obj_with_args2).to be true + + default_obj1 = options.new + default_obj2 = options.new + expect(default_obj1 == default_obj2).to be true + end + + it "returns false if any instance variables differ" do + expect(options.new == options.new(**args)).to be false + end + end + + describe "#empty?" do + it "returns true if object has only default values" do + expect(options.new.empty?).to be true + end + + it "returns false if object has any non-default values" do + expect(options.new(**args).empty?).to be false + end + end + + describe "#present?" do + it "returns false if object has only default values" do + expect(options.new.present?).to be false + end + + it "returns true if object has any non-default values" do + expect(options.new(**args).present?).to be true + end + end +end diff --git a/Library/Homebrew/test/livecheck/strategy_spec.rb b/Library/Homebrew/test/livecheck/strategy_spec.rb index bb701e3b43..4ef416c331 100644 --- a/Library/Homebrew/test/livecheck/strategy_spec.rb +++ b/Library/Homebrew/test/livecheck/strategy_spec.rb @@ -181,8 +181,12 @@ RSpec.describe Homebrew::Livecheck::Strategy do it "handles `post_form` `url` options" do allow(strategy).to receive(:curl_headers).and_return({ responses:, body: }) - expect(strategy.page_headers(url, url_options: { post_form: post_hash })) - .to eq([responses.first[:headers]]) + expect( + strategy.page_headers( + url, + options: Homebrew::Livecheck::Options.new(post_form: post_hash), + ), + ).to eq([responses.first[:headers]]) end it "returns an empty array if `curl_headers` only raises an `ErrorDuringExecution` error" do @@ -207,14 +211,24 @@ RSpec.describe Homebrew::Livecheck::Strategy do allow_any_instance_of(Utils::Curl).to receive(:curl_version).and_return(curl_version) allow(strategy).to receive(:curl_output).and_return([response_text[:ok], nil, success_status]) - expect(strategy.page_content(url, url_options: { post_form: post_hash })).to eq({ content: body }) + expect( + strategy.page_content( + url, + options: Homebrew::Livecheck::Options.new(post_form: post_hash), + ), + ).to eq({ content: body }) end it "handles `post_json` `url` option" do allow_any_instance_of(Utils::Curl).to receive(:curl_version).and_return(curl_version) allow(strategy).to receive(:curl_output).and_return([response_text[:ok], nil, success_status]) - expect(strategy.page_content(url, url_options: { post_json: post_hash })).to eq({ content: body }) + expect( + strategy.page_content( + url, + options: Homebrew::Livecheck::Options.new(post_json: post_hash), + ), + ).to eq({ content: body }) end it "returns error `messages` from `stderr` in the return hash on failure when `stderr` is not `nil`" do diff --git a/Library/Homebrew/test/livecheck_spec.rb b/Library/Homebrew/test/livecheck_spec.rb index e52fd76265..ba5bde56e0 100644 --- a/Library/Homebrew/test/livecheck_spec.rb +++ b/Library/Homebrew/test/livecheck_spec.rb @@ -156,10 +156,17 @@ RSpec.describe Livecheck do expect(livecheck_c.url).to eq(:url) end - it "sets `url_options` when provided" do - post_args = { post_form: post_hash } - livecheck_f.url(url_string, **post_args) - expect(livecheck_f.url_options).to eq(post_args) + it "sets `url` options when provided" do + # This test makes sure that we can set multiple options at once and + # options from subsequent `url` calls are merged with existing values + # (i.e. existing values aren't reset to `nil`). [We only call `url` once + # in a `livecheck` block but this should technically work due to how it's + # implemented.] + livecheck_f.url(url_string, homebrew_curl: true, post_form: post_hash) + livecheck_f.url(url_string, post_json: post_hash) + expect(livecheck_f.options.homebrew_curl).to be(true) + expect(livecheck_f.options.post_form).to eq(post_hash) + expect(livecheck_f.options.post_json).to eq(post_hash) end it "raises an ArgumentError if the argument isn't a valid Symbol" do @@ -179,15 +186,15 @@ RSpec.describe Livecheck do it "returns a Hash of all instance variables" do expect(livecheck_f.to_hash).to eq( { - "cask" => nil, - "formula" => nil, - "regex" => nil, - "skip" => false, - "skip_msg" => nil, - "strategy" => nil, - "throttle" => nil, - "url" => nil, - "url_options" => nil, + "options" => Homebrew::Livecheck::Options.new.to_hash, + "cask" => nil, + "formula" => nil, + "regex" => nil, + "skip" => false, + "skip_msg" => nil, + "strategy" => nil, + "throttle" => nil, + "url" => nil, }, ) end