-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
tap_auditor: add comprehensive validation for formula and cask renames #21011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
tap_auditor: add comprehensive validation for formula and cask renames #21011
Conversation
- Add check_renames method to validate rename entries - Detect .rb extensions in rename keys/values - Validate rename targets exist in tap - Detect and report chained renames - Warn about old names conflicting with existing formulae/casks - Add cask_renames to attr_reader - Add comprehensive test coverage for rename validation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds comprehensive validation for cask_renames.json and formula_renames.json files in Homebrew taps, replacing basic existence checking with detailed auditing.
- Implements a new
check_renamesmethod that validates rename entries for both casks and formulae - Detects common issues: .rb extensions, missing targets, chained renames, and naming conflicts
- Adds comprehensive test coverage for cask rename validation and partial coverage for formula renames
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| Library/Homebrew/tap_auditor.rb | Adds cask_renames attribute, implements check_renames method with four validation checks, and integrates validation into the audit process |
| Library/Homebrew/test/tap_auditor_spec.rb | Adds comprehensive test suite covering cask_renames validation scenarios and partial test coverage for formula_renames validation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add missing cask rename process documentation - Document validation rules for both formula and cask renames - Explain .rb extension, chained renames, and other common issues - Update title to reflect coverage of both formulae and casks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… end - Follow rename chains to their final target (e.g., A → B → C → D now correctly suggests A → D) - Add cycle detection to prevent infinite loops on circular renames - Add test case for multi-level chained renames - Simplify suggestion message since chains can be arbitrarily long Addresses PR feedback from Homebrew#21011
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
MikeMcQuaid
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@loganrosen Was an LLM used to generated any of the PR description and/or code here? If so, can you confirm you've manually reviewed, shortened and simplified it all as much as possible to the best of your ability and you understand it all? Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@MikeMcQuaid Yes, I did use an LLM to assist with the PR description and code changes, but I've manually reviewed all of the information/changes and understand them fully. Your nudge did lead me to some slight improvements in the error messages, though. 🙂 |
| ## Important Rules | ||
|
|
||
| When editing `formula_renames.json` or `cask_renames.json`, follow these rules: | ||
|
|
||
| 1. **Do not include `.rb` file extensions** - Use only the formula/cask token name | ||
| 2. **Ensure the target exists** - The new name must be an existing formula/cask in the tap | ||
| 3. **Avoid chained renames** - Don't create chains like `A → B` and `B → C`. Collapse chains to `A → C` directly as chained renames don't work automatically | ||
| 4. **Check for conflicts** - The old name should not conflict with an existing formula/cask | ||
|
|
||
| These rules are validated by `brew audit` for tap maintainers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's necessary to duplicate what the tooling does in the documentation. They will become out of sync.
| expect(auditor.problems.first[:message]).to include("'.rb' file extensions") | ||
| expect(auditor.problems.first[:message]).to include("oldcask.rb") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do a full match on the message instead of two includes and an empty check.
This also applies to all the test cases below too.
| cask_renames_path.write JSON.pretty_generate({ | ||
| "oldcask.rb" => "newcask", | ||
| }) | ||
|
|
||
| auditor.audit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use before and subject to DRY this up
| check_formula_list_directory "style_exceptions", @tap_style_exceptions | ||
| check_formula_list "pypi_formula_mappings", @tap_pypi_formula_mappings | ||
| check_formula_list "formula_renames", @formula_renames.values | ||
| check_renames "formula_renames", @formula_renames, @formula_names, @formula_aliases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels weird passing the same argument twice
| valid_aliases: T::Array[String]).void | ||
| } | ||
| def check_renames(list_file, renames_hash, valid_tokens, valid_aliases = []) | ||
| list_file += ".json" if File.extname(list_file).empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems strange; why wouldn't you just check the passed filename?
| problem <<~EOS | ||
| #{list_file} contains entries with '.rb' file extensions. | ||
| Rename entries should use formula/cask names only, without '.rb' extensions. | ||
| Invalid entries: #{invalid_format.map { |k, v| "\"#{k}\": \"#{v}\"" }.join(", ")} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use filter_map instead of select above and make it a single array that can be .join(", ") here instead.
| if chained.any? | ||
| suggestions = chained.map do |old_name, intermediate| | ||
| # Follow the chain to the end, with cycle detection | ||
| final = intermediate | ||
| seen = Set.new([old_name, intermediate]) | ||
| while renames_hash.key?(final) | ||
| next_name = renames_hash[final] | ||
| break if next_name.nil? || seen.include?(next_name) # Prevent infinite loops on circular renames | ||
|
|
||
| final = next_name | ||
| seen << final | ||
| end | ||
| " \"#{old_name}\": \"#{final}\" (instead of chained rename)" | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unnecessarily complex and doesn't need a while. Instead you can just see if old_names contains any new_names with a single array intersection operation.
| end | ||
|
|
||
| # Warn if old names conflict with existing casks/formulae | ||
| conflicts = renames_hash.keys.select { |old_name| valid_tokens.include?(old_name) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nicer for readability to just loop through renames_hash once and append to several arrays inside that single loop instead of looping for each check.
brew stylewith your changes locally?brew typecheckwith your changes locally?brew testswith your changes locally?Overview
This PR enhances
TapAuditorto provide comprehensive validation forformula_renames.jsonandcask_renames.jsonfiles in taps, and updates the rename documentation.Changes
New Validation Checks (
tap_auditor.rb)The new
check_renamesmethod validates rename entries and detects:.rbfile extensions in rename keys or values (should use tokens only)Implementation Details
cask_renamestoattr_reader(was missing)check_formula_listcall forformula_renames.jsonwithcheck_renamesmethodcheck_renamescall forcask_renames.jsonvalidationDocumentation Updates (
docs/Rename-A-Formula.md)Motivation
This was motivated by Homebrew/homebrew-cask#235881, which fixes an incorrect
cask_renames.jsonentry that erroneously included a.rbfile extension in the old cask name. This caused Homebrew to fail to properly migrate users frommultiviewer-for-f1tomultiviewer, breaking the rename functionality entirely.Currently, there's no validation to catch these errors before they're merged, meaning broken renames can silently break user upgrades. This PR adds auditing to prevent such issues:
.rbextensions that break rename matchingThese checks will catch issues during
brew auditbefore they're merged and affect users.Testing
All new functionality is covered by RSpec tests in
tap_auditor_spec.rb:Local validation: