Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,10 @@ function readPackageJson(f: string = findRoot(cwd()), file: string | undefined =
? `Package.json at ${packageJsonPath} does not exist`
: `No package.json found at ${packageJsonPath}. Run this command from your project root (the folder that contains package.json), or pass --package-json <path> to point at it (for example in a monorepo).`
log.error(message)
throw new Error(message)
// Expected user error, not a crash: throw a CliUserError so error tracking
// skips it. Keep the thrown message constant (the path goes in context) so
// it fingerprints one issue instead of one per absolute path.
throw new CliUserError('package.json not found. Run this command from your project root, or pass --package-json <path>.', { packageJsonPath })
}
const packageJson = readFileSync(packageJsonPath)
return JSON.parse(packageJson as any)
Expand Down Expand Up @@ -498,7 +501,9 @@ export async function getAllPackagesDependencies(f: string = findRoot(cwd()), fi
if (!existsSync(file)) {
const message = `Package.json at ${file} does not exist`
log.error(message)
throw new Error(message)
// Expected user error, not a crash: constant thrown message, path in
// context, so error tracking skips it and does not fingerprint per path.
throw new CliUserError('package.json not found. Run this command from your project root, or pass --package-json <path>.', { packageJsonPath: file })
}
}
}
Expand Down Expand Up @@ -573,7 +578,9 @@ export async function getDeclaredPackageVersionMap(f: string = findRoot(cwd()),
if (!existsSync(file)) {
const message = `Package.json at ${file} does not exist`
log.error(message)
throw new Error(message)
// Expected user error, not a crash: constant thrown message, path in
// context, so error tracking skips it and does not fingerprint per path.
throw new CliUserError('package.json not found. Run this command from your project root, or pass --package-json <path>.', { packageJsonPath: file })
}
}
}
Expand Down
20 changes: 13 additions & 7 deletions cli/test/test-package-json-guard.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@ function makeDir(name) {

// Regression: running `capgo init` (and doctor) from a directory without a
// package.json used to escape as a raw Node ENOENT stack trace. readPackageJson
// must now guard the default path and surface an actionable message.
await test('getBundleVersion throws a helpful message when package.json is missing', async () => {
// must now guard the default path and throw a CliUserError with a constant,
// actionable message, so error tracking skips it and does not open one issue
// per absolute path.
await test('getBundleVersion throws a CliUserError when package.json is missing', async () => {
const dir = makeDir('missing-pkg')
try {
assert.throws(
() => getBundleVersion(dir),
(error) => {
assert.ok(!(error instanceof Error && 'code' in error && error.code === 'ENOENT'), 'should not surface a raw ENOENT')
assert.match(error.message, /No package\.json found at/)
assert.match(error.message, /project root/)
assert.match(error.message, /--package-json/)
assert.equal(error.name, 'CliUserError')
// Constant, actionable message (no interpolated path) so error tracking
// fingerprints one issue; the path travels in context instead.
assert.equal(error.message, 'package.json not found. Run this command from your project root, or pass --package-json <path>.')
assert.match(error.context.packageJsonPath, /package\.json$/)
return true
},
)
Expand All @@ -43,14 +47,16 @@ await test('getBundleVersion throws a helpful message when package.json is missi
}
})

await test('getPackageScripts throws the explicit-path message when a supplied package.json is missing', async () => {
await test('getPackageScripts throws a CliUserError with the path in context for an explicit package.json', async () => {
const dir = makeDir('missing-explicit-pkg')
try {
const missing = join(dir, 'package.json')
assert.throws(
() => getPackageScripts(undefined, missing),
(error) => {
assert.match(error.message, /Package\.json at .*package\.json does not exist/)
assert.equal(error.name, 'CliUserError')
assert.equal(error.message, 'package.json not found. Run this command from your project root, or pass --package-json <path>.')
assert.equal(error.context.packageJsonPath, missing)
return true
},
)
Expand Down
Loading