@@ -4,8 +4,10 @@ import {ArgOutput, FlagOutput, Input} from '@oclif/core/lib/interfaces/parser.js
44import Command from '@shopify/cli-kit/node/base-command'
55import { AdminSession , ensureAuthenticatedThemes } from '@shopify/cli-kit/node/session'
66import { loadEnvironment } from '@shopify/cli-kit/node/environments'
7- import { renderWarning } from '@shopify/cli-kit/node/ui'
7+ import { renderWarning , renderConcurrent } from '@shopify/cli-kit/node/ui'
88import { AbortError } from '@shopify/cli-kit/node/error'
9+ import { AbortController } from '@shopify/cli-kit/node/abort'
10+ import { Writable } from 'stream'
911
1012export interface FlagValues {
1113 [ key : string ] : boolean | string | string [ ] | number | undefined
@@ -36,7 +38,11 @@ export default abstract class ThemeCommand extends Command {
3638 return configurationFileName
3739 }
3840
39- async command ( _flags : FlagValues , _session : AdminSession ) : Promise < void > { }
41+ async command (
42+ _flags : FlagValues ,
43+ _session : AdminSession ,
44+ _context ?: { stdout ?: Writable ; stderr ?: Writable } ,
45+ ) : Promise < void > { }
4046
4147 async run <
4248 TFlags extends FlagOutput & { path ?: string ; verbose ?: boolean } ,
@@ -50,20 +56,38 @@ export default abstract class ThemeCommand extends Command {
5056 const requiredFlags = klass . multiEnvironmentsFlags
5157 const { flags} = await this . parse ( klass )
5258
53- // Single environment
54- if ( ! flags . environment ) {
59+ // No environment provided
60+ if ( ! flags . environment ?. length ) {
5561 const session = await this . ensureAuthenticated ( flags )
62+
5663 await this . command ( flags , session )
64+
5765 return
5866 }
5967
60- // Synchronously authenticate all environments
61- const sessions : { [ storeFqdn : string ] : AdminSession } = { }
6268 // OCLIF parses flags.environment as an array when using the --environment & -e flag but
6369 // as a string when using the direct environment variable SHOPIFY_FLAG_ENVIRONMENT
6470 // This handles both cases
6571 const environments = Array . isArray ( flags . environment ) ? flags . environment : [ flags . environment ]
6672
73+ // If only one environment is specified, treat it as single environment mode
74+ if ( environments . length === 1 ) {
75+ const environmentConfig = await loadEnvironment ( environments [ 0 ] , 'shopify.theme.toml' , { from : flags . path } )
76+ const environmentFlags = {
77+ ...flags ,
78+ ...environmentConfig ,
79+ environment : environments ,
80+ }
81+
82+ const session = await this . ensureAuthenticated ( environmentConfig as FlagValues )
83+ await this . command ( environmentFlags , session )
84+
85+ return
86+ }
87+
88+ // Multiple environments
89+ const sessions : { [ storeFqdn : string ] : AdminSession } = { }
90+
6791 // Authenticate on all environments sequentially to avoid race conditions,
6892 // with authentication happening in parallel.
6993 for ( const environmentName of environments ) {
@@ -73,27 +97,34 @@ export default abstract class ThemeCommand extends Command {
7397 sessions [ environmentName ] = await this . ensureAuthenticated ( environmentConfig as FlagValues )
7498 }
7599
76- // Concurrently run commands
77- await Promise . all (
78- environments . map ( async ( environment : string ) => {
79- const environmentConfig = await loadEnvironment ( environment , 'shopify.theme.toml' , { from : flags . path } )
80- const environmentFlags = {
81- ...flags ,
82- ...environmentConfig ,
83- environment : [ environment ] ,
84- }
85-
86- if ( ! this . validConfig ( environmentConfig as FlagValues , requiredFlags , environment ) ) return
87-
88- const session = sessions [ environment ]
89-
90- if ( ! session ) {
91- throw new AbortError ( `No session found for environment ${ environment } ` )
92- }
93-
94- return this . command ( environmentFlags , session )
95- } ) ,
96- )
100+ // Use renderConcurrent for multi-environment execution
101+ const abortController = new AbortController ( )
102+
103+ await renderConcurrent ( {
104+ processes : environments . map ( ( environment : string ) => ( {
105+ prefix : environment ,
106+ action : async ( stdout : Writable , stderr : Writable , _signal ) => {
107+ const environmentConfig = await loadEnvironment ( environment , 'shopify.theme.toml' , { from : flags . path } )
108+ const environmentFlags = {
109+ ...flags ,
110+ ...environmentConfig ,
111+ environment : [ environment ] ,
112+ }
113+
114+ if ( ! this . validConfig ( environmentConfig as FlagValues , requiredFlags , environment ) ) return
115+
116+ const session = sessions [ environment ]
117+
118+ if ( ! session ) {
119+ throw new AbortError ( `No session found for environment ${ environment } ` )
120+ }
121+
122+ await this . command ( environmentFlags , session , { stdout, stderr} )
123+ } ,
124+ } ) ) ,
125+ abortSignal : abortController . signal ,
126+ showTimestamps : true ,
127+ } )
97128 }
98129
99130 private async ensureAuthenticated ( flags : FlagValues ) {
0 commit comments