167 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # typed: true
 | |
| # frozen_string_literal: true
 | |
| 
 | |
| require "cli/parser"
 | |
| require "formula"
 | |
| require "github_packages"
 | |
| require "github_releases"
 | |
| require "extend/hash/deep_merge"
 | |
| 
 | |
| module Homebrew
 | |
|   module_function
 | |
| 
 | |
|   sig { returns(CLI::Parser) }
 | |
|   def pr_upload_args
 | |
|     Homebrew::CLI::Parser.new do
 | |
|       description <<~EOS
 | |
|         Apply the bottle commit and publish bottles to a host.
 | |
|       EOS
 | |
|       switch "--keep-old",
 | |
|              description: "If the formula specifies a rebuild version, " \
 | |
|                           "attempt to preserve its value in the generated DSL."
 | |
|       switch "-n", "--dry-run",
 | |
|              description: "Print what would be done rather than doing it."
 | |
|       switch "--no-commit",
 | |
|              description: "Do not generate a new commit before uploading."
 | |
|       switch "--warn-on-upload-failure",
 | |
|              description: "Warn instead of raising an error if the bottle upload fails. " \
 | |
|                           "Useful for repairing bottle uploads that previously failed."
 | |
|       switch "--upload-only",
 | |
|              description: "Skip running `brew bottle` before uploading."
 | |
|       flag   "--committer=",
 | |
|              description: "Specify a committer name and email in `git`'s standard author format."
 | |
|       flag   "--root-url=",
 | |
|              description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default."
 | |
|       flag   "--root-url-using=",
 | |
|              description: "Use the specified download strategy class for downloading the bottle's URL instead of " \
 | |
|                           "Homebrew's default."
 | |
| 
 | |
|       conflicts "--upload-only", "--keep-old"
 | |
|       conflicts "--upload-only", "--no-commit"
 | |
| 
 | |
|       named_args :none
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def check_bottled_formulae!(bottles_hash)
 | |
|     bottles_hash.each do |name, bottle_hash|
 | |
|       formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]
 | |
|       formula_version = Formulary.factory(formula_path).pkg_version
 | |
|       bottle_version = PkgVersion.parse bottle_hash["formula"]["pkg_version"]
 | |
|       next if formula_version == bottle_version
 | |
| 
 | |
|       odie "Bottles are for #{name} #{bottle_version} but formula is version #{formula_version}!"
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def github_releases?(bottles_hash)
 | |
|     @github_releases ||= 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
 | |
| 
 | |
|   def github_packages?(bottles_hash)
 | |
|     @github_packages ||= bottles_hash.values.all? do |bottle_hash|
 | |
|       bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def bottles_hash_from_json_files(json_files, args)
 | |
|     puts "Reading JSON files: #{json_files.join(", ")}" if args.verbose?
 | |
| 
 | |
|     bottles_hash = json_files.reduce({}) do |hash, json_file|
 | |
|       hash.deep_merge(JSON.parse(File.read(json_file)))
 | |
|     end
 | |
| 
 | |
|     if args.root_url
 | |
|       bottles_hash.each_value do |bottle_hash|
 | |
|         bottle_hash["bottle"]["root_url"] = args.root_url
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     bottles_hash
 | |
|   end
 | |
| 
 | |
|   def pr_upload
 | |
|     args = pr_upload_args.parse
 | |
| 
 | |
|     json_files = Dir["*.bottle.json"]
 | |
|     odie "No bottle JSON files found in the current working directory" if json_files.blank?
 | |
|     bottles_hash = bottles_hash_from_json_files(json_files, args)
 | |
| 
 | |
|     Homebrew.install_bundler_gems!(groups: ["pr_upload"])
 | |
| 
 | |
|     unless args.upload_only?
 | |
|       bottle_args = ["bottle", "--merge", "--write"]
 | |
|       bottle_args << "--verbose" if args.verbose?
 | |
|       bottle_args << "--debug" if args.debug?
 | |
|       bottle_args << "--keep-old" if args.keep_old?
 | |
|       bottle_args << "--root-url=#{args.root_url}" if args.root_url
 | |
|       bottle_args << "--committer=#{args.committer}" if args.committer
 | |
|       bottle_args << "--no-commit" if args.no_commit?
 | |
|       bottle_args << "--root-url-using=#{args.root_url_using}" if args.root_url_using
 | |
|       bottle_args += json_files
 | |
| 
 | |
|       if args.dry_run?
 | |
|         dry_run_service = if github_packages?(bottles_hash)
 | |
|           # GitHub Packages has its own --dry-run handling.
 | |
|           nil
 | |
|         elsif github_releases?(bottles_hash)
 | |
|           "GitHub Releases"
 | |
|         else
 | |
|           odie "Service specified by root_url is not recognized"
 | |
|         end
 | |
| 
 | |
|         if dry_run_service
 | |
|           puts <<~EOS
 | |
|             brew #{bottle_args.join " "}
 | |
|             Upload bottles described by these JSON files to #{dry_run_service}:
 | |
|               #{json_files.join("\n  ")}
 | |
|           EOS
 | |
|           return
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       check_bottled_formulae!(bottles_hash)
 | |
| 
 | |
|       safe_system HOMEBREW_BREW_FILE, *bottle_args
 | |
| 
 | |
|       json_files = Dir["*.bottle.json"]
 | |
|       if json_files.blank?
 | |
|         puts "No bottle JSON files after merge, no upload needed!"
 | |
|         return
 | |
|       end
 | |
| 
 | |
|       # Reload the JSON files (in case `brew bottle --merge` generated
 | |
|       # `all: $SHA256` bottles)
 | |
|       bottles_hash = bottles_hash_from_json_files(json_files, args)
 | |
| 
 | |
|       # Check the bottle commits did not break `brew audit`
 | |
|       unless args.no_commit?
 | |
|         audit_args = ["audit", "--skip-style"]
 | |
|         audit_args << "--verbose" if args.verbose?
 | |
|         audit_args << "--debug" if args.debug?
 | |
|         audit_args += bottles_hash.keys
 | |
|         safe_system HOMEBREW_BREW_FILE, *audit_args
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     if github_releases?(bottles_hash)
 | |
|       github_releases = GitHubReleases.new
 | |
|       github_releases.upload_bottles(bottles_hash)
 | |
|     elsif github_packages?(bottles_hash)
 | |
|       github_packages = GitHubPackages.new
 | |
|       github_packages.upload_bottles(bottles_hash,
 | |
|                                      keep_old:      args.keep_old?,
 | |
|                                      dry_run:       args.dry_run?,
 | |
|                                      warn_on_error: args.warn_on_upload_failure?)
 | |
|     else
 | |
|       odie "Service specified by root_url is not recognized"
 | |
|     end
 | |
|   end
 | |
| end
 | 
