@@ -17,6 +17,7 @@ import { z } from 'zod';
1717import { editToolParameters } from './editTool' ;
1818import { getAbsolutePath } from '~/lib/stores/files' ;
1919import { streamOutput } from '~/utils/process' ;
20+ import { outputLabels , type OutputLabels } from './deployToolOutputLabels' ;
2021
2122const logger = createScopedLogger ( 'ActionRunner' ) ;
2223
@@ -372,25 +373,88 @@ export class ActionRunner {
372373 case 'deploy' : {
373374 const container = await this . #webcontainer;
374375 await waitForContainerBootState ( ContainerBootState . READY ) ;
375- const convexProc = await container . spawn ( 'sh' , [
376- '-c' ,
377- 'eslint . && convex dev --once && tsc --noEmit -p tsconfig.app.json' ,
378- ] ) ;
379- action . abortSignal . addEventListener ( 'abort' , ( ) => {
380- convexProc . kill ( ) ;
381- } ) ;
382-
383- const { output, exitCode } = await streamOutput ( convexProc , {
384- onOutput : ( output ) => {
385- this . terminalOutput . set ( output ) ;
386- } ,
387- debounceMs : 50 ,
388- } ) ;
389- const cleanedOutput = cleanConvexOutput ( output ) ;
390- if ( exitCode !== 0 ) {
391- throw new Error ( `Convex failed with exit code ${ exitCode } : ${ cleanedOutput } ` ) ;
376+
377+ // TODO need to get the output into here
378+ result = '' ;
379+
380+ /** Return a promise of output on success, throws an error containing output on failure. */
381+ const run = async ( command : string , args : string [ ] , errorPrefix : OutputLabels ) : Promise < string > => {
382+ const t0 = performance . now ( ) ;
383+ const proc = await container . spawn ( command , args ) ;
384+ let abortListener : ( ) => void = ( ) => {
385+ proc . kill ( ) ;
386+ } ;
387+ action . abortSignal . addEventListener ( 'abort' , abortListener ) ;
388+ const { output : output , exitCode : exitCode } = await streamOutput ( proc , {
389+ onOutput : ( output ) => {
390+ this . terminalOutput . set ( output ) ;
391+ } ,
392+ debounceMs : 50 ,
393+ } ) ;
394+
395+ const cleanedOutput = cleanConvexOutput ( output ) ;
396+ const time = performance . now ( ) - t0 ;
397+ logger . trace ( 'finished' , errorPrefix , 'in' , Math . round ( time ) ) ;
398+ if ( exitCode !== 0 ) {
399+ throw new Error ( `[${ errorPrefix } ] Failed with exit code ${ exitCode } : ${ cleanedOutput } ` ) ;
400+ }
401+ action . abortSignal . removeEventListener ( 'abort' , abortListener ) ;
402+ return cleanedOutput + '\n\n' ;
403+ } ;
404+
405+ /*
406+ result += await run(
407+ 'sh',
408+ [
409+ '-c',
410+ 'convex codegen' +
411+ ' && tsc --noEmit -p tsconfig.app.json' +
412+ ' && eslint convex' +
413+ ' && convex dev --once --typecheck=disable',
414+ ],
415+ 'do everything' as any,
416+ );
417+ */
418+
419+ const t0 = performance . now ( ) ;
420+ result += await run ( 'convex' , [ 'codegen' , '--typecheck=disable' ] , outputLabels . convexTypecheck ) ;
421+
422+ // what if we ran tsc, eslint, and deploy all at the same time?
423+ const tscP = await run ( 'tsc' , [ '--noEmit' , '-p' , 'tsconfig.app.json' ] , outputLabels . frontendTypecheck ) ;
424+
425+ const eslintP = ( async function maybeRunEslint ( ) : Promise < string > {
426+ // Only run eslint if the file we expect is present and contains '@convex-dev/eslint-plugin'
427+ // Projects created with older versions of Chef have this file but it does not container
428+ // @convex -dev/eslint-plugin.
429+ let contents = '' ;
430+ try {
431+ contents = await container . fs . readFile ( 'eslint.config.js' , 'utf-8' ) ;
432+ } catch ( e : any ) {
433+ if ( ! e . message . includes ( 'ENOENT: no such file or directory' ) ) {
434+ throw e ;
435+ }
436+ }
437+ if ( contents . includes ( '@convex-dev/eslint-plugin' ) ) {
438+ await run ( 'eslint' , [ 'convex' ] , outputLabels . convexLint ) ;
439+ }
440+ return '' ;
441+ } ) ( ) ;
442+
443+ const deployP = run ( 'convex' , [ 'dev' , '--once' , '--typecheck=disable' ] , outputLabels . convexDeploy ) ;
444+
445+ const [ tscResult , eslintResult , deployResult ] = await Promise . allSettled ( [ tscP , eslintP , deployP ] ) ;
446+ console . log ( 'parallel stuff done in' , performance . now ( ) - t0 ) ;
447+ // TODO abort later ones?
448+ // Throw the first failure in this order
449+ for ( const pResult of [ tscResult , eslintResult , deployResult ] ) {
450+ if ( pResult . status === 'fulfilled' ) {
451+ result += pResult . value ;
452+ } else {
453+ throw pResult . reason ;
454+ }
392455 }
393- result = cleanedOutput ;
456+
457+ result += await run ( 'convex' , [ 'dev' , '--once' , '--typecheck=disable' ] , outputLabels . convexDeploy ) ;
394458
395459 // Start the default preview if it’s not already running
396460 if ( ! workbenchStore . isDefaultPreviewRunning ( ) ) {
0 commit comments