Merge pull request #17606 from Homebrew/sorbet-strict-devcmd
This commit is contained in:
		
						commit
						3773940382
					
				@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -329,6 +329,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(results: T::Hash[[Symbol, Pathname], T::Array[T::Hash[Symbol, T.untyped]]]).void }
 | 
			
		||||
      def print_problems(results)
 | 
			
		||||
        results.each do |(name, path), problems|
 | 
			
		||||
          problem_lines = format_problem_lines(problems)
 | 
			
		||||
@ -343,6 +344,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(problems: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[String]) }
 | 
			
		||||
      def format_problem_lines(problems)
 | 
			
		||||
        problems.map do |problem|
 | 
			
		||||
          status = " #{Formatter.success("[corrected]")}" if problem.fetch(:corrected)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -20,7 +20,7 @@ module Homebrew
 | 
			
		||||
    class Bottle < AbstractCommand
 | 
			
		||||
      include FileUtils
 | 
			
		||||
 | 
			
		||||
      BOTTLE_ERB = <<-EOS.freeze
 | 
			
		||||
      BOTTLE_ERB = T.let(<<-EOS.freeze, String)
 | 
			
		||||
  bottle do
 | 
			
		||||
    <% if  [HOMEBREW_BOTTLE_DEFAULT_DOMAIN.to_s,
 | 
			
		||||
           "#{HOMEBREW_BOTTLE_DEFAULT_DOMAIN}/bottles"].exclude?(root_url) %>
 | 
			
		||||
@ -39,9 +39,9 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      MAXIMUM_STRING_MATCHES = 100
 | 
			
		||||
 | 
			
		||||
      ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = [
 | 
			
		||||
      ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = T.let([
 | 
			
		||||
        %r{#{Regexp.escape(HOMEBREW_LIBRARY)}/Homebrew/os/(mac|linux)/pkgconfig},
 | 
			
		||||
      ].freeze
 | 
			
		||||
      ].freeze, T::Array[Regexp])
 | 
			
		||||
 | 
			
		||||
      cmd_args do
 | 
			
		||||
        description <<~EOS
 | 
			
		||||
@ -110,6 +110,10 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(tag: Symbol, digest: T.any(Checksum, String), cellar: T.nilable(T.any(String, Symbol)),
 | 
			
		||||
               tag_column: Integer, digest_column: Integer).returns(String)
 | 
			
		||||
      }
 | 
			
		||||
      def generate_sha256_line(tag, digest, cellar, tag_column, digest_column)
 | 
			
		||||
        line = "sha256 "
 | 
			
		||||
        tag_column += line.length
 | 
			
		||||
@ -125,6 +129,7 @@ module Homebrew
 | 
			
		||||
        %Q(#{line}"#{digest}")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(bottle: BottleSpecification, root_url_using: T.nilable(String)).returns(String) }
 | 
			
		||||
      def bottle_output(bottle, root_url_using)
 | 
			
		||||
        cellars = bottle.checksums.filter_map do |checksum|
 | 
			
		||||
          cellar = checksum["cellar"]
 | 
			
		||||
@ -153,12 +158,14 @@ module Homebrew
 | 
			
		||||
        erb.result(erb_binding).gsub(/^\s*$\n/, "")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(filenames: T::Array[String]).returns(T::Array[T::Hash[String, T.untyped]]) }
 | 
			
		||||
      def parse_json_files(filenames)
 | 
			
		||||
        filenames.map do |filename|
 | 
			
		||||
          JSON.parse(File.read(filename))
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(json_files: T::Array[T::Hash[String, T.untyped]]).returns(T::Hash[String, T.untyped]) }
 | 
			
		||||
      def merge_json_files(json_files)
 | 
			
		||||
        json_files.reduce({}) do |hash, json_file|
 | 
			
		||||
          json_file.each_value do |json_hash|
 | 
			
		||||
@ -172,6 +179,10 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(old_keys: T::Array[String], old_bottle_spec: BottleSpecification,
 | 
			
		||||
               new_bottle_hash: T::Hash[String, T.untyped]).returns(T::Array[T::Array[String]])
 | 
			
		||||
      }
 | 
			
		||||
      def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash)
 | 
			
		||||
        mismatches = []
 | 
			
		||||
        checksums = []
 | 
			
		||||
@ -214,16 +225,20 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(string: String, keg: Keg, ignores: T::Array[String],
 | 
			
		||||
               formula_and_runtime_deps_names: T.nilable(T::Array[String])).returns(T::Boolean)
 | 
			
		||||
      }
 | 
			
		||||
      def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil)
 | 
			
		||||
        @put_string_exists_header, @put_filenames = nil
 | 
			
		||||
 | 
			
		||||
        print_filename = lambda do |str, filename|
 | 
			
		||||
          unless @put_string_exists_header
 | 
			
		||||
            opoo "String '#{str}' still exists in these files:"
 | 
			
		||||
            @put_string_exists_header = true
 | 
			
		||||
            @put_string_exists_header = T.let(true, T.nilable(T::Boolean))
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          @put_filenames ||= []
 | 
			
		||||
          @put_filenames ||= T.let([], T.nilable(T::Array[T.any(String, Pathname)]))
 | 
			
		||||
 | 
			
		||||
          return false if @put_filenames.include?(filename)
 | 
			
		||||
 | 
			
		||||
@ -265,6 +280,7 @@ module Homebrew
 | 
			
		||||
        keg_contain_absolute_symlink_starting_with?(string, keg) || result
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(string: String, keg: Keg).returns(T::Boolean) }
 | 
			
		||||
      def keg_contain_absolute_symlink_starting_with?(string, keg)
 | 
			
		||||
        absolute_symlinks_start_with_string = []
 | 
			
		||||
        keg.find do |pn|
 | 
			
		||||
