Discovered blocking this PR's own Windows CI (unrelated to this PR's actual diff, fixed inline per this repo's no-defer policy): PR #4552's "full test (windows-latest, 24, shard 2/3)" job failed tests/check-env.test.cjs's npm-version subtest with "npm binary not found on PATH" under chunk 5/9's heavy load (51 concurrent files, 5+ minutes). Root-caused via the CI log: the check's spawnSync call used a 10s timeout, and every failure mode -- ENOENT, a signal-killed timeout, a non-zero exit, a thrown spawn error -- collapsed into that one message (only `res.status === 0 && res.stdout` was checked), so a genuine npm.cmd cold-start timeout under contention was indistinguishable from npm actually being absent. Extracted the reason-selection into describeNpmVersionCheckFailure, a pure function in the new scripts/lib/npm-version-check-diagnosis.cjs (kept out of check-env.cjs itself, which runs its CLI unconditionally on require with no `require.main === module` guard, so the pure logic can be unit-tested without triggering a real environment check). Reports ENOENT, signal-kill, non-zero-exit, and thrown-error cases distinctly. Does NOT raise the 10s timeout itself -- a slow subprocess under contention is a cost to reduce, not a tolerance to widen. Also fixed a stale tsconfig.build.tsbuildinfo incremental-build cache discovered while verifying this change: npm run build:lib was silently omitting gsd-core/bin/lib/markdown-table.cjs (a real, needed compiled module -- src/state-document.cts requires it), which only surfaced via npm run lint:generated-sync's gen-health-docs check failing with Cannot find module. Deleting the cache and rebuilding fresh restored it; docs/INVENTORY-MANIFEST.json needed no net change once the build was genuinely complete. Manually verified describeNpmVersionCheckFailure's five branches directly (ENOENT, signal-kill, non-zero exit, thrown error, defensive default) before wiring the test file, since this repo blocks local node --test. Re-ran node scripts/check-env.cjs directly to confirm the real success path is unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
42 lines
1.8 KiB
JavaScript
42 lines
1.8 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* #4460: distinguishes WHY scripts/check-env.cjs's npm-version check's
|
|
* `spawnSync(npmCmd, ['--version'], ...)` produced no usable output,
|
|
* instead of collapsing every case into "npm binary not found on PATH" -- a
|
|
* message that used to fire identically for a genuinely-missing binary AND
|
|
* for a spawnSync TIMEOUT under CI load (status stays null, stdout stays
|
|
* empty, either way). Root-caused live: an unrelated PR's Windows CI shard
|
|
* failed this check while running 51 concurrent test files; npm.cmd's own
|
|
* cold-start plausibly exceeded the 10s window under that contention, and
|
|
* the misleading message made a real timeout indistinguishable from npm
|
|
* actually being absent.
|
|
*
|
|
* Kept out of scripts/check-env.cjs itself (which runs its CLI unconditionally
|
|
* on require, with no `require.main === module` guard) so this pure logic
|
|
* can be required directly by tests without triggering a real environment
|
|
* check as a side effect.
|
|
*
|
|
* @param {import('child_process').SpawnSyncReturns<string>|null} spawnResult
|
|
* @param {Error|null} spawnThrew
|
|
* @param {number} timeoutMs
|
|
* @returns {string}
|
|
*/
|
|
function describeNpmVersionCheckFailure(spawnResult, spawnThrew, timeoutMs) {
|
|
if (spawnResult && spawnResult.error && spawnResult.error.code === 'ENOENT') {
|
|
return 'npm binary not found on PATH';
|
|
}
|
|
if (spawnResult && spawnResult.signal) {
|
|
return `npm --version was killed (signal ${spawnResult.signal}) -- likely the ${timeoutMs}ms timeout under CI load, not a missing binary`;
|
|
}
|
|
if (spawnResult && spawnResult.status != null && spawnResult.status !== 0) {
|
|
return `npm --version exited ${spawnResult.status} with no usable output`;
|
|
}
|
|
if (spawnThrew) {
|
|
return `npm --version could not be spawned: ${spawnThrew.message}`;
|
|
}
|
|
return 'npm binary not found on PATH';
|
|
}
|
|
|
|
module.exports = { describeNpmVersionCheckFailure };
|