diff --git a/Library/Homebrew/livecheck/strategy.rb b/Library/Homebrew/livecheck/strategy.rb index abe14e200f868..3e9e1bef7c032 100644 --- a/Library/Homebrew/livecheck/strategy.rb +++ b/Library/Homebrew/livecheck/strategy.rb @@ -65,13 +65,16 @@ module Strategy # Baseline `curl` options used in {Strategy} methods. DEFAULT_CURL_OPTIONS = { - print_stdout: false, - print_stderr: false, + # By default, `Utils::Curl` methods will print text (e.g. the command) + # when `--debug` is set. `debug` is set to `false` to ensure that this + # unwanted text doesn't appear in livecheck's debug output. debug: false, - verbose: false, timeout: CURL_PROCESS_TIMEOUT, connect_timeout: CURL_CONNECT_TIMEOUT, max_time: CURL_MAX_TIME, + # `Utils::Curl` uses curl's `--retry` option by default but this isn't + # valuable enough in the context of livecheck to justify the additional + # effort. A zero value ensures that the `--retry` option is omitted. retries: 0, }.freeze diff --git a/Library/Homebrew/livecheck/strategy/github_latest.rb b/Library/Homebrew/livecheck/strategy/github_latest.rb index 92792059b3895..8cb4bf67f800f 100644 --- a/Library/Homebrew/livecheck/strategy/github_latest.rb +++ b/Library/Homebrew/livecheck/strategy/github_latest.rb @@ -72,7 +72,7 @@ def self.generate_input_values(url) match = url.sub(/\.git$/i, "").match(URL_MATCH_REGEX) return values if match.blank? - values[:url] = "https://api.github.com/repos/#{match[:username]}/#{match[:repository]}/releases/latest" + values[:url] = "#{GitHub::API_URL}/repos/#{match[:username]}/#{match[:repository]}/releases/latest" values[:username] = match[:username] values[:repository] = match[:repository] @@ -141,7 +141,11 @@ def self.find_versions(url:, regex: DEFAULT_REGEX, **_unused, &block) match_data[:url] = generated[:url] - release = GitHub.get_latest_release(generated[:username], generated[:repository]) + release = GitHub.get_latest_release( + generated[:username], + generated[:repository], + **Strategy::DEFAULT_CURL_OPTIONS, + ) versions_from_content(release, regex, &block).each do |match_text| match_data[:matches][match_text] = Version.new(match_text) end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index 830c6c5a811c9..0efbbd9daed2b 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -248,9 +248,36 @@ def self.get_release(user, repo, tag) API.open_rest(url, request_method: :GET) end - def self.get_latest_release(user, repo) + sig { + params( + user: String, + repo: String, + debug: T.nilable(T::Boolean), + timeout: T.nilable(T.any(Integer, Float)), + connect_timeout: T.nilable(T.any(Integer, Float)), + max_time: T.nilable(T.any(Integer, Float)), + retries: T.nilable(Integer), + ).returns(T::Hash[String, T.untyped]) + } + def self.get_latest_release( + user, + repo, + debug: nil, + timeout: nil, + connect_timeout: nil, + max_time: nil, + retries: nil + ) url = "#{API_URL}/repos/#{user}/#{repo}/releases/latest" - API.open_rest(url, request_method: :GET) + + curl_options = { + debug: debug, + timeout: timeout, + connect_timeout: connect_timeout, + max_time: max_time, + retries: retries, + }.compact + API.open_rest(url, request_method: :GET, **curl_options) end def self.generate_release_notes(user, repo, tag, previous_tag: nil) diff --git a/Library/Homebrew/utils/github/api.rb b/Library/Homebrew/utils/github/api.rb index d5e9bdb4ddfdd..787e923d76708 100644 --- a/Library/Homebrew/utils/github/api.rb +++ b/Library/Homebrew/utils/github/api.rb @@ -180,8 +180,33 @@ def self.credentials_error_message(response_headers, needed_scopes) EOS end + sig { + params( + url: T.any(String, URI::HTTPS), + data: T.nilable(T::Hash[String, T.untyped]), + data_binary_path: T.nilable(String), + request_method: T.nilable(Symbol), + scopes: Array, + parse_json: T::Boolean, + debug: T.nilable(T::Boolean), + timeout: T.nilable(T.any(Integer, Float)), + connect_timeout: T.nilable(T.any(Integer, Float)), + max_time: T.nilable(T.any(Integer, Float)), + retries: T.nilable(Integer), + ).returns(T.untyped) + } def self.open_rest( - url, data: nil, data_binary_path: nil, request_method: nil, scopes: [].freeze, parse_json: true + url, + data: nil, + data_binary_path: nil, + request_method: nil, + scopes: [].freeze, + parse_json: true, + debug: nil, + timeout: nil, + connect_timeout: nil, + max_time: nil, + retries: nil ) # This is a no-op if the user is opting out of using the GitHub API. return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api? @@ -222,7 +247,15 @@ def self.open_rest( args += ["--dump-header", T.must(headers_tmpfile.path)] - output, errors, status = curl_output("--location", url.to_s, *args, secrets: [token]) + curl_options = { + debug: debug, + timeout: timeout, + connect_timeout: connect_timeout, + max_time: max_time, + retries: retries, + }.compact + + output, errors, status = curl_output("--location", url.to_s, *args, secrets: [token], **curl_options) output, _, http_code = output.rpartition("\n") output, _, http_code = output.rpartition("\n") if http_code == "000" headers = headers_tmpfile.read @@ -262,7 +295,7 @@ def self.paginate_rest(url, additional_query_params: nil, per_page: 100) def self.open_graphql(query, variables: nil, scopes: [].freeze, raise_errors: true) data = { query: query, variables: variables } - result = open_rest("#{API_URL}/graphql", scopes: scopes, data: data, request_method: "POST") + result = open_rest("#{API_URL}/graphql", scopes: scopes, data: data, request_method: :POST) if raise_errors if result["errors"].present?