@ -283,6 +299,7 @@ module Homebrew
 | 
			
		||||
        !absolute_symlinks_start_with_string.empty?
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(cellar: T.nilable(T.any(String, Symbol))).returns(T::Boolean) }
 | 
			
		||||
      def cellar_parameter_needed?(cellar)
 | 
			
		||||
        default_cellars = [
 | 
			
		||||
          Homebrew::DEFAULT_MACOS_CELLAR,
 | 
			
		||||
@ -292,6 +309,7 @@ module Homebrew
 | 
			
		||||
        cellar.present? && default_cellars.exclude?(cellar)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(T::Boolean)) }
 | 
			
		||||
      def sudo_purge
 | 
			
		||||
        return unless ENV["HOMEBREW_BOTTLE_SUDO_PURGE"]
 | 
			
		||||
 | 
			
		||||
@ -354,6 +372,7 @@ module Homebrew
 | 
			
		||||
        [gnu_tar(gnu_tar_formula), reproducible_gnutar_args(mtime)].freeze
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: T.untyped).returns(T::Array[T.untyped]) }
 | 
			
		||||
      def formula_ignores(formula)
 | 
			
		||||
        ignores = []
 | 
			
		||||
        cellar_regex = Regexp.escape(HOMEBREW_CELLAR)
 | 
			
		||||
@ -384,6 +403,7 @@ module Homebrew
 | 
			
		||||
        ignores.compact
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula).void }
 | 
			
		||||
      def bottle_formula(formula)
 | 
			
		||||
        local_bottle_json = args.json? && formula.local_bottle_path.present?
 | 
			
		||||
 | 
			
		||||
@ -453,6 +473,8 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
        if local_bottle_json
 | 
			
		||||
          bottle_path = formula.local_bottle_path
 | 
			
		||||
          return if bottle_path.blank?
 | 
			
		||||
 | 
			
		||||
          local_filename = bottle_path.basename.to_s
 | 
			
		||||
 | 
			
		||||
          tab_path = Utils::Bottles.receipt_path(bottle_path)
 | 
			
		||||
@ -471,6 +493,7 @@ module Homebrew
 | 
			
		||||
        else
 | 
			
		||||
          tar_filename = filename.to_s.sub(/.gz$/, "")
 | 
			
		||||
          tar_path = Pathname.pwd/tar_filename
 | 
			
		||||
          return if tar_path.blank?
 | 
			
		||||
 | 
			
		||||
          keg = Keg.new(formula.prefix)
 | 
			
		||||
        end
 | 
			
		||||
@ -681,6 +704,7 @@ module Homebrew
 | 
			
		||||
        json_path.write(JSON.pretty_generate(json))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Hash[String, T.untyped]) }
 | 
			
		||||
      def merge
 | 
			
		||||
        bottles_hash = merge_json_files(parse_json_files(args.named))
 | 
			
		||||
 | 
			
		||||
@ -750,7 +774,7 @@ module Homebrew
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          all_bottle_hash = T.let(nil, T.nilable(Hash))
 | 
			
		||||
          all_bottle_hash = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
 | 
			
		||||
          bottle_hash["bottle"]["tags"].each do |tag, tag_hash|
 | 
			
		||||
            filename = ::Bottle::Filename.new(
 | 
			
		||||
              formula_name,
 | 
			
		||||
@ -801,7 +825,7 @@ module Homebrew
 | 
			
		||||
          checksums = old_checksums(formula, formula_ast, bottle_hash)
 | 
			
		||||
          update_or_add = checksums.nil? ? "add" : "update"
 | 
			
		||||
 | 
			
		||||
          checksums&.each(&bottle.method(:sha256))
 | 
			
		||||
          checksums&.each { |checksum| bottle.sha256(checksum) }
 | 
			
		||||
          output = bottle_output(bottle, args.root_url_using)
 | 
			
		||||
          puts output
 | 
			
		||||
 | 
			
		||||
@ -835,8 +859,12 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(formula: Formula, formula_ast: Utils::AST::FormulaAST,
 | 
			
		||||
               bottle_hash: T::Hash[String, T.untyped]).returns(T.nilable(T::Array[String]))
 | 
			
		||||
      }
 | 
			
		||||
      def old_checksums(formula, formula_ast, bottle_hash)
 | 
			
		||||
        bottle_node = formula_ast.bottle_block
 | 
			
		||||
        bottle_node = T.cast(formula_ast.bottle_block, T.nilable(RuboCop::AST::BlockNode))
 | 
			
		||||
        return if bottle_node.nil?
 | 
			
		||||
        return [] unless args.keep_old?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -145,10 +145,10 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
        old_mirrors = formula_spec.mirrors
 | 
			
		||||
        new_mirrors ||= args.mirror
 | 
			
		||||
        new_mirror ||= determine_mirror(new_url)
 | 
			
		||||
        new_mirrors ||= [new_mirror] if new_mirror.present?
 | 
			
		||||
 | 
			
		||||
        check_for_mirrors(formula, old_mirrors, new_mirrors) if new_url.present?
 | 
			
		||||
        if new_url.present? && (new_mirror = determine_mirror(new_url))
 | 
			
		||||
          new_mirrors ||= [new_mirror]
 | 
			
		||||
          check_for_mirrors(formula, old_mirrors, new_mirrors)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        old_hash = formula_spec.checksum&.hexdigest
 | 
			
		||||
        new_hash = args.sha256
 | 
			
		||||
