Skip to content

fix(lockfile): handle yarn berry builtin compat flags & ~/ patch paths#963

Merged
jdx merged 6 commits into
jdx:mainfrom
GabDug:fix/yarn-berry-optional-builtin-patch
Jul 1, 2026
Merged

fix(lockfile): handle yarn berry builtin compat flags & ~/ patch paths#963
jdx merged 6 commits into
jdx:mainfrom
GabDug:fix/yarn-berry-optional-builtin-patch

Conversation

@GabDug

@GabDug GabDug commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Hey there, hope you're doing fine!

Follow-up of the work in #728. I was trying aube on a Yarn v4 project and got a few import/install failures around Yarn patch handling.

It seems like aube's Yarn Berry patch: parser matched only a slice of Yarn's grammar. This rewrites patch_protocol_path
to mirror Yarn patchUtils.ts across Yarn 2.4–4.x.

The PR was written by Claude: I'm not too much of a Rust person, so I hope this is a good starting point, but I'll be a poor judge of whether the code is good. Fine to close it and move it to a Discussion :)

bug

aube install fails at the patch step on Yarn v4 projects I tried, including Yarn itself and backstage(.io). The patch: selector parser only handled part of Yarn's grammar, so two forms break:

  • optional!builtin<compat/fsevents>: Yarn's compat shim that can't be disabled. It's in almost every Yarn 4 lockfile (via fsevents). due to the optional!, aube treats it as a real patch path and tries to read a file that doesn't exist.
  • ~/.yarn/patches/foo.patch: the path yarn patch-commit -s writes by default. aube keeps the ~/, so it looks for a literal ~ dir.

Either one gives × failed to read patch file .../optional!builtin<compat/fsevents>...

fix

Parse the selector the way Yarn does: split on &, drop the flags, skip builtin<...>, strip a leading ~/. Builtin compat patches get skipped, since aube can't apply Yarn's bundled shims, but the package still installs from its normal npm entry. It's one function, no other call sites.

The flag handling also covers the older compat-shim spellings (builtin<...> and ~builtin<...> from Yarn 2.x) alongside today's optional!builtin<...>

The fix does not add support for multiple patch files, which currently can't be emitted with yarn patch.

test

In addition to the tests, I ran aube import/aube install before/after on backstage and yarnpkg/berry, plus a parse diff across about a dozen Yarn 4 repos. No obvious regressions in my runs.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of Yarn Berry patch: selectors, including robust parsing of composed selectors and selector :: parameters.
    • Builtin compat patch selectors are now skipped consistently while preserving real project patch paths.
    • Project-root (~/) patch paths are normalized correctly, and selectors that resolve to multiple real patch files are rejected.
  • Tests

    • Expanded unit and property-based coverage for compat skipping, selector composition/order, malformed selectors, and ~/ normalization.
    • Added a new fixture and end-to-end aube install test for #~/.yarn/patches/... references.

GabDug and others added 2 commits June 27, 2026 16:43
aube's berry `patch:` parser mishandled three patch-path selector forms,
all stemming from an incomplete reading of Yarn's grammar
(plugin-patch/sources/patchUtils.ts). Mirror Yarn faithfully: split the
selector on `&`, strip flags, then classify each segment.

- optional!builtin<…>: Yarn ≥3.2's plugin-compat emits its builtin compat
  shims (fsevents, resolve, typescript) with an `optional!` flag — the
  canonical form that pervades real lockfiles. aube only matched the bare
  `builtin<…>` prefix, so the flagged form slipped through and was
  recorded as a real project patch pointing at a nonexistent file. Strip
  `!`-delimited flags up to the last `!`, then match `^builtin<…>$`.

- ~builtin<…>: Yarn 2.4–3.1 spelled the optional flag as a leading `~`
  (plugin-compat #2543), so older lockfiles carry `~builtin<…>`. Strip a
  bare leading `~` so these legacy compat patches are skipped too.

- ~/.yarn/patches/…: Yarn's `patch-commit -s` default writes
  project-root-relative paths with a `~/` prefix. aube kept it verbatim,
  so the materializer looked for a literal `~` directory and the install
  failed. Strip `~/` to aube's canonical project-root-relative form (the
  two `~` meanings never collide: a project path keeps its slash, the
  legacy flag does not).

Builtin segments are ignored (the package survives via its plain npm
block); a composed `real.patch&optional!builtin<…>` keeps the real file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Property test the yarn berry patch-selector parser: for any &-joined
selector of Yarn-shaped segments, patch_protocol_path returns either None
or a clean project-relative path — never a leftover `~` prefix and never a
`builtin<…>` marker (the exact forms that broke installs). Plus a no-panic
property over arbitrary input. Helper is made pub(super) to test directly,
matching the existing parse_berry_spec / split_berry_header convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2601f68d-cfe5-44fc-ac14-ad476fbb06af

