Merge pull request #12121 from EricFromCanada/restore-repology
bump: add `--start-with` option to retrieve a subset of results
This commit is contained in:
		
						commit
						b77b08cf00
					
				
							
								
								
									
										2
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							@ -309,6 +309,8 @@ jobs:
 | 
			
		||||
          brew sh -c "svn --homebrew=print-path"
 | 
			
		||||
          which svn
 | 
			
		||||
          which svnadmin
 | 
			
		||||
          brew install curl
 | 
			
		||||
          which curl
 | 
			
		||||
 | 
			
		||||
      - name: Create parallel test log directory
 | 
			
		||||
        run: mkdir tests
 | 
			
		||||
 | 
			
		||||
@ -192,6 +192,9 @@ module Homebrew
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def limit; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def start_with; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(String)) }
 | 
			
		||||
      def message; end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,8 +13,9 @@ module Homebrew
 | 
			
		||||
  def bump_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      description <<~EOS
 | 
			
		||||
        Display out-of-date brew formulae and the latest version available.
 | 
			
		||||
        Also displays whether a pull request has been opened with the URL.
 | 
			
		||||
        Display out-of-date brew formulae and the latest version available. If the
 | 
			
		||||
        returned current and livecheck versions differ or when querying specific
 | 
			
		||||
        formulae, also displays whether a pull request has been opened with the URL.
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "--full-name",
 | 
			
		||||
             description: "Print formulae/casks with fully-qualified names."
 | 
			
		||||
@ -26,6 +27,8 @@ module Homebrew
 | 
			
		||||
             description: "Check only casks."
 | 
			
		||||
      flag   "--limit=",
 | 
			
		||||
             description: "Limit number of package results returned."
 | 
			
		||||
      flag   "--start-with=",
 | 
			
		||||
             description: "Letter or word that the list of package results should alphabetically follow."
 | 
			
		||||
 | 
			
		||||
      conflicts "--cask", "--formula"
 | 
			
		||||
 | 
			
		||||
@ -53,6 +56,18 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    limit = args.limit.to_i if args.limit.present?
 | 
			
		||||
 | 
			
		||||
    unless quiet_system(HOMEBREW_SHIMS_PATH/"shared/curl", "--tlsv1.3", "--head", "https://repology.org/")
 | 
			
		||||
      begin
 | 
			
		||||
        brewed_curl = Formula["curl"]
 | 
			
		||||
        unless brewed_curl.any_version_installed?
 | 
			
		||||
          ohai "Installing `curl` for Repology queries..."
 | 
			
		||||
          safe_system HOMEBREW_BREW_FILE, "install", "--formula", brewed_curl.full_name
 | 
			
		||||
        end
 | 
			
		||||
      rescue FormulaUnavailableError
 | 
			
		||||
        opoo "A `curl` with TLS 1.3 support is required for Repology queries"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if formulae_and_casks.present?
 | 
			
		||||
      Livecheck.load_other_tap_strategies(formulae_and_casks)
 | 
			
		||||
 | 
			
		||||
@ -104,21 +119,25 @@ module Homebrew
 | 
			
		||||
      api_response = {}
 | 
			
		||||
      unless args.cask?
 | 
			
		||||
        api_response[:formulae] =
 | 
			
		||||
          Repology.parse_api_response(limit, repository: Repology::HOMEBREW_CORE)
 | 
			
		||||
          Repology.parse_api_response(limit, args.start_with, repository: Repology::HOMEBREW_CORE)
 | 
			
		||||
      end
 | 
			
		||||
      unless args.formula?
 | 
			
		||||
        api_response[:casks] =
 | 
			
		||||
          Repology.parse_api_response(limit, repository: Repology::HOMEBREW_CASK)
 | 
			
		||||
          Repology.parse_api_response(limit, args.start_with, repository: Repology::HOMEBREW_CASK)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      api_response.each do |package_type, outdated_packages|
 | 
			
		||||
      api_response.each_with_index do |(package_type, outdated_packages), idx|
 | 
			
		||||
        repository = if package_type == :formulae
 | 
			
		||||
          Repology::HOMEBREW_CORE
 | 
			
		||||
        else
 | 
			
		||||
          Repology::HOMEBREW_CASK
 | 
			
		||||
        end
 | 
			
		||||
        puts if idx.positive?
 | 
			
		||||
        oh1 package_type.capitalize if api_response.size > 1
 | 
			
		||||
 | 
			
		||||
        outdated_packages.each_with_index do |(_name, repositories), i|
 | 
			
		||||
          break if limit && i >= limit
 | 
			
		||||
 | 
			
		||||
          homebrew_repo = repositories.find do |repo|
 | 
			
		||||
            repo["repo"] == repository
 | 
			
		||||
          end
 | 
			
		||||
