 45978435e7
			
		
	
	
		45978435e7
		
			
		
	
	
	
	
		
			
			- Previously I thought that comments were fine to discourage people from wasting their time trying to bump things that used `undef` that Sorbet didn't support. But RuboCop is better at this since it'll complain if the comments are unnecessary. - Suggested in https://github.com/Homebrew/brew/pull/18018#issuecomment-2283369501. - I've gone for a mixture of `rubocop:disable` for the files that can't be `typed: strict` (use of undef, required before everything else, etc) and `rubocop:todo` for everything else that should be tried to make strictly typed. There's no functional difference between the two as `rubocop:todo` is `rubocop:disable` with a different name. - And I entirely disabled the cop for the docs/ directory since `typed: strict` isn't going to gain us anything for some Markdown linting config files. - This means that now it's easier to track what needs to be done rather than relying on checklists of files in our big Sorbet issue: ```shell $ git grep 'typed: true # rubocop:todo Sorbet/StrictSigil' | wc -l 268 ``` - And this is confirmed working for new files: ```shell $ git status On branch use-rubocop-for-sorbet-strict-sigils Untracked files: (use "git add <file>..." to include in what will be committed) Library/Homebrew/bad.rb Library/Homebrew/good.rb nothing added to commit but untracked files present (use "git add" to track) $ brew style Offenses: bad.rb:1:1: C: Sorbet/StrictSigil: Sorbet sigil should be at least strict got true. ^^^^^^^^^^^^^ 1340 files inspected, 1 offense detected ```
		
			
				
	
	
		
			103 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # typed: true # rubocop:todo Sorbet/StrictSigil
 | |
| # frozen_string_literal: true
 | |
| 
 | |
| require "utils/curl"
 | |
| 
 | |
| # Repology API client.
 | |
| module Repology
 | |
|   HOMEBREW_CORE = "homebrew"
 | |
|   HOMEBREW_CASK = "homebrew_casks"
 | |
|   MAX_PAGINATION = 15
 | |
|   private_constant :MAX_PAGINATION
 | |
| 
 | |
|   def self.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, = Utils::Curl.curl_output(url.to_s, "--silent",
 | |
|                                               use_homebrew_curl: !Utils::Curl.curl_supports_tls13?)
 | |
|     JSON.parse(output)
 | |
|   rescue
 | |
|     if Homebrew::EnvConfig.developer?
 | |
|       $stderr.puts errors
 | |
|     else
 | |
|       odebug errors
 | |
|     end
 | |
| 
 | |
|     raise
 | |
|   end
 | |
| 
 | |
|   def self.single_package_query(name, repository:)
 | |
|     url = "https://repology.org/api/v1/project/#{name}"
 | |
| 
 | |
|     output, errors, = Utils::Curl.curl_output("--location", "--silent", url.to_s,
 | |
|                                               use_homebrew_curl: !Utils::Curl.curl_supports_tls13?)
 | |
| 
 | |
|     data = JSON.parse(output)
 | |
|     { name => data }
 | |
|   rescue => e
 | |
|     require "utils/backtrace"
 | |
|     error_output = [errors, "#{e.class}: #{e}", Utils::Backtrace.clean(e)].compact
 | |
|     if Homebrew::EnvConfig.developer?
 | |
|       $stderr.puts(*error_output)
 | |
|     else
 | |
|       odebug(*error_output)
 | |
|     end
 | |
| 
 | |
|     nil
 | |
|   end
 | |
| 
 | |
|   def self.parse_api_response(limit = nil, last_package = "", repository:)
 | |
|     package_term = case repository
 | |
|     when HOMEBREW_CORE
 | |
|       "formulae"
 | |
|     when HOMEBREW_CASK
 | |
|       "casks"
 | |
|     else
 | |
|       "packages"
 | |
|     end
 | |
| 
 | |
|     ohai "Querying outdated #{package_term} from Repology"
 | |
| 
 | |
|     page_no = 1
 | |
|     outdated_packages = {}
 | |
| 
 | |
|     while page_no <= MAX_PAGINATION
 | |
|       odebug "Paginating Repology API page: #{page_no}"
 | |
| 
 | |
|       response = query_api(last_package, repository:)
 | |
|       outdated_packages.merge!(response)
 | |
|       last_package = response.keys.max
 | |
| 
 | |
|       page_no += 1
 | |
|       break if (limit && outdated_packages.size >= limit) || response.size <= 1
 | |
|     end
 | |
| 
 | |
|     package_term = package_term.chop if outdated_packages.size == 1
 | |
|     puts "#{outdated_packages.size} outdated #{package_term} found"
 | |
|     puts
 | |
| 
 | |
|     outdated_packages.sort.to_h
 | |
|   end
 | |
| 
 | |
|   def self.latest_version(repositories)
 | |
|     # The status is "unique" when the package is present only in Homebrew, so
 | |
|     # Repology has no way of knowing if the package is up-to-date.
 | |
|     is_unique = repositories.find do |repo|
 | |
|       repo["status"] == "unique"
 | |
|     end.present?
 | |
| 
 | |
|     return "present only in Homebrew" if is_unique
 | |
| 
 | |
|     latest_version = repositories.find do |repo|
 | |
|       repo["status"] == "newest"
 | |
|     end
 | |
| 
 | |
|     # Repology cannot identify "newest" versions for packages without a version
 | |
|     # scheme
 | |
|     return "no latest version" if latest_version.blank?
 | |
| 
 | |
|     Version.new(latest_version["version"])
 | |
|   end
 | |
| end
 |