Skip to content

Commit 548f541

Browse files
committed
Add more debug info to fix install errors
1 parent 5749f54 commit 548f541

File tree

3 files changed

+96
-46
lines changed

3 files changed

+96
-46
lines changed

src/commands/fix/agent-fix.mts

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ export type InstallPhaseHandler = (
9797
export type Installer = (
9898
pkgEnvDetails: EnvDetails,
9999
options: InstallOptions,
100-
) => Promise<NodeClass | null>
100+
) => Promise<InstallerResult>
101+
102+
export type InstallerResult = {
103+
actualTree?: NodeClass | undefined
104+
error?: unknown | undefined
105+
}
101106

102107
const noopHandler = (() => {}) as unknown as InstallPhaseHandler
103108

@@ -198,13 +203,15 @@ export async function agentFix(
198203
: []
199204
}
200205

201-
const handleInstallFail = (): CResult<{ fixed: boolean }> => {
206+
const handleInstallFail = (
207+
error?: unknown | undefined,
208+
): CResult<{ fixed: boolean }> => {
202209
cleanupInfoEntriesLoop()
203210
spinner?.stop()
204211
return {
205212
ok: false,
206213
message: 'Install failed',
207-
cause: `Unexpected condition: ${pkgEnvDetails.agent} install failed`,
214+
cause: `${pkgEnvDetails.agent} install failed${error ? `; ${error}` : ''}`,
208215
}
209216
}
210217

@@ -273,19 +280,25 @@ export async function agentFix(
273280
// eslint-disable-next-line no-await-in-loop
274281
await removeNodeModules(cwd)
275282
}
276-
const maybeActualTree =
277-
fixEnv.isCi && existsSync(path.join(rootPath, 'node_modules'))
278-
? // eslint-disable-next-line no-await-in-loop
279-
await getActualTree(cwd)
280-
: // eslint-disable-next-line no-await-in-loop
281-
await installer(pkgEnvDetails, { cwd, spinner })
282-
if (maybeActualTree && existsSync(pkgEnvDetails.lockPath)) {
283+
if (fixEnv.isCi && existsSync(path.join(rootPath, 'node_modules'))) {
284+
// eslint-disable-next-line no-await-in-loop
285+
actualTree = await getActualTree(cwd)
286+
} else {
287+
// eslint-disable-next-line no-await-in-loop
288+
const installResult = await installer(pkgEnvDetails, { cwd, spinner })
289+
const maybeActualTree = installResult.actualTree
290+
if (!maybeActualTree) {
291+
// Exit early if install fails.
292+
return handleInstallFail(installResult.error)
293+
}
283294
actualTree = maybeActualTree
284295
}
285-
}
286-
if (!actualTree) {
287-
// Exit early if install fails.
288-
return handleInstallFail()
296+
if (!existsSync(pkgEnvDetails.lockPath)) {
297+
// Exit early if lockfile is missing.
298+
return handleInstallFail(
299+
new Error(`Missing lockfile at ${pkgEnvDetails.lockPath}`),
300+
)
301+
}
289302
}
290303

291304
const oldVersions = arrayUnique(
@@ -447,15 +460,22 @@ export async function agentFix(
447460
const newId = `${name}@${applyRange(refRange, newVersion, rangeStyle)}`
448461
spinner?.info(`Installing ${newId} in ${workspace}.`)
449462

450-
let error
463+
let error: unknown | undefined
451464
let errored = false
452465
try {
453466
// eslint-disable-next-line no-await-in-loop
454-
const maybeActualTree = await installer(pkgEnvDetails, {
467+
const installResult = await installer(pkgEnvDetails, {
455468
cwd,
456469
spinner,
457470
})
458-
if (maybeActualTree && existsSync(pkgEnvDetails.lockPath)) {
471+
const maybeActualTree = installResult.actualTree
472+
if (!maybeActualTree) {
473+
errored = true
474+
error = installResult.error
475+
} else if (!existsSync(pkgEnvDetails.lockPath)) {
476+
errored = true
477+
error = new Error(`Missing lockfile at ${pkgEnvDetails.lockPath}`)
478+
} else {
459479
actualTree = maybeActualTree
460480
// eslint-disable-next-line no-await-in-loop
461481
await afterInstall(
@@ -473,8 +493,6 @@ export async function agentFix(
473493
}
474494
spinner?.success(`Fixed ${name} in ${workspace}.`)
475495
seenVersions.add(newVersion)
476-
} else {
477-
errored = true
478496
}
479497
} catch (e) {
480498
error = e
@@ -516,16 +534,23 @@ export async function agentFix(
516534
// eslint-disable-next-line no-await-in-loop
517535
await gitDeleteBranch(branch, cwd)
518536
// eslint-disable-next-line no-await-in-loop
519-
const maybeActualTree = await installer(pkgEnvDetails, {
537+
const installResult = await installer(pkgEnvDetails, {
520538
cwd,
521539
spinner,
522540
})
523-
if (maybeActualTree && existsSync(pkgEnvDetails.lockPath)) {
524-
actualTree = maybeActualTree
525-
continue infosLoop
541+
const maybeActualTree = installResult.actualTree
542+
if (!maybeActualTree) {
543+
// Exit early if install fails.
544+
return handleInstallFail(installResult.error)
526545
}
527-
// Exit early if install fails.
528-
return handleInstallFail()
546+
if (!existsSync(pkgEnvDetails.lockPath)) {
547+
// Exit early if lockfile is missing.
548+
return handleInstallFail(
549+
new Error(`Missing lockfile at ${pkgEnvDetails.lockPath}`),
550+
)
551+
}
552+
actualTree = maybeActualTree
553+
continue infosLoop
529554
}
530555

531556
seenBranches.add(branch)
@@ -595,15 +620,17 @@ export async function agentFix(
595620
// eslint-disable-next-line no-await-in-loop
596621
await gitCheckoutBranch(fixEnv.baseBranch, cwd)
597622
// eslint-disable-next-line no-await-in-loop
598-
const maybeActualTree = await installer(pkgEnvDetails, {
623+
const installResult = await installer(pkgEnvDetails, {
599624
cwd,
600625
spinner,
601626
})
602627
spinner?.stop()
628+
const maybeActualTree = installResult.actualTree
603629
if (maybeActualTree) {
604630
actualTree = maybeActualTree
605631
} else {
606632
errored = true
633+
error = installResult.error
607634
}
608635
}
609636
if (errored) {
@@ -624,17 +651,17 @@ export async function agentFix(
624651
editablePkgJson.save({ ignoreWhitespace: true }),
625652
])
626653
// eslint-disable-next-line no-await-in-loop
627-
const maybeActualTree = await installer(pkgEnvDetails, {
654+
const installResult = await installer(pkgEnvDetails, {
628655
cwd,
629656
spinner,
630657
})
631658
spinner?.stop()
632-
if (maybeActualTree) {
633-
actualTree = maybeActualTree
634-
} else {
659+
const maybeActualTree = installResult.actualTree
660+
if (!maybeActualTree) {
635661
// Exit early if install fails.
636-
return handleInstallFail()
662+
return handleInstallFail(installResult.error)
637663
}
664+
actualTree = maybeActualTree
638665
}
639666
return {
640667
ok: false,

src/commands/fix/npm-fix.mts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import { runAgentInstall } from '../../utils/agent.mts'
1414
import { getAlertsMapFromPurls } from '../../utils/alerts-map.mts'
1515
import { getNpmConfig } from '../../utils/npm-config.mts'
1616

17-
import type { FixConfig, InstallOptions } from './agent-fix.mts'
17+
import type {
18+
FixConfig,
19+
InstallOptions,
20+
InstallerResult,
21+
} from './agent-fix.mts'
1822
import type { NodeClass } from '../../shadow/npm/arborist/types.mts'
1923
import type { CResult } from '../../types.mts'
2024
import type { EnvDetails } from '../../utils/package-environment.mts'
@@ -23,7 +27,7 @@ import type { PackageJson } from '@socketsecurity/registry/lib/packages'
2327
async function install(
2428
pkgEnvDetails: EnvDetails,
2529
options: InstallOptions,
26-
): Promise<NodeClass | null> {
30+
): Promise<InstallerResult> {
2731
const {
2832
args: extraArgs,
2933
cwd,
@@ -68,6 +72,7 @@ async function install(
6872
const isSpinning = spinner?.isSpinning
6973
spinner?.stop()
7074

75+
let error
7176
let errored = false
7277
try {
7378
await runAgentInstall(pkgEnvDetails, {
@@ -76,24 +81,30 @@ async function install(
7681
stdio: useDebug ? 'inherit' : 'ignore',
7782
})
7883
} catch (e) {
79-
debugFn('error', `caught: ${quotedCmd} failed`)
80-
debugDir('inspect', { error: e })
8184
errored = true
85+
error = e
86+
debugFn('error', `caught: ${quotedCmd} failed`)
87+
debugDir('inspect', { error })
8288
}
8389

84-
let actualTree: NodeClass | null = null
90+
let actualTree: NodeClass | undefined = undefined
8591
if (!errored) {
8692
try {
8793
actualTree = await getActualTree(cwd)
8894
} catch (e) {
95+
errored = true
96+
error = e
8997
debugFn('error', 'caught: Arborist error')
90-
debugDir('inspect', { error: e })
98+
debugDir('inspect', { error })
9199
}
92100
}
93101
if (isSpinning) {
94102
spinner.start()
95103
}
96-
return actualTree
104+
return {
105+
...(actualTree ? { actualTree } : undefined),
106+
...(errored ? { error } : undefined),
107+
}
97108
}
98109

99110
export async function npmFix(

src/commands/fix/pnpm-fix.mts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import {
2121
import { applyRange } from '../../utils/semver.mts'
2222
import { getOverridesDataPnpm } from '../optimize/get-overrides-by-agent.mts'
2323

24-
import type { FixConfig, InstallOptions } from './agent-fix.mts'
24+
import type {
25+
FixConfig,
26+
InstallOptions,
27+
InstallerResult,
28+
} from './agent-fix.mts'
2529
import type { NodeClass } from '../../shadow/npm/arborist/types.mts'
2630
import type { CResult, StringKeyValueObject } from '../../types.mts'
2731
import type { EnvDetails } from '../../utils/package-environment.mts'
@@ -32,7 +36,7 @@ const { OVERRIDES, PNPM } = constants
3236
async function install(
3337
pkgEnvDetails: EnvDetails,
3438
options: InstallOptions,
35-
): Promise<NodeClass | null> {
39+
): Promise<InstallerResult> {
3640
const {
3741
args: extraArgs,
3842
cwd,
@@ -59,6 +63,7 @@ async function install(
5963
const isSpinning = spinner?.isSpinning
6064
spinner?.stop()
6165

66+
let error
6267
let errored = false
6368
try {
6469
await runAgentInstall(pkgEnvDetails, {
@@ -67,24 +72,30 @@ async function install(
6772
stdio: isDebug('stdio') ? 'inherit' : 'ignore',
6873
})
6974
} catch (e) {
70-
debugFn('error', `caught: ${quotedCmd} failed`)
71-
debugDir('inspect', { error: e })
7275
errored = true
76+
error = e
77+
debugFn('error', `caught: ${quotedCmd} failed`)
78+
debugDir('inspect', { error })
7379
}
7480

75-
let actualTree: NodeClass | null = null
81+
let actualTree: NodeClass | undefined = undefined
7682
if (!errored) {
7783
try {
7884
actualTree = await getActualTree(cwd)
7985
} catch (e) {
86+
errored = true
87+
error = e
8088
debugFn('error', 'caught: Arborist error')
81-
debugDir('inspect', { error: e })
89+
debugDir('inspect', { error })
8290
}
8391
}
8492
if (isSpinning) {
8593
spinner.start()
8694
}
87-
return actualTree
95+
return {
96+
...(actualTree ? { actualTree } : undefined),
97+
...(errored ? { error } : undefined),
98+
}
8899
}
89100

90101
export async function pnpmFix(
@@ -104,11 +115,12 @@ export async function pnpmFix(
104115
pkgEnvDetails.agentVersion.major >= 10 &&
105116
(parsePnpmLockfileVersion(lockfile?.lockfileVersion)?.major ?? 0) <= 6
106117
) {
107-
const maybeActualTree = await install(pkgEnvDetails, {
118+
const installResult = await install(pkgEnvDetails, {
108119
args: ['--lockfile-only'],
109120
cwd,
110121
spinner,
111122
})
123+
const maybeActualTree = installResult.actualTree
112124
if (maybeActualTree) {
113125
lockSrc = (await readLockfile(pkgEnvDetails.lockPath)) ?? ''
114126
} else {

0 commit comments

Comments
 (0)