@ -143,8 +162,6 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
          puts if i.positive?
 | 
			
		||||
          retrieve_and_display_info(formula_or_cask, name, repositories, args: args, ambiguous_cask: ambiguous_cask)
 | 
			
		||||
 | 
			
		||||
          break if limit && i >= limit
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
@ -180,7 +197,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    return "unable to get versions" if latest.blank?
 | 
			
		||||
 | 
			
		||||
    latest.to_s
 | 
			
		||||
    Version.new(latest)
 | 
			
		||||
  rescue => e
 | 
			
		||||
    "error: #{e}"
 | 
			
		||||
  end
 | 
			
		||||
@ -211,22 +228,24 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    livecheck_latest = livecheck_result(formula_or_cask)
 | 
			
		||||
    pull_requests = retrieve_pull_requests(formula_or_cask, name) unless args.no_pull_requests?
 | 
			
		||||
    pull_requests = if !args.no_pull_requests? && (args.named.present? || livecheck_latest != current_version)
 | 
			
		||||
      retrieve_pull_requests(formula_or_cask, name)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    name += " (cask)" if ambiguous_cask
 | 
			
		||||
    title = if current_version == repology_latest &&
 | 
			
		||||
               current_version == livecheck_latest
 | 
			
		||||
      "#{name} is up to date!"
 | 
			
		||||
      "#{name} #{Tty.green}is up to date!#{Tty.reset}"
 | 
			
		||||
    else
 | 
			
		||||
      name
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    ohai title
 | 
			
		||||
    puts <<~EOS
 | 
			
		||||
      Current formula version:  #{current_version}
 | 
			
		||||
      Latest Repology version:  #{repology_latest}
 | 
			
		||||
      Current #{formula_or_cask.is_a?(Formula) ? "formula version:" : "cask version:   "}  #{current_version}
 | 
			
		||||
      Latest livecheck version: #{livecheck_latest}
 | 
			
		||||
      Latest Repology version:  #{repology_latest}
 | 
			
		||||
    EOS
 | 
			
		||||
    puts "Open pull requests:       #{pull_requests}" unless args.no_pull_requests?
 | 
			
		||||
    puts "Open pull requests:       #{pull_requests}" unless pull_requests.nil?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ require "cmd/shared_examples/args_parse"
 | 
			
		||||
describe "brew bump" do
 | 
			
		||||
  it_behaves_like "parseable arguments"
 | 
			
		||||
 | 
			
		||||
  describe "formula", :integration_test, :needs_network do
 | 
			
		||||
  describe "formula", :integration_test, :needs_network, :needs_tls13 do
 | 
			
		||||
    it "returns data for single valid specified formula" do
 | 
			
		||||
      install_test_formula "testball"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,15 @@ RSpec.configure do |config|
 | 
			
		||||
                      .append(svnadmin.dirname)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  config.before(:each, :needs_tls13) do
 | 
			
		||||
    begin
 | 
			
		||||
      curl = Utils::Curl.curl_executable(use_homebrew_curl: OS.mac?)
 | 
			
		||||
    rescue FormulaUnavailableError
 | 
			
		||||
      skip "curl formula not available"
 | 
			
		||||
    end
 | 
			
		||||
    skip "Requires curl with TLS 1.3 support." unless quiet_system curl, "--tlsv1.3", "--head", "https://brew.sh/"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  config.before(:each, :needs_unzip) do
 | 
			
		||||
    skip "Unzip is not installed." unless which("unzip")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
require "utils/repology"
 | 
			
		||||
 | 
			
		||||
describe Repology do
 | 
			
		||||
  describe "single_package_query", :needs_network do
 | 
			
		||||
  describe "single_package_query", :needs_network, :needs_tls13 do
 | 
			
		||||
    it "returns nil for non-existent package" do
 | 
			
		||||
      response = described_class.single_package_query("invalidName", repository: "homebrew")
 | 
			
		||||
 | 
			
		||||
@ -14,15 +14,12 @@ describe Repology do
 | 
			
		||||
    it "returns a hash for existing package" do
 | 
			
		||||
      response = described_class.single_package_query("openclonk", repository: "homebrew")
 | 
			
		||||
 | 
			
		||||
      expect(response).to be_nil
 | 
			
		||||
      # TODO: uncomment (and remove line above) when we have a fix for Repology
 | 
			
		||||
      # `curl` issues
 | 
			
		||||
      # expect(response).not_to be_nil
 | 
			
		||||
      # expect(response).to be_a(Hash)
 | 
			
		||||
      expect(response).not_to be_nil
 | 
			
		||||
      expect(response).to be_a(Hash)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "parse_api_response", :needs_network do
 | 
			
		||||
  describe "parse_api_response", :needs_network, :needs_tls13 do
 | 
			
		||||
    it "returns a hash of data" do
 | 
			
		||||
      limit = 1
 | 
			
		||||
      response = described_class.parse_api_response(limit, repository: "homebrew")
 | 
			
		||||
 | 
			
		||||
