brew/Library/Homebrew/dev-cmd/bump-cask-pr.rb

271 lines
8.9 KiB
Ruby
Raw Normal View History

2020-10-10 14:16:11 +02:00
# typed: false
2020-09-04 16:58:31 -07:00
# frozen_string_literal: true
require "cask"
require "cli/parser"
require "utils/tar"
module Homebrew
2020-10-20 12:03:48 +02:00
extend T::Sig
2020-09-04 16:58:31 -07:00
module_function
2020-10-20 12:03:48 +02:00
sig { returns(CLI::Parser) }
2020-09-04 16:58:31 -07:00
def bump_cask_pr_args
Homebrew::CLI::Parser.new do
description <<~EOS
2020-09-04 16:58:31 -07:00
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",
description: "Make the expected file modifications without taking any Git actions."
switch "--commit",
depends_on: "--write",
description: "When passed with `--write`, generate a new commit after writing changes "\
"to the cask file."
switch "--no-audit",
2020-11-18 08:10:21 +01:00
description: "Don't run `brew audit` before opening the PR."
switch "--online",
2020-11-18 08:10:21 +01:00
description: "Run `brew audit --online` before opening the PR."
2020-09-04 16:58:31 -07:00
switch "--no-style",
2020-11-18 08:10:21 +01:00
description: "Don't run `brew style --fix` before opening the PR."
2020-09-04 16:58:31 -07:00
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: "Append <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."
switch "-f", "--force",
description: "Ignore duplicate open PRs."
conflicts "--dry-run", "--write"
conflicts "--no-audit", "--online"
2021-01-10 14:26:40 -05:00
named_args :cask, number: 1
2020-09-04 16:58:31 -07:00
end
end
def bump_cask_pr
args = bump_cask_pr_args.parse
# As this command is simplifying user-run commands then let's just use a
# user path, too.
ENV["PATH"] = ENV["HOMEBREW_PATH"]
# Use the user's browser, too.
ENV["BROWSER"] = Homebrew::EnvConfig.browser
cask = args.named.to_casks.first
2021-01-08 11:42:37 -08:00
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?
2020-09-04 16:58:31 -07:00
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?
2020-09-04 16:58:31 -07:00
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=/--sha256= argument specified!"
end
2020-09-04 16:58:31 -07:00
old_version = cask.version
2020-12-04 00:07:02 +01:00
old_hash = cask.sha256
2020-09-04 16:58:31 -07:00
2021-01-08 11:42:37 -08:00
check_open_pull_requests(cask, args: args)
2020-09-04 16:58:31 -07:00
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}\""}",
]
end
2020-09-04 16:58:31 -07:00
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
if new_version.present?
if new_version.latest?
opoo "Ignoring specified `--sha256=` argument." if new_hash.present?
new_hash = :no_check
elsif new_hash.nil? || cask.languages.present?
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 = cask.config
tmp_url = tmp_cask.url.to_s
if old_hash != :no_check
if new_hash.nil?
resource_path = fetch_resource(cask, new_version, tmp_url)
Utils::Tar.validate_file(resource_path)
new_hash = resource_path.sha256
end
if tmp_contents.include?("Hardware::CPU.intel?")
other_contents = tmp_contents.gsub("Hardware::CPU.intel?", (!Hardware::CPU.intel?).to_s)
other_cask = Cask::CaskLoader.load(other_contents)
other_url = other_cask.url.to_s
other_old_hash = other_cask.sha256.to_s
resource_path = fetch_resource(cask, new_version, other_url)
Utils::Tar.validate_file(resource_path)
other_new_hash = resource_path.sha256
replacement_pairs << [
other_old_hash,
other_new_hash,
]
end
end
cask.languages.each do |language|
next if language == cask.language
lang_config = tmp_config.merge(Cask::Config.new(explicit: { languages: [language] }))
lang_cask = Cask::CaskLoader.load(tmp_contents)
lang_cask.config = lang_config
lang_url = lang_cask.url.to_s
lang_old_hash = lang_cask.sha256.to_s
resource_path = fetch_resource(cask, new_version, lang_url)
Utils::Tar.validate_file(resource_path)
lang_new_hash = resource_path.sha256
replacement_pairs << [
lang_old_hash,
lang_new_hash,
]
end
2020-09-04 16:58:31 -07:00
end
end
if new_hash.present?
2020-12-04 00:07:02 +01:00
hash_regex = old_hash == :no_check ? ":no_check" : "[\"']#{Regexp.escape(old_hash.to_s)}[\"']"
replacement_pairs << [
2020-12-04 00:07:02 +01:00
/sha256\s+#{hash_regex}/m,
"sha256 #{new_hash == :no_check ? ":no_check" : "\"#{new_hash}\""}",
]
end
2020-09-04 16:58:31 -07:00
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?
branch_name += "-#{new_version.tr(",:", "-")}"
commit_message += " from #{old_version} to #{new_version}"
end
2020-09-04 16:58:31 -07:00
pr_info = {
sourcefile_path: cask.sourcefile_path,
old_contents: old_contents,
branch_name: branch_name,
commit_message: commit_message,
2020-09-04 16:58:31 -07:00
tap: cask.tap,
pr_message: "Created with `brew bump-cask-pr`.",
}
GitHub.create_bump_pr(pr_info, args: args)
end
def fetch_resource(cask, new_version, url, **specs)
resource = Resource.new
resource.url(url, specs)
resource.owner = Resource.new(cask.token)
resource.version = new_version
resource.fetch
end
2021-01-08 11:42:37 -08:00
def check_open_pull_requests(cask, args:)
GitHub.check_for_duplicate_pull_requests(cask.token, cask.tap.full_name,
state: "open",
file: cask.sourcefile_path.relative_path_from(cask.tap.path).to_s,
args: args)
2020-09-04 16:58:31 -07:00
end
def run_cask_audit(cask, old_contents, args:)
if args.dry_run?
if args.no_audit?
2020-11-18 08:10:21 +01:00
ohai "Skipping `brew audit`"
elsif args.online?
2020-11-18 08:10:21 +01:00
ohai "brew audit --cask --online #{cask.sourcefile_path.basename}"
2020-09-04 16:58:31 -07:00
else
2020-11-18 08:10:21 +01:00
ohai "brew audit --cask #{cask.sourcefile_path.basename}"
2020-09-04 16:58:31 -07:00
end
return
end
failed_audit = false
if args.no_audit?
2020-11-18 08:10:21 +01:00
ohai "Skipping `brew audit`"
elsif args.online?
2020-11-18 08:10:21 +01:00
system HOMEBREW_BREW_FILE, "audit", "--cask", "--online", cask.sourcefile_path
failed_audit = !$CHILD_STATUS.success?
2020-09-04 16:58:31 -07:00
else
2020-11-18 08:10:21 +01:00
system HOMEBREW_BREW_FILE, "audit", "--cask", cask.sourcefile_path
2020-09-04 16:58:31 -07:00
failed_audit = !$CHILD_STATUS.success?
end
return unless failed_audit
cask.sourcefile_path.atomic_write(old_contents)
2020-11-18 08:10:21 +01:00
odie "`brew audit` failed!"
2020-09-04 16:58:31 -07:00
end
def run_cask_style(cask, old_contents, args:)
if args.dry_run?
if args.no_style?
2020-11-18 08:10:21 +01:00
ohai "Skipping `brew style --fix`"
2020-09-04 16:58:31 -07:00
else
2020-11-18 08:10:21 +01:00
ohai "brew style --fix #{cask.sourcefile_path.basename}"
2020-09-04 16:58:31 -07:00
end
return
end
failed_style = false
if args.no_style?
2020-11-18 08:10:21 +01:00
ohai "Skipping `brew style --fix`"
2020-09-04 16:58:31 -07:00
else
2020-11-18 08:10:21 +01:00
system HOMEBREW_BREW_FILE, "style", "--fix", cask.sourcefile_path
2020-09-04 16:58:31 -07:00
failed_style = !$CHILD_STATUS.success?
end
return unless failed_style
cask.sourcefile_path.atomic_write(old_contents)
2020-11-18 08:10:21 +01:00
odie "`brew style --fix` failed!"
2020-09-04 16:58:31 -07:00
end
end