@ -190,12 +190,14 @@ module Homebrew
 | 
			
		||||
        elsif new_url.blank? && new_version.blank?
 | 
			
		||||
          raise UsageError, "#{formula}: no `--url` or `--version` argument specified!"
 | 
			
		||||
        else
 | 
			
		||||
          new_url ||= PyPI.update_pypi_url(old_url, T.must(new_version))
 | 
			
		||||
          return unless new_version.present?
 | 
			
		||||
 | 
			
		||||
          new_url ||= PyPI.update_pypi_url(old_url, new_version)
 | 
			
		||||
          if new_url.blank?
 | 
			
		||||
            new_url = update_url(old_url, old_version, T.must(new_version))
 | 
			
		||||
            new_url = update_url(old_url, old_version, new_version)
 | 
			
		||||
            if new_mirrors.blank? && old_mirrors.present?
 | 
			
		||||
              new_mirrors = old_mirrors.map do |old_mirror|
 | 
			
		||||
                update_url(old_mirror, old_version, T.must(new_version))
 | 
			
		||||
                update_url(old_mirror, old_version, new_version)
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
@ -271,9 +273,9 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
        old_contents = formula.path.read
 | 
			
		||||
 | 
			
		||||
        if new_mirrors.present?
 | 
			
		||||
        if new_mirrors.present? && new_url.present?
 | 
			
		||||
          replacement_pairs << [
 | 
			
		||||
            /^( +)(url "#{Regexp.escape(T.must(new_url))}"[^\n]*?\n)/m,
 | 
			
		||||
            /^( +)(url "#{Regexp.escape(new_url)}"[^\n]*?\n)/m,
 | 
			
		||||
            "\\1\\2\\1mirror \"#{new_mirrors.join("\"\n\\1mirror \"")}\"\n",
 | 
			
		||||
          ]
 | 
			
		||||
        end
 | 
			
		||||
@ -395,6 +397,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(url: String).returns(T.nilable(String)) }
 | 
			
		||||
      def determine_mirror(url)
 | 
			
		||||
        case url
 | 
			
		||||
        when %r{.*ftp\.gnu\.org/gnu.*}
 | 
			
		||||
@ -408,6 +411,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: String, old_mirrors: T::Array[String], new_mirrors: T::Array[String]).void }
 | 
			
		||||
      def check_for_mirrors(formula, old_mirrors, new_mirrors)
 | 
			
		||||
        return if new_mirrors.present? || old_mirrors.empty?
 | 
			
		||||
 | 
			
		||||
@ -427,11 +431,17 @@ module Homebrew
 | 
			
		||||
        return new_url if (old_version_parts = old_version.split(".")).length < 2
 | 
			
		||||
        return new_url if (new_version_parts = new_version.split(".")).length != old_version_parts.length
 | 
			
		||||
 | 
			
		||||
        partial_old_version = T.must(old_version_parts[0..-2]).join(".")
 | 
			
		||||
        partial_new_version = T.must(new_version_parts[0..-2]).join(".")
 | 
			
		||||
        partial_old_version = old_version_parts[0..-2]&.join(".")
 | 
			
		||||
        partial_new_version = new_version_parts[0..-2]&.join(".")
 | 
			
		||||
        return new_url if partial_old_version.blank? || partial_new_version.blank?
 | 
			
		||||
 | 
			
		||||
        new_url.gsub(%r{/(v?)#{Regexp.escape(partial_old_version)}/}, "/\\1#{partial_new_version}/")
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(formula: Formula, new_version: T.nilable(String), url: String,
 | 
			
		||||
               specs: Float).returns(T::Array[T.untyped])
 | 
			
		||||
      }
 | 
			
		||||
      def fetch_resource_and_forced_version(formula, new_version, url, **specs)
 | 
			
		||||
        resource = Resource.new
 | 
			
		||||
        resource.url(url, **specs)
 | 
			
		||||
@ -442,6 +452,7 @@ module Homebrew
 | 
			
		||||
        [resource.fetch, forced_version]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula, contents: T.nilable(String)).returns(String) }
 | 
			
		||||
      def formula_version(formula, contents = nil)
 | 
			
		||||
        spec = :stable
 | 
			
		||||
        name = formula.name
 | 
			
		||||
@ -453,17 +464,29 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula, tap_remote_repo: String).returns(T.nilable(T::Array[String])) }
 | 
			
		||||
      def check_open_pull_requests(formula, tap_remote_repo)
 | 
			
		||||
        GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo,
 | 
			
		||||
                                                 state: "open",
 | 
			
		||||
                                                 file:  formula.path.relative_path_from(formula.tap.path).to_s,
 | 
			
		||||
                                                 quiet: args.quiet?)
 | 
			
		||||
        tap = formula.tap
 | 
			
		||||
        return if tap.nil?
 | 
			
		||||
 | 
			
		||||
        GitHub.check_for_duplicate_pull_requests(
 | 
			
		||||
          formula.name, tap_remote_repo,
 | 
			
		||||
          state: "open",
 | 
			
		||||
          file:  formula.path.relative_path_from(tap.path).to_s,
 | 
			
		||||
          quiet: args.quiet?
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(formula: Formula, tap_remote_repo: String, version: T.nilable(String), url: T.nilable(String),
 | 
			
		||||
               tag: T.nilable(String)).void
 | 
			
		||||
      }
 | 
			
		||||
      def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil)
 | 
			
		||||
        if version.nil?
 | 
			
		||||
          specs = {}
 | 
			
		||||
          specs[:tag] = tag if tag.present?
 | 
			
		||||
          return if url.blank?
 | 
			
		||||
 | 
			
		||||
          version = Version.detect(url, **specs).to_s
 | 
			
		||||
          return if version.blank?
 | 
			
		||||
        end
 | 
			
		||||
@ -472,9 +495,13 @@ module Homebrew
 | 
			
		||||
        check_closed_pull_requests(formula, tap_remote_repo, version:)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula, new_version: String).returns(NilClass) }
 | 
			
		||||
      def check_throttle(formula, new_version)
 | 
			
		||||
        tap = formula.tap
 | 
			
		||||
        return if tap.nil?
 | 
			
		||||
 | 
			
		||||
        throttled_rate = formula.livecheck.throttle
 | 
			
		||||
        throttled_rate ||= if (rate = formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name))
 | 
			
		||||
        throttled_rate ||= if (rate = tap.audit_exceptions.dig(:throttled_formulae, formula.name))
 | 
			
		||||
          odisabled "throttled_formulae.json", "Livecheck#throttle"
 | 
			
		||||
          rate
 | 
			
		||||
        end
 | 
			
		||||