@ -357,6 +357,12 @@ module Utils
 | 
			
		||||
      file.unlink
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def homebrew_curl_available?
 | 
			
		||||
      Formulary.factory("curl").present?
 | 
			
		||||
    rescue FormulaUnavailableError
 | 
			
		||||
      false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def http_status_ok?(status)
 | 
			
		||||
      (100..299).cover?(status.to_i)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -15,33 +15,29 @@ module Repology
 | 
			
		||||
  MAX_PAGINATION = 15
 | 
			
		||||
  private_constant :MAX_PAGINATION
 | 
			
		||||
 | 
			
		||||
  def query_api(_last_package_in_response = "", repository:)
 | 
			
		||||
    {}
 | 
			
		||||
    # TODO: uncomment (and remove lines above) when we have a fix for Repology
 | 
			
		||||
    # `curl` issues
 | 
			
		||||
    # last_package_in_response += "/" if last_package_in_response.present?
 | 
			
		||||
    # url = "https://repology.org/api/v1/projects/#{last_package_in_response}?inrepo=#{repository}&outdated=1"
 | 
			
		||||
  def query_api(last_package_in_response = "", repository:)
 | 
			
		||||
    last_package_in_response += "/" if last_package_in_response.present?
 | 
			
		||||
    url = "https://repology.org/api/v1/projects/#{last_package_in_response}?inrepo=#{repository}&outdated=1"
 | 
			
		||||
 | 
			
		||||
    # output, _errors, _status = curl_output(url.to_s)
 | 
			
		||||
    # JSON.parse(output)
 | 
			
		||||
    output, _errors, _status = curl_output(url.to_s, use_homebrew_curl: OS.mac?)
 | 
			
		||||
    JSON.parse(output)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def single_package_query(name, repository:)
 | 
			
		||||
    # TODO: uncomment when we have a fix for Repology `curl` issues
 | 
			
		||||
    # url = "https://repology.org/tools/project-by?repo=#{repository}&" \
 | 
			
		||||
    #       "name_type=srcname&target_page=api_v1_project&name=#{name}"
 | 
			
		||||
    url = "https://repology.org/tools/project-by?repo=#{repository}&" \
 | 
			
		||||
          "name_type=srcname&target_page=api_v1_project&name=#{name}"
 | 
			
		||||
 | 
			
		||||
    # output, _errors, _status = curl_output("--location", url.to_s)
 | 
			
		||||
    output, _errors, _status = curl_output("--location", url.to_s, use_homebrew_curl: OS.mac?)
 | 
			
		||||
 | 
			
		||||
    # begin
 | 
			
		||||
    #   data = JSON.parse(output)
 | 
			
		||||
    #   { name => data }
 | 
			
		||||
    # rescue
 | 
			
		||||
    #   nil
 | 
			
		||||
    # end
 | 
			
		||||
    begin
 | 
			
		||||
      data = JSON.parse(output)
 | 
			
		||||
      { name => data }
 | 
			
		||||
    rescue
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def parse_api_response(limit = nil, repository:)
 | 
			
		||||
  def parse_api_response(limit = nil, last_package = "", repository:)
 | 
			
		||||
    package_term = case repository
 | 
			
		||||
    when HOMEBREW_CORE
 | 
			
		||||
      "formula"
 | 
			
		||||
@ -55,14 +51,13 @@ module Repology
 | 
			
		||||
 | 
			
		||||
    page_no = 1
 | 
			
		||||
    outdated_packages = {}
 | 
			
		||||
    last_package = ""
 | 
			
		||||
 | 
			
		||||
    while page_no <= MAX_PAGINATION
 | 
			
		||||
      odebug "Paginating Repology API page: #{page_no}"
 | 
			
		||||
 | 
			
		||||
      response = query_api(last_package, repository: repository)
 | 
			
		||||
      outdated_packages.merge!(response)
 | 
			
		||||
      last_package = response.keys.last
 | 
			
		||||
      last_package = response.keys.max
 | 
			
		||||
 | 
			
		||||
      page_no += 1
 | 
			
		||||
      break if (limit && outdated_packages.size >= limit) || response.size <= 1
 | 
			
		||||
