Skip to content

Commit 0c6a8db

Browse files
committed
Replace brew which-update
- Keep `brew which-update` as the CI-facing incremental command for command-not-found database entries. - Remove the scheduled updater workflow and old bulk scan flags because core CI now updates touched formulae. - Reuse `executables_db.rb` for versionless database writes and bottle metadata updates. - Regenerate command docs, completions and Sorbet RBI for the new command interface.
1 parent 6f293da commit 0c6a8db

11 files changed

Lines changed: 315 additions & 259 deletions

File tree

.github/workflows/command-not-found-db-update.yml

Lines changed: 0 additions & 94 deletions
This file was deleted.

Library/Homebrew/dev-cmd/which-update.rb

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
require "abstract_command"
88
require "executables_db"
9+
require "utils/github"
910

1011
module Homebrew
1112
module DevCmd
@@ -19,20 +20,24 @@ class WhichUpdate < AbstractCommand
1920
"list of missing formulae)."
2021
switch "--commit",
2122
description: "Commit the changes using `git`."
22-
switch "--update-existing",
23-
description: "Update database entries with outdated formula versions."
24-
switch "--install-missing",
25-
description: "Install and update formulae that are missing from the database and don't have bottles."
26-
switch "--eval-all",
27-
description: "Evaluate all installed taps, rather than just the core tap."
28-
flag "--max-downloads=",
29-
description: "Specify a maximum number of formulae to download and update."
23+
flag "--bottle-json-dir=",
24+
description: "Use generated bottle JSON files in the given directory to update formula entries."
25+
flag "--formulae-file=",
26+
description: "Update database entries for formulae listed in the given file."
27+
flag "--removed-formulae-file=",
28+
description: "Remove database entries for formulae listed in the given file."
29+
flag "--pull-request=",
30+
description: "Update entries for formula changes in the given pull request number."
31+
flag "--repository=",
32+
depends_on: "--pull-request",
33+
description: "GitHub repository for `--pull-request` (default: `$GITHUB_REPOSITORY`)."
3034
flag "--summary-file=",
3135
description: "Output a summary of the changes to a file."
3236
conflicts "--stats", "--commit"
33-
conflicts "--stats", "--install-missing"
34-
conflicts "--stats", "--update-existing"
35-
conflicts "--stats", "--max-downloads"
37+
conflicts "--stats", "--bottle-json-dir"
38+
conflicts "--stats", "--formulae-file"
39+
conflicts "--stats", "--removed-formulae-file"
40+
conflicts "--stats", "--pull-request"
3641
named_args :database, number: 1
3742
end
3843

@@ -41,13 +46,18 @@ def run
4146
if args.stats?
4247
stats source: args.named.fetch(0)
4348
else
44-
update_and_save! source: args.named.fetch(0),
45-
commit: args.commit?,
46-
update_existing: args.update_existing?,
47-
install_missing: args.install_missing?,
48-
max_downloads: args.max_downloads&.to_i,
49-
eval_all: args.eval_all?,
50-
summary_file: args.summary_file
49+
updated = update_and_save! source: args.named.fetch(0),
50+
commit: args.commit?,
51+
bottle_json_dir: args.bottle_json_dir,
52+
formulae_file: args.formulae_file,
53+
removed_formulae_file: args.removed_formulae_file,
54+
pull_request: args.pull_request,
55+
repository: args.repository,
56+
summary_file: args.summary_file
57+
58+
if (github_output = ENV["GITHUB_OUTPUT"].presence)
59+
File.open(github_output, "a") { |file| file.puts "updated=#{updated}" }
60+
end
5161
end
5262
end
5363

@@ -77,20 +87,54 @@ def stats(source:)
7787

