| … | … | @@ -0,0 +1,93 @@ |
| 1 | import test from 'brittle' |
| 2 | import { readdirSync, readFileSync, existsSync, statSync } from '#node:fs' |
| 3 | import { join, dirname } from '#node:path' |
| 4 | import { fileURLToPath } from '#node:url' |
| 5 | |
| 6 | // Drift guard for the duplicated-runtime bug. |
| 7 | // |
| 8 | // `pgh publish` builds .pgh-lock.json by WALKING the physically installed |
| 9 | // node_modules (lib/publish.js: "Walks node_modules/ of an app dir, computes a |
| 10 | // tree hash per top-level dep") -- it does not re-resolve version ranges. So the |
| 11 | // tarball contains whatever is on disk at publish time. |
| 12 | // |
| 13 | // node_modules/pgh is a SYMLINK to the sibling ../../pgh repo, which has its own |
| 14 | // separately-installed node_modules. Both repos declared bare-runtime@^1.28.5 and |
| 15 | // were installed at different times, so they drifted apart: |
| 16 | // |
| 17 | // pgh-sidecar/node_modules → bare-runtime@1.28.7 |
| 18 | // pgh/node_modules → bare-runtime@1.28.6 |
| 19 | // |
| 20 | // The publish walk followed the symlink and picked up BOTH, putting two ~90MB |
| 21 | // runtimes in one bootstrap tarball. Measured cost: 90.0 MiB of a 786.1 MiB tree, |
| 22 | // 53% of all reclaimable duplication across 47 duplicated packages. |
| 23 | // |
| 24 | // Both repos now pin bare-runtime EXACTLY. An exact pin only holds if BOTH are |
| 25 | // repinned together on an upgrade -- repin one and the duplicate silently returns. |
| 26 | // This test is what makes that failure loud instead of silent. |
| 27 | |
| 28 | const here = dirname(fileURLToPath(import.meta.url)) |
| 29 | const root = join(here, '..') |
| 30 | |
| 31 | // Collect name@version for every bare-runtime* package reachable from a tree, |
| 32 | // following the file:-dep symlinks that the publish walk also follows. |
| 33 | function collectRuntimes (nmDir, found = new Map(), depth = 0) { |
| 34 | if (depth > 2 || !existsSync(nmDir)) return found |
| 35 | let entries = [] |
| 36 | try { entries = readdirSync(nmDir) } catch { return found } |
| 37 | for (const entry of entries) { |
| 38 | if (entry.startsWith('.')) continue |
| 39 | const dir = join(nmDir, entry) |
| 40 | const pkgPath = join(dir, 'package.json') |
| 41 | if (existsSync(pkgPath)) { |
| 42 | try { |
| 43 | const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) |
| 44 | if (pkg && /^bare-runtime/.test(pkg.name || '') && pkg.version) { |
| 45 | if (!found.has(pkg.name)) found.set(pkg.name, new Set()) |
| 46 | found.get(pkg.name).add(pkg.version) |
| 47 | } |
| 48 | } catch {} |
| 49 | } |
| 50 | // Recurse into nested node_modules AND through symlinked file: deps — |
| 51 | // the publish walk resolves both, so the guard must too. |
| 52 | let isDir = false |
| 53 | try { isDir = statSync(dir).isDirectory() } catch {} |
| 54 | if (isDir) collectRuntimes(join(dir, 'node_modules'), found, depth + 1) |
| 55 | } |
| 56 | return found |
| 57 | } |
| 58 | |
| 59 | test('bare-runtime is pinned to an exact version (not a floating range)', (t) => { |
| 60 | const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) |
| 61 | const direct = (pkg.dependencies || {})['bare-runtime'] |
| 62 | const override = (pkg.overrides || {})['bare-runtime'] |
| 63 | t.ok(direct, 'declared as a direct dependency') |
| 64 | t.absent(/[\^~*x]|\s-\s/.test(direct || ''), `direct dep "${direct}" is exact, not a range`) |
| 65 | t.is(override, direct, 'overrides entry agrees with the direct dep (npm EOVERRIDEs if they conflict)') |
| 66 | }) |
| 67 | |
| 68 | test('the installed tree resolves bare-runtime to exactly ONE version', (t) => { |
| 69 | const found = collectRuntimes(join(root, 'node_modules')) |
| 70 | t.ok(found.size > 0, 'found bare-runtime packages in the installed tree') |
| 71 | const dupes = [...found].filter(([, versions]) => versions.size > 1) |
| 72 | for (const [name, versions] of dupes) { |
| 73 | t.fail(`${name} resolved to ${versions.size} versions: ${[...versions].sort().join(', ')} — ` + |
| 74 | 'the publish walk will put all of them in the bootstrap tarball (~90MB each). ' + |
| 75 | 'Repin bare-runtime to the SAME exact version in BOTH pgh and pgh-sidecar, then npm install in each.') |
| 76 | } |
| 77 | t.is(dupes.length, 0, 'no bare-runtime package is duplicated across the tree') |
| 78 | }) |
| 79 | |
| 80 | test('the sibling pgh repo pins the same exact version', (t) => { |
| 81 | // The sidecar symlinks node_modules/pgh -> ../../pgh, so a mismatch here is |
| 82 | // precisely how the duplicate gets reintroduced on the next upgrade. |
| 83 | const siblingPkg = join(root, '..', 'pgh', 'package.json') |
| 84 | if (!existsSync(siblingPkg)) { |
| 85 | t.pass('sibling pgh checkout not present — skipped') |
| 86 | return |
| 87 | } |
| 88 | const mine = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) |
| 89 | const theirs = JSON.parse(readFileSync(siblingPkg, 'utf8')) |
| 90 | const a = (mine.dependencies || {})['bare-runtime'] |
| 91 | const b = (theirs.dependencies || {})['bare-runtime'] |
| 92 | t.is(b, a, `pgh pins "${b}", pgh-sidecar pins "${a}" — they MUST match or publish ships both`) |
| 93 | }) |