@ -71,7 +66,7 @@ module Repology
 | 
			
		||||
    puts "#{outdated_packages.size} outdated #{package_term.pluralize(outdated_packages.size)} found"
 | 
			
		||||
    puts
 | 
			
		||||
 | 
			
		||||
    outdated_packages
 | 
			
		||||
    outdated_packages.sort.to_h
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def latest_version(repositories)
 | 
			
		||||
 | 
			
		||||
@ -437,6 +437,7 @@ _brew_bump() {
 | 
			
		||||
      --limit
 | 
			
		||||
      --no-pull-requests
 | 
			
		||||
      --quiet
 | 
			
		||||
      --start-with
 | 
			
		||||
      --verbose
 | 
			
		||||
      "
 | 
			
		||||
      return
 | 
			
		||||
 | 
			
		||||
@ -389,6 +389,7 @@ __fish_brew_complete_arg 'bump' -l help -d 'Show this message'
 | 
			
		||||
__fish_brew_complete_arg 'bump' -l limit -d 'Limit number of package results returned'
 | 
			
		||||
__fish_brew_complete_arg 'bump' -l no-pull-requests -d 'Do not retrieve pull requests from GitHub'
 | 
			
		||||
__fish_brew_complete_arg 'bump' -l quiet -d 'Make some output more quiet'
 | 
			
		||||
__fish_brew_complete_arg 'bump' -l start-with -d 'Letter or word that the list of package results should alphabetically follow'
 | 
			
		||||
__fish_brew_complete_arg 'bump' -l verbose -d 'Make some output more verbose'
 | 
			
		||||
__fish_brew_complete_arg 'bump; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)'
 | 
			
		||||
__fish_brew_complete_arg 'bump; and not __fish_seen_argument -l formula -l formulae' -a '(__fish_brew_suggest_casks_all)'
 | 
			
		||||
 | 
			
		||||
@ -479,6 +479,7 @@ _brew_bump() {
 | 
			
		||||
    '--limit[Limit number of package results returned]' \
 | 
			
		||||
    '--no-pull-requests[Do not retrieve pull requests from GitHub]' \
 | 
			
		||||
    '--quiet[Make some output more quiet]' \
 | 
			
		||||
    '--start-with[Letter or word that the list of package results should alphabetically follow]' \
 | 
			
		||||
    '--verbose[Make some output more verbose]' \
 | 
			
		||||
    - formula \
 | 
			
		||||
    '(--cask)--formula[Check only formulae]' \
 | 
			
		||||
 | 
			
		||||
@ -901,8 +901,9 @@ value, while `--no-rebuild` will remove it.
 | 
			
		||||
 | 
			
		||||
### `bump` [*`options`*] [*`formula`*|*`cask`* ...]
 | 
			
		||||
 | 
			
		||||
Display out-of-date brew formulae and the latest version available.
 | 
			
		||||
Also displays whether a pull request has been opened with the URL.
 | 
			
		||||
Display out-of-date brew formulae and the latest version available. If the
 | 
			
		||||
returned current and livecheck versions differ or when querying specific
 | 
			
		||||
formulae, also displays whether a pull request has been opened with the URL.
 | 
			
		||||
 | 
			
		||||
* `--full-name`:
 | 
			
		||||
  Print formulae/casks with fully-qualified names.
 | 
			
		||||
@ -914,6 +915,8 @@ Also displays whether a pull request has been opened with the URL.
 | 
			
		||||
  Check only casks.
 | 
			
		||||
* `--limit`:
 | 
			
		||||
  Limit number of package results returned.
 | 
			
		||||
* `--start-with`:
 | 
			
		||||
  Letter or word that the list of package results should alphabetically follow.
 | 
			
		||||
 | 
			
		||||
### `bump-cask-pr` [*`options`*] *`cask`*
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1265,7 +1265,7 @@ Use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew
 | 
			
		||||
Use the specified download strategy class for downloading the bottle\'s URL instead of Homebrew\'s default\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBbump\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR \.\.\.]"
 | 
			
		||||
Display out\-of\-date brew formulae and the latest version available\. Also displays whether a pull request has been opened with the URL\.
 | 
			
		||||
Display out\-of\-date brew formulae and the latest version available\. If the returned current and livecheck versions differ or when querying specific formulae, also displays whether a pull request has been opened with the URL\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-full\-name\fR
 | 
			
		||||
@ -1287,6 +1287,10 @@ Check only casks\.
 | 
			
		||||
\fB\-\-limit\fR
 | 
			
		||||
Limit number of package results returned\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-start\-with\fR
 | 
			
		||||
Letter or word that the list of package results should alphabetically follow\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBbump\-cask\-pr\fR [\fIoptions\fR] \fIcask\fR"
 | 
			
		||||
Create a pull request to update \fIcask\fR with a new version\.
 | 
			
		||||
.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user