@@ -3,8 +3,9 @@ import * as path from "node:path";
33
44import { printLogTail , QUIET_COMMAND_CAPTURE_LIMIT } from "../../../lib/command-output" ;
55import type { PackageManager } from "../../../lib/detect-package-manager" ;
6- import { CliCancelledError , CreateError , processErrorProperties } from "../../../lib/errors" ;
6+ import { CliCancelledError , cliErrorProperties , throwCommandFailure } from "../../../lib/errors" ;
77import { mutedNpmEnv , runCommand } from "../../../lib/process-runner" ;
8+ import { withRetry } from "../../../lib/retry" ;
89import { withSpinner } from "../../../lib/spinner" ;
910import type { OverlayName , TemplateName } from "./create-types" ;
1011import type { CreateTelemetryClient } from "./telemetry" ;
@@ -82,53 +83,47 @@ export async function installProjectDependencies(params: {
8283 if ( verbose ) {
8384 console . info ( `Installing dependencies with: ${ installCmd } \n` ) ;
8485 }
85- const installResult = verbose
86- ? await runInstall ( )
87- : await withSpinner ( "Installing dependencies..." , runInstall ) ;
88- if ( ! installResult . error && installResult . status === 0 ) {
86+ const attemptInstall = async ( ) => {
87+ const result = await runInstall ( ) ;
88+ if ( ! result . error && result . status === 0 ) return result ;
89+
8990 if ( ! verbose ) {
90- console . info ( "✓ Dependencies installed ") ;
91+ printLogTail ( result . diagnosticTail , "install log (tail) ") ;
9192 }
92- tel . trackDependencyInstallSucceeded ( {
93- template,
94- ai_setup : aiSetup ,
95- dependency_installed : true ,
93+ throwCommandFailure ( result , "dependency_install" , "dependency install failed" , {
94+ error_class : "dependency" ,
95+ error_code : "NONZERO_EXIT" ,
9696 } ) ;
97- return true ;
98- }
97+ } ;
9998
100- if ( ! verbose ) {
101- printLogTail ( installResult . diagnosticTail , "install log (tail)" ) ;
102- }
103- const properties = processErrorProperties ( installResult , "dependency_install" , {
104- error_class : "dependency" ,
105- error_code : "NONZERO_EXIT" ,
106- } ) ;
107- if ( properties . error_class === "user_cancelled" ) {
108- tel . trackDependencyInstallCancelled ( {
99+ try {
100+ const runWithRetry = ( ) =>
101+ withRetry ( "Dependency install" , attemptInstall , {
102+ onRetry : tel . reportNetworkRetry ( "dependency_install" ) ,
103+ } ) ;
104+ await ( verbose ? runWithRetry ( ) : withSpinner ( "Installing dependencies..." , runWithRetry ) ) ;
105+ } catch ( err ) {
106+ const properties = {
109107 template,
110108 ai_setup : aiSetup ,
111109 dependency_installed : false ,
112- ...properties ,
113- } ) ;
114- throw new CliCancelledError (
115- "dependency_install" ,
116- properties . cancellation_exit_code ?? 0 ,
117- properties ,
118- ) ;
110+ ...cliErrorProperties ( err ) ,
111+ } ;
112+ if ( err instanceof CliCancelledError ) {
113+ tel . trackDependencyInstallCancelled ( properties ) ;
114+ } else {
115+ tel . trackDependencyInstallFailed ( properties ) ;
116+ }
117+ throw err ;
118+ }
119+
120+ if ( ! verbose ) {
121+ console . info ( "✓ Dependencies installed" ) ;
119122 }
120- tel . trackDependencyInstallFailed ( {
123+ tel . trackDependencyInstallSucceeded ( {
121124 template,
122125 ai_setup : aiSetup ,
123- dependency_installed : false ,
124- ...properties ,
126+ dependency_installed : true ,
125127 } ) ;
126- const { failure_stage, error_class, error_code, ...metadata } = properties ;
127- throw new CreateError (
128- failure_stage ,
129- "dependency install failed" ,
130- error_class ,
131- error_code ,
132- metadata ,
133- ) ;
128+ return true ;
134129}
0 commit comments