* test(#4137): keg-only Homebrew Cellar path falls back to raw execPath Regression tests for the Homebrew branch of normalizeNodePath: the rewrite to <prefix>/bin/node must be existsSync-guarded like the mise/volta branches, falling through to the raw execPath when the keg-only formula was never linked into <prefix>/bin. Also makes the existing #3181/#2185 Cellar assertions hermetic by injecting existsSync stubs (granting existence to exactly the one candidate each asserts) so they no longer depend on the runner machine's real /usr/local/bin/node. * fix(#4137): existsSync-guard the Homebrew Cellar rewrite in normalizeNodePath The Homebrew branch of normalizeNodePath returned <prefix>/bin/node unconditionally — the only one of five runtime branches that never probed its rewrite candidate. On a keg-only or versioned Homebrew install (node@24 never brew-linked) that path does not exist, so every managed hook command baked by resolveNodeRunner/buildBakedNodeToken/ buildNodeRunnerChainToken failed at invocation with exit 127, /bin/sh: <prefix>/bin/node: No such file or directory. Guard the rewrite with the already-injected existsSync exactly like the mise and volta branches: when <prefix>/bin/node exists (linked formula) the rewrite is byte-identical to today; when it does not, fall through to the raw execPath — a working keg path instead of an immediately broken one. Also drops two now-unused constants from the regression tests. * test(#4137): make the #977 non-fnm Cellar assertions hermetic too The Bug #977 folded block's two 'still maps to stable symlink' assertions called normalizeNodePath without an existsSync stub, silently depending on the runner machine's real /usr/local/bin/node (present on the Linux bench image, absent for /opt/homebrew). With the #4137 guard these become environment-dependent; grant each exactly the one candidate it asserts. * chore(#4137): add changeset fragment * chore(#4137): backfill changeset pr number --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -512,11 +512,19 @@ function normalizeNodePath(execPath: string, opts?: NodeNormOpts): string {
|
||||
// survives the upgrade. Derive <prefix> from the path itself (more reliable
|
||||
// than HOMEBREW_PREFIX env — the path IS the install location) so every layout
|
||||
// is covered by one branch instead of one per known prefix (#2185).
|
||||
//
|
||||
// #4137: rewrite only when the symlink exists; otherwise fall through to the
|
||||
// raw execPath, exactly like the mise and volta branches. A keg-only/versioned
|
||||
// formula (node@24 installed but never `brew link`ed) has no <prefix>/bin/node
|
||||
// at all, so the unconditional rewrite handed every managed hook a path that
|
||||
// fails at invocation — a rewrite must never turn a working keg path into an
|
||||
// immediately broken one.
|
||||
const homebrewMatch = normalizedForMatch.match(
|
||||
/^(.+)\/Cellar\/node(@\d+)?\/[^/]+\/bin\/node(\.exe)?$/i,
|
||||
);
|
||||
if (homebrewMatch) {
|
||||
return `${homebrewMatch[1]}/bin/node${homebrewMatch[3] || ''}`;
|
||||
const homebrewStable = `${homebrewMatch[1]}/bin/node${homebrewMatch[3] || ''}`;
|
||||
if (existsSync(homebrewStable)) return homebrewStable;
|
||||
}
|
||||
|
||||
// mise pins a concrete node version at <data>/installs/node/<ver>/bin/node
|
||||
|
||||
Reference in New Issue
Block a user