@ -486,27 +513,41 @@ module Homebrew
 | 
			
		||||
        odie "#{formula} should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(formula: Formula, tap_remote_repo: String,
 | 
			
		||||
               version: T.nilable(String)).returns(T.nilable(T::Array[String]))
 | 
			
		||||
      }
 | 
			
		||||
      def check_closed_pull_requests(formula, tap_remote_repo, version:)
 | 
			
		||||
        tap = formula.tap
 | 
			
		||||
        return if tap.nil?
 | 
			
		||||
 | 
			
		||||
        # if we haven't already found open requests, try for an exact match across closed requests
 | 
			
		||||
        GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo,
 | 
			
		||||
                                                 version:,
 | 
			
		||||
                                                 state:   "closed",
 | 
			
		||||
                                                 file:    formula.path.relative_path_from(formula.tap.path).to_s,
 | 
			
		||||
                                                 quiet:   args.quiet?)
 | 
			
		||||
        GitHub.check_for_duplicate_pull_requests(
 | 
			
		||||
          formula.name, tap_remote_repo,
 | 
			
		||||
          version:,
 | 
			
		||||
          state:   "closed",
 | 
			
		||||
          file:    formula.path.relative_path_from(tap.path).to_s,
 | 
			
		||||
          quiet:   args.quiet?
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula, new_formula_version: String).returns(T.nilable(T::Array[String])) }
 | 
			
		||||
      def alias_update_pair(formula, new_formula_version)
 | 
			
		||||
        versioned_alias = formula.aliases.grep(/^.*@\d+(\.\d+)?$/).first
 | 
			
		||||
        return if versioned_alias.nil?
 | 
			
		||||
 | 
			
		||||
        name, old_alias_version = versioned_alias.split("@")
 | 
			
		||||
        return if old_alias_version.blank?
 | 
			
		||||
 | 
			
		||||
        new_alias_regex = (old_alias_version.split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/
 | 
			
		||||
        new_alias_version, = *new_formula_version.to_s.match(new_alias_regex)
 | 
			
		||||
        return if new_alias_version.blank?
 | 
			
		||||
        return if Version.new(new_alias_version) <= Version.new(old_alias_version)
 | 
			
		||||
 | 
			
		||||
        [versioned_alias, "#{name}@#{new_alias_version}"]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula, alias_rename: T.nilable(T::Array[String]), old_contents: String).void }
 | 
			
		||||
      def run_audit(formula, alias_rename, old_contents)
 | 
			
		||||
        audit_args = ["--formula"]
 | 
			
		||||
        audit_args << "--strict" if args.strict?
 | 
			
		||||
@ -521,7 +562,9 @@ module Homebrew
 | 
			
		||||
          end
 | 
			
		||||
          return
 | 
			
		||||
        end
 | 
			
		||||
        FileUtils.mv alias_rename.first, alias_rename.last if alias_rename.present?
 | 
			
		||||
        if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last)
 | 
			
		||||
          FileUtils.mv source, destination
 | 
			
		||||
        end
 | 
			
		||||
        failed_audit = false
 | 
			
		||||
        if args.no_audit?
 | 
			
		||||
          ohai "Skipping `brew audit`"
 | 
			
		||||
@ -535,7 +578,9 @@ module Homebrew
 | 
			
		||||
        return unless failed_audit
 | 
			
		||||
 | 
			
		||||
        formula.path.atomic_write(old_contents)
 | 
			
		||||
        FileUtils.mv alias_rename.last, alias_rename.first if alias_rename.present?
 | 
			
		||||
        if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last)
 | 
			
		||||
          FileUtils.mv source, destination
 | 
			
		||||
        end
 | 
			
		||||
        odie "`brew audit` failed!"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -10,12 +10,12 @@ end
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module DevCmd
 | 
			
		||||
    class Contributions < AbstractCommand
 | 
			
		||||
      PRIMARY_REPOS = %w[brew core cask].freeze
 | 
			
		||||
      SUPPORTED_REPOS = [
 | 
			
		||||
      PRIMARY_REPOS = T.let(%w[brew core cask].freeze, T::Array[String])
 | 
			
		||||
      SUPPORTED_REPOS = T.let([
 | 
			
		||||
        PRIMARY_REPOS,
 | 
			
		||||
        OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") },
 | 
			
		||||
        OFFICIAL_CASK_TAPS.reject { |t| t == "cask" },
 | 
			
		||||
      ].flatten.freeze
 | 
			
		||||
      ].flatten.freeze, T::Array[String])
 | 
			
		||||
      MAX_REPO_COMMITS = 1000
 | 
			
		||||
 | 
			
		||||
      cmd_args do
 | 
			
		||||
@ -50,9 +50,9 @@ module Homebrew
 | 
			
		||||
        results = {}
 | 
			
		||||
        grand_totals = {}
 | 
			
		||||
 | 
			
		||||
        repos = if args.repositories.blank? || T.must(args.repositories).include?("primary")
 | 
			
		||||
        repos = if args.repositories.blank? || args.repositories&.include?("primary")
 | 
			
		||||
          PRIMARY_REPOS
 | 
			
		||||
        elsif T.must(args.repositories).include?("all")
 | 
			
		||||
        elsif args.repositories&.include?("all")
 | 
			
		||||
          SUPPORTED_REPOS
 | 
			
		||||
        else
 | 
			
		||||
          args.repositories
 | 
			
		||||
@ -116,7 +116,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(totals: Hash).returns(String) }
 | 
			
		||||
      sig { params(totals: T::Hash[String, T::Hash[Symbol, Integer]]).returns(String) }
 | 
			
		||||
      def generate_csv(totals)
 | 
			
		||||
        CSV.generate do |csv|
 | 
			
		||||
          csv << %w[user repo author committer coauthor review total]
 | 
			
		||||
