@@ -26,14 +26,14 @@ import {
2626} from './cfn-api' ;
2727import { determineAllowCrossAccountAssetPublishing } from './checks' ;
2828import type { DeployStackResult , SuccessfulDeployStackResult } from './deployment-result' ;
29- import type { ChangeSetDeploymentMethod , DeploymentMethod } from '../../actions/deploy' ;
29+ import type { ChangeSetDeployment , DeploymentMethod , DirectDeployment } from '../../actions/deploy' ;
3030import { ToolkitError } from '../../toolkit/toolkit-error' ;
3131import { formatErrorMessage } from '../../util' ;
3232import type { SDK , SdkProvider , ICloudFormationClient } from '../aws-auth/private' ;
3333import type { TemplateBodyParameter } from '../cloudformation' ;
3434import { makeBodyParameter , CfnEvaluationException , CloudFormationStack } from '../cloudformation' ;
3535import type { EnvironmentResources , StringWithoutPlaceholders } from '../environment' ;
36- import { HotswapMode , HotswapPropertyOverrides , ICON } from '../hotswap/common' ;
36+ import { HotswapPropertyOverrides , HotswapMode , ICON , createHotswapPropertyOverrides } from '../hotswap/common' ;
3737import { tryHotswapDeployment } from '../hotswap/hotswap-deployments' ;
3838import { IO , type IoHelper } from '../io/private' ;
3939import type { ResourcesToImport } from '../resource-import' ;
@@ -158,17 +158,21 @@ export interface DeployStackOptions {
158158 */
159159 readonly rollback ?: boolean ;
160160
161- /*
161+ /**
162162 * Whether to perform a 'hotswap' deployment.
163163 * A 'hotswap' deployment will attempt to short-circuit CloudFormation
164164 * and update the affected resources like Lambda functions directly.
165165 *
166166 * @default - `HotswapMode.FULL_DEPLOYMENT` for regular deployments, `HotswapMode.HOTSWAP_ONLY` for 'watch' deployments
167+ *
168+ * @deprecated Use 'deploymentMethod' instead
167169 */
168170 readonly hotswap ?: HotswapMode ;
169171
170172 /**
171173 * Extra properties that configure hotswap behavior
174+ *
175+ * @deprecated Use 'deploymentMethod' instead
172176 */
173177 readonly hotswapPropertyOverrides ?: HotswapPropertyOverrides ;
174178
@@ -202,9 +206,31 @@ export interface DeployStackOptions {
202206
203207export async function deployStack ( options : DeployStackOptions , ioHelper : IoHelper ) : Promise < DeployStackResult > {
204208 const stackArtifact = options . stack ;
205-
206209 const stackEnv = options . resolvedEnvironment ;
207210
211+ let deploymentMethod = options . deploymentMethod ?? { method : 'change-set' } ;
212+ // Honour old hotswap option
213+ // @TODO remove when we don't care about this export anymore
214+ if ( options . hotswap && deploymentMethod ?. method !== 'hotswap' ) {
215+ switch ( options . hotswap ) {
216+ case HotswapMode . HOTSWAP_ONLY :
217+ deploymentMethod = {
218+ method : 'hotswap' ,
219+ properties : options . hotswapPropertyOverrides ,
220+ } ;
221+ break ;
222+ case HotswapMode . FALL_BACK :
223+ deploymentMethod = {
224+ method : 'hotswap' ,
225+ properties : options . hotswapPropertyOverrides ,
226+ fallback : deploymentMethod ,
227+ } ;
228+ break ;
229+ case HotswapMode . FULL_DEPLOYMENT :
230+ break ;
231+ }
232+ }
233+
208234 options . sdk . appendCustomUserAgent ( options . extraUserAgent ) ;
209235 const cfn = options . sdk . cloudFormation ( ) ;
210236 const deployName = options . deployName || stackArtifact . stackName ;
@@ -246,14 +272,11 @@ export async function deployStack(options: DeployStackOptions, ioHelper: IoHelpe
246272 ? templateParams . updateExisting ( finalParameterValues , cloudFormationStack . parameters )
247273 : templateParams . supplyAll ( finalParameterValues ) ;
248274
249- const hotswapMode = options . hotswap ?? HotswapMode . FULL_DEPLOYMENT ;
250- const hotswapPropertyOverrides = options . hotswapPropertyOverrides ?? new HotswapPropertyOverrides ( ) ;
251-
252275 if ( await canSkipDeploy ( options , cloudFormationStack , stackParams . hasChanges ( cloudFormationStack . parameters ) , ioHelper ) ) {
253276 await ioHelper . notify ( IO . DEFAULT_TOOLKIT_DEBUG . msg ( `${ deployName } : skipping deployment (use --force to override)` ) ) ;
254277 // if we can skip deployment and we are performing a hotswap, let the user know
255278 // that no hotswap deployment happened
256- if ( hotswapMode !== HotswapMode . FULL_DEPLOYMENT ) {
279+ if ( deploymentMethod ?. method === 'hotswap' ) {
257280 await ioHelper . notify ( IO . DEFAULT_TOOLKIT_INFO . msg (
258281 format (
259282 `\n ${ ICON } %s\n` ,
@@ -290,16 +313,21 @@ export async function deployStack(options: DeployStackOptions, ioHelper: IoHelpe
290313 allowCrossAccount : await determineAllowCrossAccountAssetPublishing ( options . sdk , ioHelper , bootstrapStackName ) ,
291314 } , ioHelper ) ;
292315
293- if ( hotswapMode !== HotswapMode . FULL_DEPLOYMENT ) {
294- // attempt to short-circuit the deployment if possible
316+ // attempt to short-circuit the deployment if possible
317+ if ( deploymentMethod ?. method === 'hotswap' ) {
295318 try {
319+ const hotswapModeNew = deploymentMethod ?. fallback ? 'fall-back' : 'hotswap-only' ;
320+ const hotswapPropertyOverrides = deploymentMethod . properties
321+ ? createHotswapPropertyOverrides ( deploymentMethod . properties )
322+ : new HotswapPropertyOverrides ( ) ;
323+
296324 const hotswapDeploymentResult = await tryHotswapDeployment (
297325 options . sdkProvider ,
298326 ioHelper ,
299327 stackParams . values ,
300328 cloudFormationStack ,
301329 stackArtifact ,
302- hotswapMode ,
330+ hotswapModeNew ,
303331 hotswapPropertyOverrides ,
304332 ) ;
305333
@@ -321,9 +349,10 @@ export async function deployStack(options: DeployStackOptions, ioHelper: IoHelpe
321349 ) ) ) ;
322350 }
323351
324- if ( hotswapMode === HotswapMode . FALL_BACK ) {
352+ if ( deploymentMethod . fallback ) {
325353 await ioHelper . notify ( IO . DEFAULT_TOOLKIT_INFO . msg ( 'Falling back to doing a full deployment' ) ) ;
326354 options . sdk . appendCustomUserAgent ( 'cdk-hotswap/fallback' ) ;
355+ deploymentMethod = deploymentMethod . fallback ;
327356 } else {
328357 return {
329358 type : 'did-deploy-stack' ,
@@ -336,6 +365,7 @@ export async function deployStack(options: DeployStackOptions, ioHelper: IoHelpe
336365
337366 // could not short-circuit the deployment, perform a full CFN deploy instead
338367 const fullDeployment = new FullCloudFormationDeployment (
368+ deploymentMethod ,
339369 options ,
340370 cloudFormationStack ,
341371 stackArtifact ,
@@ -364,6 +394,7 @@ class FullCloudFormationDeployment {
364394 private readonly uuid : string ;
365395
366396 constructor (
397+ private readonly deploymentMethod : DirectDeployment | ChangeSetDeployment ,
367398 private readonly options : DeployStackOptions ,
368399 private readonly cloudFormationStack : CloudFormationStack ,
369400 private readonly stackArtifact : cxapi . CloudFormationStackArtifact ,
@@ -380,9 +411,7 @@ class FullCloudFormationDeployment {
380411 }
381412
382413 public async performDeployment ( ) : Promise < DeployStackResult > {
383- const deploymentMethod = this . options . deploymentMethod ?? {
384- method : 'change-set' ,
385- } ;
414+ const deploymentMethod = this . deploymentMethod ?? { method : 'change-set' } ;
386415
387416 if ( deploymentMethod . method === 'direct' && this . options . resourcesToImport ) {
388417 throw new ToolkitError ( 'Importing resources requires a changeset deployment' ) ;
@@ -397,7 +426,7 @@ class FullCloudFormationDeployment {
397426 }
398427 }
399428
400- private async changeSetDeployment ( deploymentMethod : ChangeSetDeploymentMethod ) : Promise < DeployStackResult > {
429+ private async changeSetDeployment ( deploymentMethod : ChangeSetDeployment ) : Promise < DeployStackResult > {
401430 const changeSetName = deploymentMethod . changeSetName ?? 'cdk-deploy-change-set' ;
402431 const execute = deploymentMethod . execute ?? true ;
403432 const importExistingResources = deploymentMethod . importExistingResources ?? false ;
0 commit comments