7888
sig {
7989
params(
80-
source: String,
81-
commit: T::Boolean,
82-
update_existing: T::Boolean,
83-
install_missing: T::Boolean,
84-
max_downloads: T.nilable(Integer),
85-
eval_all: T::Boolean,
86-
summary_file: T.nilable(String),
87-
).void
90+
source: String,
91+
commit: T::Boolean,
92+
bottle_json_dir: T.nilable(String),
93+
formulae_file: T.nilable(String),
94+
removed_formulae_file: T.nilable(String),
95+
pull_request: T.nilable(String),
96+
repository: T.nilable(String),
97+
summary_file: T.nilable(String),
98+
).returns(T::Boolean)
8899
}
89-
def update_and_save!(source:, commit: false, update_existing: false, install_missing: false,
90-
max_downloads: nil, eval_all: false, summary_file: nil)
100+
def update_and_save!(source:, commit: false, bottle_json_dir: nil, formulae_file: nil,
101+
removed_formulae_file: nil, pull_request: nil, repository: nil, summary_file: nil)
102+
source_path = Pathname(source)
103+
original_database = source_path.exist? ? source_path.read : nil
91104
db = ExecutablesDB.new source
92-
db.update!(update_existing:, install_missing:,
93-
max_downloads:, eval_all:)
105+
106+
formulae = file_lines(formulae_file)
107+
removed_formulae = file_lines(removed_formulae_file)
108+
109+
if pull_request
110+
repository = repository.presence || ENV["GITHUB_REPOSITORY"].presence
111+
if repository.blank?
112+
raise UsageError,
113+
"`--repository` or `$GITHUB_REPOSITORY` is required with `--pull-request`."
114+
end
115+
116+
owner, repo = repository.split("/", 2)
117+
raise UsageError, "`--repository` must be in the form `owner/repo`." if owner.blank? || repo.blank?
118+
119+
GitHub::API.paginate_rest(GitHub.url_to("repos", owner, repo, "pulls", pull_request, "files")) do |files|
120+
T.cast(files, T::Array[T::Hash[String, T.untyped]]).each do |file|
121+
filename = file["filename"].to_s
122+
next if !filename.start_with?("Formula/") || !filename.end_with?(".rb")
123+
124+
case file["status"].to_s
125+
when "removed"
126+
removed_formulae << File.basename(filename, ".rb")
127+
when "renamed"
128+
removed_formulae << File.basename(file["previous_filename"].to_s, ".rb")
129+
formulae << File.basename(filename, ".rb")
130+
else
131+
formulae << File.basename(filename, ".rb")
132+
end
133+
end
134+
end
135+
end
136+
137+
db.update!(bottle_json_dir:, formulae:, removed_formulae:)
94138
db.save!
95139

96140
if summary_file
@@ -100,10 +144,11 @@ def update_and_save!(source:, commit: false, update_existing: false, install_mis
100144
end
101145
end
102146

103-
return if !commit || !db.changed?
147+
return original_database != source_path.read if !commit || !db.changed?
104148

105149
msg = git_commit_message(db.changes)
106150
safe_system "git", "-C", db.root.to_s, "commit", "-m", msg, source
151+
original_database != source_path.read
107152
end
108153

109154
sig { params(els: T::Array[String], verb: String).returns(String) }
@@ -121,7 +166,6 @@ def git_commit_message(changes)
121166
names = changes.send(action)
122167
next if names.empty?
123168

124-
action = "bump version for" if action == :version_bump
125169
msg << english_list(names.to_a.sort, action.to_s)
126170
break
127171
end
@@ -152,6 +196,17 @@ def summary_file_message(changes)
152196
#{msg.join("\n")}
153197
MESSAGE
154198
end
199+
200+
private
201+
202+
sig { params(path: T.nilable(String)).returns(T::Array[String]) }
203+
def file_lines(path)
204+
return [] if path.blank? || !File.file?(path)
205+
206+
File.readlines(path, chomp: true).filter_map do |line|
207+
line.strip.presence
208+
end
209+
end
155210
end
156211
end
157212
end

0 commit comments

Comments
 (0)