@ -127,7 +127,14 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(user: String, grand_total: Hash).returns(Array) }
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          user:        String,
 | 
			
		||||
          grand_total: T::Hash[Symbol, Integer],
 | 
			
		||||
        ).returns(
 | 
			
		||||
          [String, String, T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), Integer],
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      def grand_total_row(user, grand_total)
 | 
			
		||||
        [
 | 
			
		||||
          user,
 | 
			
		||||
@ -140,7 +147,10 @@ module Homebrew
 | 
			
		||||
        ]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(repos: T.nilable(T::Array[String]), person: String, from: String).void }
 | 
			
		||||
      def scan_repositories(repos, person, from:)
 | 
			
		||||
        return if repos.blank?
 | 
			
		||||
 | 
			
		||||
        data = {}
 | 
			
		||||
 | 
			
		||||
        repos.each do |repo|
 | 
			
		||||
@ -168,7 +178,7 @@ module Homebrew
 | 
			
		||||
          data[repo] = {
 | 
			
		||||
            author:    author_commits,
 | 
			
		||||
            committer: committer_commits,
 | 
			
		||||
            coauthor:  git_log_trailers_cmd(T.must(repo_path), person, "Co-authored-by", from:, to: args.to),
 | 
			
		||||
            coauthor:  git_log_trailers_cmd(repo_path, person, "Co-authored-by", from:, to: args.to),
 | 
			
		||||
            review:    count_reviews(repo_full_name, person, from:, to: args.to),
 | 
			
		||||
          }
 | 
			
		||||
        end
 | 
			
		||||
@ -176,7 +186,7 @@ module Homebrew
 | 
			
		||||
        data
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(results: Hash).returns(Hash) }
 | 
			
		||||
      sig { params(results: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, Integer]) }
 | 
			
		||||
      def total(results)
 | 
			
		||||
        totals = { author: 0, committer: 0, coauthor: 0, review: 0 }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: true # This cannot be `# typed: strict` due to the use of `undef`.
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -71,6 +71,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(title: String).returns(String) }
 | 
			
		||||
      def html_template(title)
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          ---
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -69,6 +69,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(title: String).returns(String) }
 | 
			
		||||
      def html_template(title)
 | 
			
		||||
        <<~EOS
 | 
			
		||||
          ---
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,20 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
require "formula"
 | 
			
		||||
require "formulary"
 | 
			
		||||
require "cask/cask_loader"
 | 
			
		||||
 | 
			
		||||
class String
 | 
			
		||||
  # @!visibility private
 | 
			
		||||
  sig { params(args: Integer).returns(Formula) }
 | 
			
		||||
  def f(*args)
 | 
			
		||||
    require "formula"
 | 
			
		||||
    Formulary.factory(self, *args)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # @!visibility private
 | 
			
		||||
  sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) }
 | 
			
		||||
  def c(config: nil)
 | 
			
		||||
    Cask::CaskLoader.load(self, config:)
 | 
			
		||||
  end
 | 
			
		||||
@ -20,11 +22,13 @@ end
 | 
			
		||||
 | 
			
		||||
class Symbol
 | 
			
		||||
  # @!visibility private
 | 
			
		||||
  sig { params(args: Integer).returns(Formula) }
 | 
			
		||||
  def f(*args)
 | 
			
		||||
    to_s.f(*args)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # @!visibility private
 | 
			
		||||
  sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) }
 | 
			
		||||
  def c(config: nil)
 | 
			
		||||
    to_s.c(config:)
 | 
			
		||||
  end
 | 
			
		||||
@ -72,7 +76,6 @@ module Homebrew
 | 
			
		||||
          require "irb"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        require "formula"
 | 
			
		||||
        require "keg"
 | 
			
		||||
        require "cask"
 | 
			
		||||
 | 
			
		||||
@ -94,6 +97,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      # Remove the `--debug`, `--verbose` and `--quiet` options which cause problems
 | 
			
		||||
      # for IRB and have already been parsed by the CLI::Parser.
 | 
			
		||||
      sig { returns(T.nilable(T::Array[Symbol])) }
 | 
			
		||||
      def clean_argv
 | 
			
		||||
        global_options = Homebrew::CLI::Parser
 | 
			
		||||
                         .global_options
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -113,8 +113,9 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { returns(String) }
 | 
			
		||||
      def watchlist_path
 | 
			
		||||
        @watchlist_path ||= File.expand_path(Homebrew::EnvConfig.livecheck_watchlist)
 | 
			
		||||
        @watchlist_path ||= T.let(File.expand_path(Homebrew::EnvConfig.livecheck_watchlist), T.nilable(String))
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -141,7 +141,7 @@ module Homebrew
 | 
			
		||||
                  user, repo, pr, workflow_id: workflow, artifact_pattern:
 | 
			
		||||
                )
 | 
			
		||||
                if args.ignore_missing_artifacts.present? &&
 | 
			
		||||
                   T.must(args.ignore_missing_artifacts).include?(workflow) &&
 | 
			
		||||
                   args.ignore_missing_artifacts&.include?(workflow) &&
 | 
			
		||||
                   workflow_run.first.blank?
 | 
			
		||||
                  # Ignore that workflow as it was not executed and we specified
 | 
			
		||||
                  # that we could skip it.
 | 
			
		||||
@ -183,8 +183,10 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Separates a commit message into subject, body and trailers.
 | 
			
		||||
      sig { params(message: String).returns([String, String, String]) }
 | 
			
		||||
      def separate_commit_message(message)
 | 
			
		||||
        subject = message.lines.first.strip
 | 
			
		||||
        first_line = message.lines.first
 | 
			
		||||
        return ["", "", ""] unless first_line
 | 
			
		||||
 | 
			
		||||
        # Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by")
 | 
			
		||||
        # from lines that look like regular body text.
 | 
			
		||||
