diff --git a/packages/cli-core/src/abstractions/features/Command.ts b/packages/cli-core/src/abstractions/features/Command.ts index 02cc742e5b..d592f12a9a 100644 --- a/packages/cli-core/src/abstractions/features/Command.ts +++ b/packages/cli-core/src/abstractions/features/Command.ts @@ -5,6 +5,7 @@ export interface ICommandParamDefinition { description: string; type: "boolean" | "number" | "string"; required?: boolean; + array?: boolean; default?: any; validation?: (value: TCommandParams) => boolean | string; } diff --git a/packages/cli-core/src/features/DeployCommand/DeployCommand.ts b/packages/cli-core/src/features/DeployCommand/DeployCommand.ts index ffe928e216..cba7b31dc5 100644 --- a/packages/cli-core/src/features/DeployCommand/DeployCommand.ts +++ b/packages/cli-core/src/features/DeployCommand/DeployCommand.ts @@ -10,21 +10,26 @@ import open from "open"; // TODO: convert to a real service. import { PrintInfoForEnv } from "~/features/InfoCommand/PrintInfoForEnv.js"; -export interface IDeployNoAppParams { +export interface IDeployCommandParams { + apps?: AppName[]; variant?: string; region?: string; env: string; deploymentLogs?: boolean; + build?: boolean; + preview?: boolean; } -export interface IDeployWithAppParams extends IDeployNoAppParams { +export interface IDeploySingleAppParams { app: AppName; + variant?: string; + region?: string; + env: string; + deploymentLogs?: boolean; build?: boolean; preview?: boolean; } -export type IDeployCommandParams = IDeployNoAppParams | IDeployWithAppParams; - const sleep = (ms: number = 1500) => setTimeout(ms); export class DeployCommand implements Command.Interface { @@ -43,15 +48,18 @@ export class DeployCommand implements Command.Interface { description: "Deploys specified app or all apps in the project", examples: [ "$0 deploy api --env dev", + "$0 deploy core api --env dev", "$0 deploy admin --env prod", "$0 deploy --env prod", "$0 deploy" ], params: [ { - name: "app", - description: "Name of the app (core, admin, or api)", - type: "string" + name: "apps", + description: + "Name of the app(s) to deploy (core, admin, or api). You can specify multiple apps.", + type: "string", + array: true } ], options: [ @@ -61,7 +69,7 @@ export class DeployCommand implements Command.Interface { type: "string", default: "dev", validation: params => { - if ("app" in params && !params.env) { + if (params.apps && params.apps.length > 0 && !params.env) { throw new Error("Environment name is required when deploying an app."); } return true; @@ -111,8 +119,17 @@ export class DeployCommand implements Command.Interface { } ], handler: async (params: IDeployCommandParams) => { - if ("app" in params) { - await this.deployApp(params); + if (params.apps && params.apps.length > 0) { + // Deploy specified apps + for (const app of params.apps) { + const appParams: IDeploySingleAppParams = { + ...params, + app + }; + ui.info("Deploying %s app...", app.charAt(0).toUpperCase() + app.slice(1)); + await this.deployApp(appParams); + ui.newLine(); + } } else { const isCi = projectSdk.isCi(); const coreStack = await projectSdk.getAppStackOutput({ @@ -195,7 +212,7 @@ export class DeployCommand implements Command.Interface { }; } - private async deployApp(params: IDeployWithAppParams) { + private async deployApp(params: IDeploySingleAppParams) { const projectSdk = await this.getProjectSdkService.execute(); const ui = this.uiService; diff --git a/packages/cli-core/src/features/DeployCommand/deployOutputs/BaseDeployOutput.ts b/packages/cli-core/src/features/DeployCommand/deployOutputs/BaseDeployOutput.ts index d49bfa104d..3e1ba7e7c7 100644 --- a/packages/cli-core/src/features/DeployCommand/deployOutputs/BaseDeployOutput.ts +++ b/packages/cli-core/src/features/DeployCommand/deployOutputs/BaseDeployOutput.ts @@ -1,5 +1,5 @@ import { UiService, StdioService } from "~/abstractions/index.js"; -import { IDeployWithAppParams } from "../DeployCommand.js"; +import { IDeploySingleAppParams } from "../DeployCommand.js"; import { ExecaChildProcess } from "execa"; export type IDeployProcess = ExecaChildProcess; @@ -9,7 +9,7 @@ export interface IBaseDeployOutputParams { stdio: StdioService.Interface; ui: UiService.Interface; showDeploymentLogs: boolean; - deployParams: IDeployWithAppParams; + deployParams: IDeploySingleAppParams; } export class BaseDeployOutput { @@ -17,7 +17,7 @@ export class BaseDeployOutput { public readonly stdio: StdioService.Interface; public readonly ui: UiService.Interface; public readonly showDeploymentLogs: boolean; - public readonly deployParams: IDeployWithAppParams; + public readonly deployParams: IDeploySingleAppParams; public constructor({ deployProcess, diff --git a/packages/cli-core/src/services/GetCliRunnerService/GetCliRunnerService.ts b/packages/cli-core/src/services/GetCliRunnerService/GetCliRunnerService.ts index 7b743ae267..34c97fbaa3 100644 --- a/packages/cli-core/src/services/GetCliRunnerService/GetCliRunnerService.ts +++ b/packages/cli-core/src/services/GetCliRunnerService/GetCliRunnerService.ts @@ -126,7 +126,8 @@ export class DefaultGetCliRunnerService implements GetCliRunnerService.Interface " " + params .map(param => { - return param.required ? `<${param.name}>` : `[${param.name}]`; + const paramName = param.array ? `${param.name}..` : param.name; + return param.required ? `<${paramName}>` : `[${paramName}]`; }) .join(" "); } @@ -136,10 +137,11 @@ export class DefaultGetCliRunnerService implements GetCliRunnerService.Interface description, yargs => { params.forEach((param: Command.ParamDefinition) => { - const { name, required, validation, ...rest } = param; + const { name, required, validation, array, ...rest } = param; const yargsParam = yargs.positional(name, { ...rest, + ...(array && { array: true }), demandOption: required }); diff --git a/webiny.config.tsx b/webiny.config.tsx index 780fa52f9b..e7d57280ac 100644 --- a/webiny.config.tsx +++ b/webiny.config.tsx @@ -15,10 +15,10 @@ export default () => { Core, API, and Admin Pulumi apps that we deploy by default. */} - - - - + {/**/} + {/**/} + {/**/} + {/**/}