
Currently we only check for closed PRs in `bump-cask-pr`. This adds that check to `bump` and `bump-formula-pr`. The idea is that this check can warn users about already updated packages or those that can't be updated easily and should be updated manually instead.
256 lines
9.1 KiB
Ruby
256 lines
9.1 KiB
Ruby
# typed: false
|
|
# frozen_string_literal: true
|
|
|
|
require "cask"
|
|
require "cask/download"
|
|
require "cli/parser"
|
|
require "utils/tar"
|
|
|
|
module Homebrew
|
|
extend T::Sig
|
|
|
|
module_function
|
|
|
|
sig { returns(CLI::Parser) }
|
|
def bump_cask_pr_args
|
|
Homebrew::CLI::Parser.new do
|
|
description <<~EOS
|
|
Create a pull request to update <cask> with a new version.
|
|
|
|
A best effort to determine the <SHA-256> will be made if the value is not
|
|
supplied by the user.
|
|
EOS
|
|
switch "-n", "--dry-run",
|
|
description: "Print what would be done rather than doing it."
|
|
switch "--write-only",
|
|
description: "Make the expected file modifications without taking any Git actions."
|
|
switch "--commit",
|
|
depends_on: "--write-only",
|
|
description: "When passed with `--write-only`, generate a new commit after writing changes " \
|
|
"to the cask file."
|
|
switch "--no-audit",
|
|
description: "Don't run `brew audit` before opening the PR."
|
|
switch "--online",
|
|
description: "Run `brew audit --online` before opening the PR."
|
|
switch "--no-style",
|
|
description: "Don't run `brew style --fix` before opening the PR."
|
|
switch "--no-browse",
|
|
description: "Print the pull request URL instead of opening in a browser."
|
|
switch "--no-fork",
|
|
description: "Don't try to fork the repository."
|
|
flag "--version=",
|
|
description: "Specify the new <version> for the cask."
|
|
flag "--message=",
|
|
description: "Prepend <message> to the default pull request message."
|
|
flag "--url=",
|
|
description: "Specify the <URL> for the new download."
|
|
flag "--sha256=",
|
|
description: "Specify the <SHA-256> checksum of the new download."
|
|
flag "--fork-org=",
|
|
description: "Use the specified GitHub organization for forking."
|
|
switch "-f", "--force",
|
|
description: "Ignore duplicate open PRs."
|
|
|
|
conflicts "--dry-run", "--write"
|
|
conflicts "--no-audit", "--online"
|
|
|
|
named_args :cask, number: 1
|
|
end
|
|
end
|
|
|
|
def bump_cask_pr
|
|
args = bump_cask_pr_args.parse
|
|
|
|
# This will be run by `brew style` later so run it first to not start
|
|
# spamming during normal output.
|
|
Homebrew.install_bundler_gems!
|
|
|
|
# As this command is simplifying user-run commands then let's just use a
|
|
# user path, too.
|
|
ENV["PATH"] = PATH.new(ORIGINAL_PATHS).to_s
|
|
|
|
# Use the user's browser, too.
|
|
ENV["BROWSER"] = Homebrew::EnvConfig.browser
|
|
|
|
cask = args.named.to_casks.first
|
|
|
|
odie "This cask is not in a tap!" if cask.tap.blank?
|
|
odie "This cask's tap is not a Git repository!" unless cask.tap.git?
|
|
|
|
new_version = args.version
|
|
new_version = :latest if ["latest", ":latest"].include? new_version
|
|
new_version = Cask::DSL::Version.new(new_version) if new_version.present?
|
|
new_base_url = args.url
|
|
new_hash = args.sha256
|
|
new_hash = :no_check if ["no_check", ":no_check"].include? new_hash
|
|
|
|
if new_version.nil? && new_base_url.nil? && new_hash.nil?
|
|
raise UsageError, "No `--version=`, `--url=` or `--sha256=` argument specified!"
|
|
end
|
|
|
|
old_version = cask.version
|
|
old_hash = cask.sha256
|
|
|
|
check_pull_requests(cask, state: "open", args: args)
|
|
# if we haven't already found open requests, try for an exact match across closed requests
|
|
check_pull_requests(cask, state: "closed", args: args, version: new_version) if new_version.present?
|
|
|
|
old_contents = File.read(cask.sourcefile_path)
|
|
|
|
replacement_pairs = []
|
|
|
|
if new_version.present?
|
|
old_version_regex = old_version.latest? ? ":latest" : "[\"']#{Regexp.escape(old_version.to_s)}[\"']"
|
|
|
|
replacement_pairs << [
|
|
/version\s+#{old_version_regex}/m,
|
|
"version #{new_version.latest? ? ":latest" : "\"#{new_version}\""}",
|
|
]
|
|
if new_version.latest? || new_hash == :no_check
|
|
opoo "Ignoring specified `--sha256=` argument." if new_hash.is_a? String
|
|
replacement_pairs << [/"#{old_hash}"/, ":no_check"] if old_hash != :no_check
|
|
elsif old_hash != :no_check
|
|
if new_hash.nil? || cask.languages.present?
|
|
if new_hash.present? && cask.languages.present?
|
|
opoo "Multiple hash replacements required; ignoring specified `--sha256=` argument."
|
|
end
|
|
tmp_contents = Utils::Inreplace.inreplace_pairs(cask.sourcefile_path,
|
|
replacement_pairs.uniq.compact,
|
|
read_only_run: true,
|
|
silent: true)
|
|
|
|
tmp_cask = Cask::CaskLoader.load(tmp_contents)
|
|
tmp_config = tmp_cask.config
|
|
|
|
[:arm, :intel].each do |arch|
|
|
Homebrew::SimulateSystem.arch = arch
|
|
|
|
languages = cask.languages
|
|
languages = [nil] if languages.empty?
|
|
languages.each do |language|
|
|
new_hash_config = if language.blank?
|
|
tmp_config
|
|
else
|
|
tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
|
|
end
|
|
|
|
new_hash_cask = Cask::CaskLoader.load(tmp_contents)
|
|
new_hash_cask.config = new_hash_config
|
|
old_hash = new_hash_cask.sha256.to_s
|
|
|
|
cask_download = Cask::Download.new(new_hash_cask, quarantine: true)
|
|
download = cask_download.fetch(verify_download_integrity: false)
|
|
Utils::Tar.validate_file(download)
|
|
|
|
replacement_pairs << [new_hash_cask.sha256.to_s, download.sha256]
|
|
end
|
|
|
|
Homebrew::SimulateSystem.clear
|
|
end
|
|
elsif new_hash.present?
|
|
opoo "Cask contains multiple hashes; only updating hash for current arch." if cask.on_system_blocks_exist?
|
|
replacement_pairs << [old_hash.to_s, new_hash]
|
|
end
|
|
end
|
|
end
|
|
|
|
if new_base_url.present?
|
|
m = /^ +url "(.+?)"\n/m.match(old_contents)
|
|
odie "Could not find old URL in cask!" if m.nil?
|
|
|
|
old_base_url = m.captures.first
|
|
|
|
replacement_pairs << [
|
|
/#{Regexp.escape(old_base_url)}/,
|
|
new_base_url,
|
|
]
|
|
end
|
|
|
|
Utils::Inreplace.inreplace_pairs(cask.sourcefile_path,
|
|
replacement_pairs.uniq.compact,
|
|
read_only_run: args.dry_run?,
|
|
silent: args.quiet?)
|
|
|
|
run_cask_audit(cask, old_contents, args: args)
|
|
run_cask_style(cask, old_contents, args: args)
|
|
|
|
branch_name = "bump-#{cask.token}"
|
|
commit_message = "Update #{cask.token}"
|
|
if new_version.present?
|
|
if new_version.before_comma != old_version.before_comma
|
|
new_version = new_version.before_comma
|
|
old_version = old_version.before_comma
|
|
end
|
|
branch_name += "-#{new_version.tr(",:", "-")}"
|
|
commit_message += " from #{old_version} to #{new_version}"
|
|
end
|
|
pr_info = {
|
|
sourcefile_path: cask.sourcefile_path,
|
|
old_contents: old_contents,
|
|
branch_name: branch_name,
|
|
commit_message: commit_message,
|
|
tap: cask.tap,
|
|
pr_message: "Created with `brew bump-cask-pr`.",
|
|
}
|
|
GitHub.create_bump_pr(pr_info, args: args)
|
|
end
|
|
|
|
def check_pull_requests(cask, state:, args:, version: nil)
|
|
tap_remote_repo = cask.tap.remote_repo || cask.tap.full_name
|
|
GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo,
|
|
state: state,
|
|
version: version,
|
|
file: cask.sourcefile_path.relative_path_from(cask.tap.path).to_s,
|
|
args: args)
|
|
end
|
|
|
|
def run_cask_audit(cask, old_contents, args:)
|
|
if args.dry_run?
|
|
if args.no_audit?
|
|
ohai "Skipping `brew audit`"
|
|
elsif args.online?
|
|
ohai "brew audit --cask --online #{cask.sourcefile_path.basename}"
|
|
else
|
|
ohai "brew audit --cask #{cask.sourcefile_path.basename}"
|
|
end
|
|
return
|
|
end
|
|
failed_audit = false
|
|
if args.no_audit?
|
|
ohai "Skipping `brew audit`"
|
|
elsif args.online?
|
|
system HOMEBREW_BREW_FILE, "audit", "--cask", "--online", cask.full_name
|
|
failed_audit = !$CHILD_STATUS.success?
|
|
else
|
|
system HOMEBREW_BREW_FILE, "audit", "--cask", cask.full_name
|
|
failed_audit = !$CHILD_STATUS.success?
|
|
end
|
|
return unless failed_audit
|
|
|
|
cask.sourcefile_path.atomic_write(old_contents)
|
|
odie "`brew audit` failed!"
|
|
end
|
|
|
|
def run_cask_style(cask, old_contents, args:)
|
|
if args.dry_run?
|
|
if args.no_style?
|
|
ohai "Skipping `brew style --fix`"
|
|
else
|
|
ohai "brew style --fix #{cask.sourcefile_path.basename}"
|
|
end
|
|
return
|
|
end
|
|
failed_style = false
|
|
if args.no_style?
|
|
ohai "Skipping `brew style --fix`"
|
|
else
|
|
system HOMEBREW_BREW_FILE, "style", "--fix", cask.sourcefile_path
|
|
failed_style = !$CHILD_STATUS.success?
|
|
end
|
|
return unless failed_style
|
|
|
|
cask.sourcefile_path.atomic_write(old_contents)
|
|
odie "`brew style --fix` failed!"
|
|
end
|
|
end
|