@ -193,11 +195,15 @@ module Homebrew
 | 
			
		||||
        trailers = trailers.uniq.join.strip
 | 
			
		||||
        body = body.join.strip.gsub(/\n{3,}/, "\n\n")
 | 
			
		||||
 | 
			
		||||
        [subject, body, trailers]
 | 
			
		||||
        [first_line.strip, body, trailers]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(git_repo: GitRepository, pull_request: T.nilable(String), dry_run: T::Boolean).void }
 | 
			
		||||
      def signoff!(git_repo, pull_request: nil, dry_run: false)
 | 
			
		||||
        subject, body, trailers = separate_commit_message(git_repo.commit_message)
 | 
			
		||||
        msg = git_repo.commit_message
 | 
			
		||||
        return if msg.blank?
 | 
			
		||||
 | 
			
		||||
        subject, body, trailers = separate_commit_message(msg)
 | 
			
		||||
 | 
			
		||||
        if pull_request
 | 
			
		||||
          # This is a tap pull request and approving reviewers should also sign-off.
 | 
			
		||||
@ -210,7 +216,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
          # Append the close message as well, unless the commit body already includes it.
 | 
			
		||||
          close_message = "Closes ##{pull_request}."
 | 
			
		||||
          body += "\n\n#{close_message}" unless body.include? close_message
 | 
			
		||||
          body.concat("\n\n#{close_message}") unless body.include?(close_message)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        git_args = Utils::Git.git, "-C", git_repo.pathname, "commit", "--amend", "--signoff", "--allow-empty",
 | 
			
		||||
@ -223,6 +229,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(tap: Tap, subject_name: String, subject_path: Pathname, content: String).returns(T.untyped) }
 | 
			
		||||
      def get_package(tap, subject_name, subject_path, content)
 | 
			
		||||
        if subject_path.to_s.start_with?("#{tap.cask_dir}/")
 | 
			
		||||
          cask = begin
 | 
			
		||||
@ -240,6 +247,10 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(old_contents: String, new_contents: String, subject_path: T.any(String, Pathname),
 | 
			
		||||
               reason: T.nilable(String)).returns(String)
 | 
			
		||||
      }
 | 
			
		||||
      def determine_bump_subject(old_contents, new_contents, subject_path, reason: nil)
 | 
			
		||||
        subject_path = Pathname(subject_path)
 | 
			
		||||
        tap          = Tap.from_path(subject_path)
 | 
			
		||||
@ -268,6 +279,10 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      # Cherry picks a single commit that modifies a single file.
 | 
			
		||||
      # Potentially rewords this commit using {determine_bump_subject}.
 | 
			
		||||
      sig {
 | 
			
		||||
        params(commit: String, file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean,
 | 
			
		||||
               resolve: T::Boolean).void
 | 
			
		||||
      }
 | 
			
		||||
      def reword_package_commit(commit, file, git_repo:, reason: "", verbose: false, resolve: false)
 | 
			
		||||
        package_file = git_repo.pathname / file
 | 
			
		||||
        package_name = package_file.basename.to_s.chomp(".rb")
 | 
			
		||||
