Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# frozen_string_literal: true
require "cask"
require "cli/parser"
require "utils/tar"
module Homebrew
module_function
def bump_cask_pr_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`bump-cask-pr` [<options>] [<cask>]
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",
description: "Don't run `brew cask audit` before opening the PR."
switch "--no-style",
description: "Don't run `brew cask 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: "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"
named 1
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
new_version = args.version
new_base_url = args.url
new_hash = args.sha256
old_version = cask.version
old_hash = cask.sha256
tap_full_name = cask.tap&.full_name
origin_branch = Utils::Git.origin_branch(cask.tap.path) if cask.tap
origin_branch ||= "origin/master"
previous_branch = "-"
check_open_pull_requests(cask, tap_full_name, args: args)
odie "#{cask}: no --version= argument specified!" unless new_version
check_closed_pull_requests(cask, tap_full_name, version: new_version, args: args)
if Version.new(new_version) < Version.new(old_version)
odie <<~EOS
You need to bump this cask manually since changing the
version from #{old_version} to #{new_version} would be a downgrade.
EOS
elsif new_version == old_version
odie <<~EOS
You need to bump this cask manually since the new version
and old version are both #{new_version}.
EOS
end
old_contents = File.read(cask.sourcefile_path)
replacement_pairs = [
[
old_version,
new_version,
],
]
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_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_url = tmp_cask.url.to_s
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
cask.languages.each do |language|
next if language == cask.language
tmp_cask.config.languages = [language]
lang_cask = Cask::CaskLoader.load(tmp_contents)
lang_url = lang_cask.url.to_s
lang_old_hash = lang_cask.sha256
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
end
replacement_pairs << [
old_hash,
new_hash,
]
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)
pr_info = {
sourcefile_path: cask.sourcefile_path,
old_contents: old_contents,
origin_branch: origin_branch,
branch_name: "bump-#{cask.token}-#{new_version}",
commit_message: "Update #{cask.token} from #{old_version} to #{new_version}",
previous_branch: previous_branch,
tap: cask.tap,
tap_full_name: tap_full_name,
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
def check_open_pull_requests(cask, tap_full_name, args:)
GitHub.check_for_duplicate_pull_requests(cask.token, tap_full_name, state: "open", args: args)
end
def check_closed_pull_requests(cask, tap_full_name, version:, args:)
# if we haven't already found open requests, try for an exact match across closed requests
pr_title = "Update #{cask.token} from #{cask.version} to #{version}"
GitHub.check_for_duplicate_pull_requests(pr_title, tap_full_name, state: "closed", args: args)
end
def run_cask_audit(cask, old_contents, args:)
if args.dry_run?
if args.no_audit?
ohai "Skipping `brew cask audit`"
else
ohai "brew cask audit #{cask.sourcefile_path.basename}"
end
return
end
failed_audit = false
if args.no_audit?
ohai "Skipping `brew cask audit`"
else
system HOMEBREW_BREW_FILE, "cask", "audit", cask.sourcefile_path
failed_audit = !$CHILD_STATUS.success?
end
return unless failed_audit
cask.sourcefile_path.atomic_write(old_contents)
odie "`brew cask audit` failed!"
end
def run_cask_style(cask, old_contents, args:)
if args.dry_run?
if args.no_style?
ohai "Skipping `brew cask style --fix`"
else
ohai "brew cask style --fix #{cask.sourcefile_path.basename}"
end
return
end
failed_style = false
if args.no_style?
ohai "Skipping `brew cask style --fix`"
else
system HOMEBREW_BREW_FILE, "cask", "style", "--fix", cask.sourcefile_path
failed_style = !$CHILD_STATUS.success?
end
return unless failed_style
cask.sourcefile_path.atomic_write(old_contents)
odie "`brew cask style --fix` failed!"
end
end