Port Homebrew::DevCmd::PrUpload
This commit is contained in:
parent
dc062bea52
commit
6d362ccb3b
@ -1,6 +1,7 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "cli/parser"
|
||||
require "formula"
|
||||
require "github_packages"
|
||||
@ -8,159 +9,159 @@ require "github_releases"
|
||||
require "extend/hash/deep_merge"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
module DevCmd
|
||||
class PrUpload < AbstractCommand
|
||||
cmd_args 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."
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
named_args :none
|
||||
end
|
||||
end
|
||||
|
||||
bottles_hash
|
||||
end
|
||||
sig { override.void }
|
||||
def run
|
||||
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)
|
||||
|
||||
def pr_upload
|
||||
args = pr_upload_args.parse
|
||||
Homebrew.install_bundler_gems!(groups: ["pr_upload"])
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
Homebrew.install_bundler_gems!(groups: ["pr_upload"])
|
||||
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
|
||||
|
||||
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 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
|
||||
|
||||
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"
|
||||
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
|
||||
|
||||
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
|
||||
private
|
||||
|
||||
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
|
||||
|
||||
check_bottled_formulae!(bottles_hash)
|
||||
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
|
||||
|
||||
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
|
||||
tag
|
||||
end
|
||||
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
|
||||
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
|
||||
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"
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cmd/shared_examples/args_parse"
|
||||
require "dev-cmd/pr-upload"
|
||||
|
||||
RSpec.describe "brew pr-upload" do
|
||||
RSpec.describe Homebrew::DevCmd::PrUpload do
|
||||
it_behaves_like "parseable arguments"
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user