@ -279,7 +294,10 @@ module Homebrew
 | 
			
		||||
        new_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD")
 | 
			
		||||
 | 
			
		||||
        bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:).strip
 | 
			
		||||
        subject, body, trailers = separate_commit_message(git_repo.commit_message)
 | 
			
		||||
        msg = git_repo.commit_message
 | 
			
		||||
        return if msg.blank?
 | 
			
		||||
 | 
			
		||||
        subject, body, trailers = separate_commit_message(msg)
 | 
			
		||||
 | 
			
		||||
        if subject != bump_subject && !subject.start_with?("#{package_name}:")
 | 
			
		||||
          safe_system("git", "-C", git_repo.pathname, "commit", "--amend", "-q",
 | 
			
		||||
@ -293,6 +311,10 @@ module Homebrew
 | 
			
		||||
      # Cherry picks multiple commits that each modify a single file.
 | 
			
		||||
      # Words the commit according to {determine_bump_subject} with the body
 | 
			
		||||
      # corresponding to all the original commit messages combined.
 | 
			
		||||
      sig {
 | 
			
		||||
        params(commits: T::Array[String], file: String, git_repo: GitRepository, reason: T.nilable(String),
 | 
			
		||||
               verbose: T::Boolean, resolve: T::Boolean).void
 | 
			
		||||
      }
 | 
			
		||||
      def squash_package_commits(commits, file, git_repo:, reason: "", verbose: false, resolve: false)
 | 
			
		||||
        odebug "Squashing #{file}: #{commits.join " "}"
 | 
			
		||||
 | 
			
		||||
@ -304,7 +326,10 @@ module Homebrew
 | 
			
		||||
        messages = []
 | 
			
		||||
        trailers = []
 | 
			
		||||
        commits.each do |commit|
 | 
			
		||||
          subject, body, trailer = separate_commit_message(git_repo.commit_message(commit))
 | 
			
		||||
          msg = git_repo.commit_message(commit)
 | 
			
		||||
          next if msg.blank?
 | 
			
		||||
 | 
			
		||||
          subject, body, trailer = separate_commit_message(msg)
 | 
			
		||||
          body = body.lines.map { |line| "  #{line.strip}" }.join("\n")
 | 
			
		||||
          messages << "* #{subject}\n#{body}".strip
 | 
			
		||||
          trailers << trailer
 | 
			
		||||
@ -340,9 +365,12 @@ module Homebrew
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`.
 | 
			
		||||
      sig {
 | 
			
		||||
        params(original_commit: String, tap: Tap, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean,
 | 
			
		||||
               cherry_picked: T::Boolean).void
 | 
			
		||||
      }
 | 
			
		||||
      def autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true)
 | 
			
		||||
        git_repo = tap.git_repository
 | 
			
		||||
        original_head = git_repo.head_ref
 | 
			
		||||
 | 
			
		||||
        commits = Utils.safe_popen_read("git", "-C", tap.path, "rev-list",
 | 
			
		||||
                                        "--reverse", "#{original_commit}..HEAD").lines.map(&:strip)
 | 
			
		||||
@ -402,14 +430,18 @@ module Homebrew
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      rescue
 | 
			
		||||
        original_head = git_repo&.head_ref
 | 
			
		||||
        return if original_head.nil?
 | 
			
		||||
 | 
			
		||||
        opoo "Autosquash encountered an error; resetting to original state at #{original_head}"
 | 
			
		||||
        system "git", "-C", tap.path, "reset", "--hard", original_head
 | 
			
		||||
        system "git", "-C", tap.path, "cherry-pick", "--abort" if cherry_picked
 | 
			
		||||
        system "git", "-C", tap.path.to_s, "reset", "--hard", original_head
 | 
			
		||||
        system "git", "-C", tap.path.to_s, "cherry-pick", "--abort" if cherry_picked
 | 
			
		||||
        raise
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(user: String, repo: String, pull_request: String, path: T.any(String, Pathname)).void }
 | 
			
		||||
      def cherry_pick_pr!(user, repo, pull_request, path: ".")
 | 
			
		||||
        if args.dry_run?
 | 
			
		||||
          puts <<~EOS
 | 
			
		||||
@ -427,6 +459,7 @@ module Homebrew
 | 
			
		||||
                                                                         resolve: args.resolve?)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(tap: Tap, original_commit: String, labels: T::Array[String]).returns(T::Boolean) }
 | 
			
		||||
      def formulae_need_bottles?(tap, original_commit, labels)
 | 
			
		||||
        return false if args.dry_run?
 | 
			
		||||
 | 
			
		||||
@ -437,6 +470,7 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(tap: Tap, original_commit: String).returns(T::Array[String]) }
 | 
			
		||||
      def changed_packages(tap, original_commit)
 | 
			
		||||
        formulae = Utils.popen_read("git", "-C", tap.path, "diff-tree",
 | 
			
		||||
                                    "-r", "--name-only", "--diff-filter=AM",
 | 
			
		||||
@ -473,6 +507,7 @@ module Homebrew
 | 
			
		||||
        formulae + casks
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(repo: String, pull_request: String).void }
 | 
			
		||||
      def pr_check_conflicts(repo, pull_request)
 | 
			
		||||
        long_build_pr_files = GitHub.issues(
 | 
			
		||||
          repo:, state: "open", labels: "no long build conflict",
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -120,6 +120,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(bottles_hash: T::Hash[String, T.untyped]).void }
 | 
			
		||||
      def check_bottled_formulae!(bottles_hash)
 | 
			
		||||
        bottles_hash.each do |name, bottle_hash|
 | 
			
		||||
          formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]
 | 
			
		||||
@ -131,22 +132,25 @@ module Homebrew
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
 | 
			
		||||
      def github_releases?(bottles_hash)
 | 
			
		||||
        @github_releases ||= bottles_hash.values.all? do |bottle_hash|
 | 
			
		||||
        @github_releases ||= T.let(bottles_hash.values.all? do |bottle_hash|
 | 
			
		||||
          root_url = bottle_hash["bottle"]["root_url"]
 | 
			
		||||
          url_match = root_url.match GitHubReleases::URL_REGEX
 | 
			
		||||
          _, _, _, tag = *url_match
 | 
			
		||||
 | 
			
		||||
          tag
 | 
			
		||||
        end
 | 
			
		||||
        end, T.nilable(T::Boolean))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
 | 
			
		||||
      def github_packages?(bottles_hash)
 | 
			
		||||
        @github_packages ||= bottles_hash.values.all? do |bottle_hash|
 | 
			
		||||
        @github_packages ||= T.let(bottles_hash.values.all? do |bottle_hash|
 | 
			
		||||
          bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX
 | 
			
		||||
        end
 | 
			
		||||
        end, T.nilable(T::Boolean))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(json_files: T::Array[String], args: T.untyped).returns(T::Hash[String, T.untyped]) }
 | 
			
		||||
      def bottles_hash_from_json_files(json_files, args)
 | 
			
		||||
        puts "Reading JSON files: #{json_files.join(", ")}" if args.verbose?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -197,6 +197,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(tap: Tap, filename: T.any(String, Pathname), content: String).void }
 | 
			
		||||
      def write_path(tap, filename, content)
 | 
			
		||||
        path = tap.path/filename
 | 
			
		||||
        tap.path.mkpath
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -110,8 +110,9 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(formula: Formula).returns(T::Boolean) }
 | 
			
		||||
      def retry_test?(formula)
 | 
			
		||||
        @test_failed ||= Set.new
 | 
			
		||||
        @test_failed ||= T.let(Set.new, T.nilable(T::Set[T.untyped]))
 | 
			
		||||
        if args.retry? && @test_failed.add?(formula)
 | 
			
		||||
          oh1 "Testing #{formula.full_name} (again)"
 | 
			
		||||
          formula.clear_cache
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -168,15 +168,17 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { returns(T.nilable(T::Boolean)) }
 | 
			
		||||
      def use_buildpulse?
 | 
			
		||||
        return @use_buildpulse if defined?(@use_buildpulse)
 | 
			
		||||
 | 
			
		||||
        @use_buildpulse = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? &&
 | 
			
		||||
        @use_buildpulse = T.let(ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? &&
 | 
			
		||||
                          ENV["HOMEBREW_BUILDPULSE_SECRET_ACCESS_KEY"].present? &&
 | 
			
		||||
                          ENV["HOMEBREW_BUILDPULSE_ACCOUNT_ID"].present? &&
 | 
			
		||||
                          ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?
 | 
			
		||||
                          ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?, T.nilable(T::Boolean))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { void }
 | 
			
		||||
      def run_buildpulse
 | 
			
		||||
        require "formula"
 | 
			
		||||
 | 
			
		||||
@ -198,6 +200,7 @@ module Homebrew
 | 
			
		||||
                       ]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Array[String]) }
 | 
			
		||||
      def changed_test_files
 | 
			
		||||
        changed_files = Utils.popen_read("git", "diff", "--name-only", "master")
 | 
			
		||||
 | 
			
		||||
@ -215,6 +218,7 @@ module Homebrew
 | 
			
		||||
        end.select(&:exist?)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Array[String]) }
 | 
			
		||||
      def setup_environment!
 | 
			
		||||
        # Cleanup any unwanted user configuration.
 | 
			
		||||
        allowed_test_env = %w[
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -34,11 +34,15 @@ module Homebrew
 | 
			
		||||
      def run
 | 
			
		||||
        Formulary.enable_factory_cache!
 | 
			
		||||
 | 
			
		||||
        @bottle_tag = if (tag = args.tag)
 | 
			
		||||
          Utils::Bottles::Tag.from_symbol(tag.to_sym)
 | 
			
		||||
        else
 | 
			
		||||
          Utils::Bottles.tag
 | 
			
		||||
        end
 | 
			
		||||
        @bottle_tag = T.let(
 | 
			
		||||
          if (tag = args.tag)
 | 
			
		||||
            Utils::Bottles::Tag.from_symbol(tag.to_sym)
 | 
			
		||||
          else
 | 
			
		||||
            Utils::Bottles.tag
 | 
			
		||||
          end,
 | 
			
		||||
          T.nilable(Utils::Bottles::Tag),
 | 
			
		||||
        )
 | 
			
		||||
        return unless @bottle_tag
 | 
			
		||||
 | 
			
		||||
        if args.lost?
 | 
			
		||||
          if args.named.present?
 | 
			
		||||
@ -98,12 +102,17 @@ module Homebrew
 | 
			
		||||
            ["installs", formula_installs]
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          return if hash.nil?
 | 
			
		||||
 | 
			
		||||
          output_unbottled(formulae, deps_hash, noun, hash, args.named.present?)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(all: T::Boolean).returns([T::Array[Formula], T::Array[Formula], T.nilable(T::Hash[Symbol, Integer])])
 | 
			
		||||
      }
 | 
			
		||||
      def formulae_all_installs_from_args(all)
 | 
			
		||||
        if args.named.present?
 | 
			
		||||
          formulae = all_formulae = args.named.to_formulae
 | 
			
		||||
@ -115,7 +124,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
          formulae = all_formulae = Formula.all(eval_all: args.eval_all?)
 | 
			
		||||
 | 
			
		||||
          @sort = " (sorted by number of dependents)"
 | 
			
		||||
          @sort = T.let(" (sorted by number of dependents)", T.nilable(String))
 | 
			
		||||
        elsif all
 | 
			
		||||
          formulae = all_formulae = Formula.all(eval_all: args.eval_all?)
 | 
			
		||||
        else
 | 
			
		||||
@ -142,7 +151,7 @@ module Homebrew
 | 
			
		||||
              nil
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          @sort = " (sorted by installs in the last 90 days; top 10,000 only)"
 | 
			
		||||
          @sort = T.let(" (sorted by installs in the last 90 days; top 10,000 only)", T.nilable(String))
 | 
			
		||||
 | 
			
		||||
          all_formulae = Formula.all(eval_all: args.eval_all?)
 | 
			
		||||
        end
 | 
			
		||||
@ -151,9 +160,11 @@ module Homebrew
 | 
			
		||||
        formulae = Array(formulae).reject(&:deprecated?) if formulae.present?
 | 
			
		||||
        all_formulae = Array(all_formulae).reject(&:deprecated?) if all_formulae.present?
 | 
			
		||||
 | 
			
		||||
        [formulae, all_formulae, formula_installs]
 | 
			
		||||
        [T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]),
 | 
			
		||||
         T.let(formula_installs, T.nilable(T::Hash[Symbol, Integer]))]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(all_formulae: T.untyped).returns([T::Hash[String, T.untyped], T::Hash[String, T.untyped]]) }
 | 
			
		||||
      def deps_uses_from_formulae(all_formulae)
 | 
			
		||||
        ohai "Populating dependency tree..."
 | 
			
		||||
 | 
			
		||||
@ -175,7 +186,10 @@ module Homebrew
 | 
			
		||||
        [deps_hash, uses_hash]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(formulae: T::Array[Formula]).returns(NilClass) }
 | 
			
		||||
      def output_total(formulae)
 | 
			
		||||
        return unless @bottle_tag
 | 
			
		||||
 | 
			
		||||
        ohai "Unbottled :#{@bottle_tag} formulae"
 | 
			
		||||
        unbottled_formulae = 0
 | 
			
		||||
 | 
			
		||||
@ -188,7 +202,14 @@ module Homebrew
 | 
			
		||||
        puts "#{unbottled_formulae}/#{formulae.length} remaining."
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(formulae: T::Array[Formula], deps_hash: T::Hash[T.any(Symbol, String), T.untyped],
 | 
			
		||||
               noun: T.nilable(String), hash: T::Hash[T.any(Symbol, String), T.untyped],
 | 
			
		||||
               any_named_args: T::Boolean).returns(NilClass)
 | 
			
		||||
      }
 | 
			
		||||
      def output_unbottled(formulae, deps_hash, noun, hash, any_named_args)
 | 
			
		||||
        return unless @bottle_tag
 | 
			
		||||
 | 
			
		||||
        ohai ":#{@bottle_tag} bottle status#{@sort}"
 | 
			
		||||
        any_found = T.let(false, T::Boolean)
 | 
			
		||||
 | 
			
		||||
@ -258,6 +279,7 @@ module Homebrew
 | 
			
		||||
        puts "No unbottled dependencies found!"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { returns(NilClass) }
 | 
			
		||||
      def output_lost_bottles
 | 
			
		||||
        ohai ":#{@bottle_tag} lost bottles"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "abstract_command"
 | 
			
		||||
@ -62,14 +62,17 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      private
 | 
			
		||||
 | 
			
		||||
      sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
 | 
			
		||||
      def sponsor_name(sponsor)
 | 
			
		||||
        sponsor[:name] || sponsor[:login]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) }
 | 
			
		||||
      def sponsor_logo(sponsor)
 | 
			
		||||
        "https://github.com/#{sponsor[:login]}.png?size=64"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) }
 | 
			
		||||
      def sponsor_url(sponsor)
 | 
			
		||||
        "https://github.com/#{sponsor[:login]}"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user