📥 Commits

Reviewing files that changed from the base of the PR and between b9c35b5 and 7d0bf67.

📒 Files selected for processing (2)
  • crates/aube-lockfile/src/yarn/berry.rs
  • crates/aube-lockfile/src/yarn/tests.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/aube-lockfile/src/yarn/tests.rs
  • crates/aube-lockfile/src/yarn/berry.rs

📝 Walkthrough

Walkthrough

patch_protocol_path now classifies Yarn Berry patch selectors as single, skipped, or multiple paths. Tests and a new import fixture cover builtin compat selectors, tilde-prefixed patch paths, and aube install handling.

Yarn Berry patch protocol selector parsing

Layer / File(s) Summary
Selector classification
crates/aube-lockfile/src/yarn/berry.rs
parse_berry_str, patch_protocol_path, and patch_spec_path use PatchSelector to separate single patch paths, skipped builtin-only selectors, and multi-path selectors.
Selector test coverage
crates/aube-lockfile/src/yarn/tests.rs
Adds unit tests and property tests for builtin compat skipping, composed selectors, multi-path rejection, tilde normalization, and parser robustness.
Tilde-path import fixture
fixtures/import-yarn-patch-tilde/package.json, test/import.bats
Adds an import fixture and Bats case for a #~/.yarn/patches/... selector and checks aube install completes with the patched dependency.

Changes

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through # and & with glee,
Found one patch path or none to see.
Tilde trails tucked safely right,
And import tests now bound it tight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the Yarn Berry patch-selector fixes for builtin compat flags and ~/ patch paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR improves Yarn Berry patch handling in the lockfile parser. The main changes are:

  • Skips Yarn builtin compat patch selectors instead of treating them as files.
  • Normalizes ~/ patch paths to project-relative paths.
  • Rejects selectors with more than one real patch file.
  • Adds parser coverage and an install fixture for the new patch forms.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
crates/aube-lockfile/src/yarn/berry.rs Updates Yarn Berry patch selector parsing to classify single real patches, builtin-only selectors, and multi-patch selectors.
crates/aube-lockfile/src/yarn/tests.rs Adds unit and property tests for builtin selectors, composed selectors, multi-patch rejection, and ~/ path normalization.
test/import.bats Adds an install test for a Yarn Berry patch path that starts with ~/.
fixtures/import-yarn-patch-tilde/package.json Adds a fixture package that uses a tilde-prefixed Yarn Berry patch dependency.
fixtures/import-yarn-patch-tilde/yarn.lock Adds the matching Yarn Berry lockfile for the tilde patch fixture.
fixtures/import-yarn-patch-tilde/.yarn/patches/is-number.patch Adds the patch file used by the tilde patch install fixture.

Reviews (4): Last reviewed commit: "test(lockfile): add yarn patch-selector ..." | Re-trigger Greptile

Comment thread crates/aube-lockfile/src/yarn/berry.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aube-lockfile/src/yarn/berry.rs`:
- Around line 458-485: The patch selector parser in patch_protocol_path is
currently truncating multi-file selectors by returning only the first real patch
path, which can silently ignore additional diffs. Update the logic to detect
when selector.split('&') contains more than one non-builtin<…> path and return
an error or otherwise fail loudly instead of picking the first entry. Keep the
existing builtin<…> filtering and prefix stripping, but make the function/its
callers reject unsupported multi-patch selectors until the patch graph can
represent them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c2509ef-5e28-4c19-9fb8-c24e3f908a67

📥 Commits

Reviewing files that changed from the base of the PR and between 834b315 and adb8340.

⛔ Files ignored due to path filters (2)
  • fixtures/import-yarn-patch-tilde/.yarn/patches/is-number.patch is excluded by !**/.yarn/**
  • fixtures/import-yarn-patch-tilde/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • crates/aube-lockfile/src/yarn/berry.rs
  • crates/aube-lockfile/src/yarn/tests.rs
  • fixtures/import-yarn-patch-tilde/package.json
  • test/import.bats

Comment thread crates/aube-lockfile/src/yarn/berry.rs Outdated
…iles

patch_protocol_path kept only the first real patch in a `&`-joined selector
and silently ignored the rest. Yarn's grammar allows multiple real patches
(its CLI never emits this), so warn (WARN_AUBE_YARN_BERRY_UNSUPPORTED) instead
of dropping them silently. Still applies the first; one path per package is
aube's model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread crates/aube-lockfile/src/yarn/berry.rs Outdated
Comment thread crates/aube-lockfile/src/yarn/berry.rs Outdated
…omments

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@GabDug GabDug marked this pull request as ready for review June 28, 2026 09:04
@jdx jdx merged commit 5901f17 into jdx:main Jul 1, 2026
17 checks passed
@greptile-apps greptile-apps Bot mentioned this pull request Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants