chore: Update yarn to 4.13, add package age gate, fix pnpm linker path detection#198
chore: Update yarn to 4.13, add package age gate, fix pnpm linker path detection#198dividedmind wants to merge 3 commits intomainfrom
Conversation
Yarn 4 pnpm linker changed the .store subdirectory naming from the package name (e.g. .store/mocha-npm-10.8.2-hash/mocha/) to a generic 'package/' directory (.store/mocha-npm-10.8.2-hash/package/). This broke all endsWith() path checks in the mocha, jest, and vitest hooks, which relied on resolved paths ending with /mocha/lib/runner.js etc. Add matchesPackageFile() utility to transform.ts that handles both the classic node_modules layout and the yarn 4 pnpm linker store layout, and update all three hooks to use it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-project Yarn 4 changed the pnpm linker's .store subdirectory name to 'package/' (was the package name in yarn 3), breaking path-based hook detection. Switch the main project to nodeLinker: node-modules to avoid the issue, and add test/pnpm-compat/ as a minimal independent yarn sub-project with nodeLinker: pnpm to specifically test the pnpm linker path format support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0160577 to
1f17220
Compare
commit: |
There was a problem hiding this comment.
Pull request overview
This PR updates the repo’s Yarn tooling to v4.13.0, adds a supply-chain “package age gate”, and fixes test-framework hook detection under Yarn 4’s pnpm linker layout by introducing a shared path-matching helper and exercising it via a new pnpm-compat integration test.
Changes:
- Bump Yarn to 4.13.0, switch root
nodeLinkertonode-modules, and enablenpmMinimalAgeGate. - Add
matchesPackageFile()and update Vitest/Jest/Mocha hooks to support Yarn 4 pnpm linker.store/.../package/...paths. - Add a standalone
test/pnpm-compat/project + integration test and CI cache entries to validate pnpm-linker compatibility.
Reviewed changes
Copilot reviewed 22 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
.yarnrc.yml |
Updates Yarn settings (compression, node linker, minimal age gate, yarnPath). |
package.json |
Updates packageManager to Yarn 4.13.0. |
.github/workflows/ci.yml |
Adds caching for test/pnpm-compat Yarn cache/global folders. |
src/util/matchesPackageFile.ts |
New helper to match hook target files across node_modules layouts. |
src/transform.ts |
Re-exports matchesPackageFile (and keeps hook dispatch unchanged). |
src/hooks/vitest.ts |
Switches Vitest hook target detection to matchesPackageFile(). |
src/hooks/jest.ts |
Switches Jest hook target detection to matchesPackageFile(). |
src/hooks/mocha.ts |
Switches Mocha hook target detection to matchesPackageFile(). |
test/pnpm-compat.test.ts |
New integration test running Vitest under Yarn pnpm linker. |
test/pnpm-compat/appmap.yml |
New AppMap config for pnpm-compat fixture project. |
test/pnpm-compat/package.json |
New fixture package manifest (Vitest dependency). |
test/pnpm-compat/vitest.config.mjs |
Minimal Vitest config for pnpm-compat fixture. |
test/pnpm-compat/sum.test.js |
Minimal Vitest test used by pnpm-compat fixture. |
test/pnpm-compat/.yarnrc.yml |
Yarn config for pnpm-compat fixture (pnpm linker + local cache folders). |
test/pnpm-compat/.gitignore |
Ignores .yarn/ within pnpm-compat fixture. |
test/pnpm-compat/yarn.lock |
Lockfile for pnpm-compat fixture project. |
test/vitest1/appmap.yml |
Excludes node_modules from the vitest package path. |
test/vitest2/appmap.yml |
Excludes node_modules from the vitest package path. |
test/vitest3/appmap.yml |
Excludes node_modules from the vitest package path. |
test/vitest4/appmap.yml |
Excludes node_modules from the vitest package path. |
test/next.test.ts |
Uses require.resolve to locate Next’s bin in the fixture project. |
test/next16.test.ts |
Uses require.resolve to locate Next’s bin in the fixture project. |
test/__snapshots__/next16.test.ts.snap |
Updates snapshot to match new Next.js output/header values. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| integrationTest("pnpm linker: vitest hooks instrument code in .store paths", () => { | ||
| const dir = resolve(__dirname, "pnpm-compat"); | ||
| if (!existsSync(resolve(dir, "node_modules"))) | ||
| spawnSync("yarn", ["install"], { | ||
| cwd: dir, | ||
| stdio: "inherit", | ||
| shell: process.platform === "win32", | ||
| }); |
There was a problem hiding this comment.
The test only runs yarn install when node_modules/ doesn't exist. That can lead to stale dependencies locally (e.g., if test/pnpm-compat/yarn.lock changes but node_modules/ is already present), making the test non-deterministic. Consider always running yarn install --immutable (or another lockfile-enforcing check) in this test setup; CI performance can still be preserved via the workflow cache for test/pnpm-compat/.yarn/*.
| // @scope/pkg → @scope-pkg-npm-ver-hash or @scope-pkg-virtual-hash | ||
| // pkg → pkg-npm-ver-hash or pkg-virtual-hash | ||
| const sanitized = packageName.replace("/", "-"); | ||
| if (urlOrPath.includes(`/.store/${sanitized}-`)) return true; |
There was a problem hiding this comment.
matchesPackageFile() can return false positives for Yarn 4 pnpm store paths because it checks includes('/.store/${sanitized}-'). For example, packageName vite would also match a store entry like vite-node-... since it contains /.store/vite-. This could cause hooks to instrument/patch the wrong package file if the filePath suffix matches. Consider matching the store entry more strictly (e.g., require /.store/${sanitized}-(npm|virtual)- or otherwise enforce a delimiter after the package name).
| if (urlOrPath.includes(`/.store/${sanitized}-`)) return true; | |
| if ( | |
| urlOrPath.includes(`/.store/${sanitized}-npm-`) || | |
| urlOrPath.includes(`/.store/${sanitized}-virtual-`) | |
| ) { | |
| return true; | |
| } |
| packages: | ||
| - path: . |
There was a problem hiding this comment.
This appmap.yml explicitly sets packages: [{ path: '.' }] but doesn't exclude node_modules/.yarn. In this repo the default package config excludes those directories (see src/config.ts default packages), and most test apps rely on that to avoid instrumenting dependencies. Consider either removing packages: entirely (to fall back to defaults) or adding an exclude list so the pnpm-compat test doesn't instrument the entire dependency tree (which can significantly slow tests and bloat generated AppMaps).
| packages: | |
| - path: . |
| @@ -0,0 +1,7 @@ | |||
| { | |||
| "name": "pnpm-compat-appmap-node-test", | |||
| "private": true, | |||
There was a problem hiding this comment.
This test project package.json omits packageManager. Other test subprojects pin Yarn via packageManager (e.g. test/mocha/package.json:3), which helps Corepack/CI reliably run the intended Yarn version when executing commands from that subdirectory. Consider adding "packageManager": "yarn@4.13.0" here to ensure yarn install/yarn vitest in test/pnpm-compat/ consistently uses Yarn 4.
| "private": true, | |
| "private": true, | |
| "packageManager": "yarn@4.13.0", |
Updates yarn from 3.6.3 to 4.13.0 and adds a 2-day minimum package age gate (
npmMinimalAgeGate) as a supply-chain security measure.Doing this unearthed some issues which were fixed:
.storesubdirectory from the package name to the genericpackage/, breaking path-based hook detection in the mocha, jest, and vitest hooks. AddedmatchesPackageFile()utility to handle all layouts (classic node_modules, yarn 3 pnpm, yarn 4 pnpm).nodeLinker: pnpmtonodeLinker: node-modules(avoids the yarn 4 pnpm linker compatibility gap with Next.js 14), and added a minimal independenttest/pnpm-compat/sub-project to keep explicit test coverage of the pnpm linker path format.