Skip to content

Commit 841bc03

Browse files
authored
refactor(cli): hotswap is now a deployment method (#519)
Follow-up from #517 to make the same changes to the CLI. This has no user impact. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 2b92bd5 commit 841bc03

File tree

3 files changed

+132
-117
lines changed

3 files changed

+132
-117
lines changed

packages/aws-cdk/lib/cli/cdk-toolkit.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import type { BootstrapEnvironmentOptions } from '../api/bootstrap';
2020
import { Bootstrapper } from '../api/bootstrap';
2121
import { ExtendedStackSelection, StackCollection } from '../api/cloud-assembly';
2222
import type { Deployments, SuccessfulDeployStackResult } from '../api/deployments';
23-
import { EcsHotswapProperties, HotswapMode, HotswapPropertyOverrides } from '../api/hotswap';
2423
import { type Tag, tagsForStack } from '../api/tags';
2524
import { StackActivityProgress } from '../commands/deploy';
2625
import { listStacks } from '../commands/list-stacks';
@@ -374,23 +373,13 @@ export class CdkToolkit {
374373

375374
const parameterMap = buildParameterMap(options.parameters);
376375

377-
if (options.hotswap !== HotswapMode.FULL_DEPLOYMENT) {
376+
if (options.deploymentMethod?.method === 'hotswap') {
378377
warning(
379378
'⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments',
380379
);
381380
warning('⚠️ They should only be used for development - never use them for your production Stacks!\n');
382381
}
383382

384-
let hotswapPropertiesFromSettings = this.props.configuration.settings.get(['hotswap']) || {};
385-
386-
let hotswapPropertyOverrides = new HotswapPropertyOverrides(
387-
new EcsHotswapProperties(
388-
hotswapPropertiesFromSettings.ecs?.minimumHealthyPercent,
389-
hotswapPropertiesFromSettings.ecs?.maximumHealthyPercent,
390-
hotswapPropertiesFromSettings.ecs?.stabilizationTimeoutSeconds,
391-
),
392-
);
393-
394383
const stacks = stackCollection.stackArtifacts;
395384

396385
const stackOutputs: { [key: string]: any } = {};
@@ -518,8 +507,6 @@ export class CdkToolkit {
518507
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
519508
usePreviousParameters: options.usePreviousParameters,
520509
rollback,
521-
hotswap: options.hotswap,
522-
hotswapPropertyOverrides: hotswapPropertyOverrides,
523510
extraUserAgent: options.extraUserAgent,
524511
assetParallelism: options.assetParallelism,
525512
ignoreNoStacks: options.ignoreNoStacks,
@@ -1403,8 +1390,7 @@ export class CdkToolkit {
14031390
watch: false,
14041391
cloudWatchLogMonitor,
14051392
cacheCloudAssembly: false,
1406-
hotswap: options.hotswap,
1407-
extraUserAgent: `cdk-watch/hotswap-${options.hotswap !== HotswapMode.FALL_BACK ? 'on' : 'off'}`,
1393+
extraUserAgent: `cdk-watch/hotswap-${options.deploymentMethod?.method === 'hotswap' ? 'on' : 'off'}`,
14081394
concurrency: options.concurrency,
14091395
};
14101396

@@ -1603,15 +1589,6 @@ interface WatchOptions extends Omit<CfnDeployOptions, 'execute'> {
16031589
*/
16041590
force?: boolean;
16051591

1606-
/**
1607-
* Whether to perform a 'hotswap' deployment.
1608-
* A 'hotswap' deployment will attempt to short-circuit CloudFormation
1609-
* and update the affected resources like Lambda functions directly.
1610-
*
1611-
* @default - `HotswapMode.FALL_BACK` for regular deployments, `HotswapMode.HOTSWAP_ONLY` for 'watch' deployments
1612-
*/
1613-
readonly hotswap: HotswapMode;
1614-
16151592
/**
16161593
* The extra string to append to the User-Agent header when performing AWS SDK calls.
16171594
*

packages/aws-cdk/lib/cli/cli.ts

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-shadow */ // yargs
22
import * as cxapi from '@aws-cdk/cx-api';
3-
import type { DeploymentMethod } from '@aws-cdk/toolkit-lib';
3+
import type { ChangeSetDeployment, DeploymentMethod, DirectDeployment } from '@aws-cdk/toolkit-lib';
44
import { ToolkitError } from '@aws-cdk/toolkit-lib';
55
import * as chalk from 'chalk';
66
import { CdkToolkit, AssetBuildTime } from './cdk-toolkit';
@@ -322,43 +322,6 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
322322
throw new ToolkitError('Can not supply both --[no-]execute and --method at the same time');
323323
}
324324

325-
let deploymentMethod: DeploymentMethod | undefined;
326-
switch (args.method) {
327-
case 'direct':
328-
if (args.changeSetName) {
329-
throw new ToolkitError('--change-set-name cannot be used with method=direct');
330-
}
331-
if (args.importExistingResources) {
332-
throw new ToolkitError('--import-existing-resources cannot be enabled with method=direct');
333-
}
334-
deploymentMethod = { method: 'direct' };
335-
break;
336-
case 'change-set':
337-
deploymentMethod = {
338-
method: 'change-set',
339-
execute: true,
340-
changeSetName: args.changeSetName,
341-
importExistingResources: args.importExistingResources,
342-
};
343-
break;
344-
case 'prepare-change-set':
345-
deploymentMethod = {
346-
method: 'change-set',
347-
execute: false,
348-
changeSetName: args.changeSetName,
349-
importExistingResources: args.importExistingResources,
350-
};
351-
break;
352-
case undefined:
353-
deploymentMethod = {
354-
method: 'change-set',
355-
execute: args.execute ?? true,
356-
changeSetName: args.changeSetName,
357-
importExistingResources: args.importExistingResources,
358-
};
359-
break;
360-
}
361-
362325
return cli.deploy({
363326
selector,
364327
exclusively: args.exclusively,
@@ -368,15 +331,14 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
368331
requireApproval: configuration.settings.get(['requireApproval']),
369332
reuseAssets: args['build-exclude'],
370333
tags: configuration.settings.get(['tags']),
371-
deploymentMethod,
334+
deploymentMethod: determineDeploymentMethod(args, configuration),
372335
force: args.force,
373336
parameters: parameterMap,
374337
usePreviousParameters: args['previous-parameters'],
375338
outputsFile: configuration.settings.get(['outputsFile']),
376339
progress: configuration.settings.get(['progress']),
377340
ci: args.ci,
378341
rollback: configuration.settings.get(['rollback']),
379-
hotswap: determineHotswapMode(args.hotswap, args.hotswapFallback),
380342
watch: args.watch,
381343
traceLogs: args.logs,
382344
concurrency: args.concurrency,
@@ -424,14 +386,10 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
424386
toolkitStackName,
425387
roleArn: args.roleArn,
426388
reuseAssets: args['build-exclude'],
427-
deploymentMethod: {
428-
method: 'change-set',
429-
changeSetName: args.changeSetName,
430-
},
389+
deploymentMethod: determineDeploymentMethod(args, configuration, true),
431390
force: args.force,
432391
progress: configuration.settings.get(['progress']),
433392
rollback: configuration.settings.get(['rollback']),
434-
hotswap: determineHotswapMode(args.hotswap, args.hotswapFallback, true),
435393
traceLogs: args.logs,
436394
concurrency: args.concurrency,
437395
});
@@ -565,6 +523,65 @@ function arrayFromYargs(xs: string[]): string[] | undefined {
565523
return xs.filter((x) => x !== '');
566524
}
567525

526+
function determineDeploymentMethod(args: any, configuration: Configuration, watch?: boolean): DeploymentMethod {
527+
let deploymentMethod: ChangeSetDeployment | DirectDeployment | undefined;
528+
switch (args.method) {
529+
case 'direct':
530+
if (args.changeSetName) {
531+
throw new ToolkitError('--change-set-name cannot be used with method=direct');
532+
}
533+
if (args.importExistingResources) {
534+
throw new ToolkitError('--import-existing-resources cannot be enabled with method=direct');
535+
}
536+
deploymentMethod = { method: 'direct' };
537+
break;
538+
case 'change-set':
539+
deploymentMethod = {
540+
method: 'change-set',
541+
execute: true,
542+
changeSetName: args.changeSetName,
543+
importExistingResources: args.importExistingResources,
544+
};
545+
break;
546+
case 'prepare-change-set':
547+
deploymentMethod = {
548+
method: 'change-set',
549+
execute: false,
550+
changeSetName: args.changeSetName,
551+
importExistingResources: args.importExistingResources,
552+
};
553+
break;
554+
case undefined:
555+
default:
556+
deploymentMethod = {
557+
method: 'change-set',
558+
execute: watch ? true : args.execute ?? true,
559+
changeSetName: args.changeSetName,
560+
importExistingResources: args.importExistingResources,
561+
};
562+
break;
563+
}
564+
565+
const hotswapMode = determineHotswapMode(args.hotswap, args.hotswapFallback, watch);
566+
const hotswapProperties = configuration.settings.get(['hotswap']) || {};
567+
switch (hotswapMode) {
568+
case HotswapMode.FALL_BACK:
569+
return {
570+
method: 'hotswap',
571+
properties: hotswapProperties,
572+
fallback: deploymentMethod,
573+
};
574+
case HotswapMode.HOTSWAP_ONLY:
575+
return {
576+
method: 'hotswap',
577+
properties: hotswapProperties,
578+
};
579+
default:
580+
case HotswapMode.FULL_DEPLOYMENT:
581+
return deploymentMethod;
582+
}
583+
}
584+
568585
function determineHotswapMode(hotswap?: boolean, hotswapFallback?: boolean, watch?: boolean): HotswapMode {
569586
if (hotswap && hotswapFallback) {
570587
throw new ToolkitError('Can not supply both --hotswap and --hotswap-fallback at the same time');

0 commit comments

Comments
 (0)