Skip to content

Commit e828c22

Browse files
authored
feat(cli): add message when resource is hotswapped (#18058)
Add additional messages to indicate that a hotswap deployment is occurring (or not) along with what resources are being hotswapped. fix #17778 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e4485f4 commit e828c22

7 files changed

+33
-2
lines changed

packages/aws-cdk/lib/api/deploy-stack.ts

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { publishAssets } from '../util/asset-publishing';
1010
import { contentHash } from '../util/content-hash';
1111
import { ISDK, SdkProvider } from './aws-auth';
1212
import { tryHotswapDeployment } from './hotswap-deployments';
13+
import { ICON } from './hotswap/common';
1314
import { CfnEvaluationException } from './hotswap/evaluate-cloudformation-template';
1415
import { ToolkitInfo } from './toolkit-info';
1516
import {
@@ -231,6 +232,11 @@ export async function deployStack(options: DeployStackOptions): Promise<DeploySt
231232

232233
if (await canSkipDeploy(options, cloudFormationStack, stackParams.hasChanges(cloudFormationStack.parameters))) {
233234
debug(`${deployName}: skipping deployment (use --force to override)`);
235+
// if we can skip deployment and we are performing a hotswap, let the user know
236+
// that no hotswap deployment happened
237+
if (options.hotswap) {
238+
print(`\n ${ICON} %s\n`, colors.bold('hotswap deployment skipped - no changes were detected (use --force to override)'));
239+
}
234240
return {
235241
noOp: true,
236242
outputs: cloudFormationStack.outputs,

packages/aws-cdk/lib/api/hotswap-deployments.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as cfn_diff from '@aws-cdk/cloudformation-diff';
22
import * as cxapi from '@aws-cdk/cx-api';
33
import { CloudFormation } from 'aws-sdk';
4+
import * as colors from 'colors/safe';
5+
import { print } from '../logging';
46
import { ISDK, Mode, SdkProvider } from './aws-auth';
57
import { DeployStackResult } from './deploy-stack';
6-
import { ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, HotswappableChangeCandidate, ListStackResources } from './hotswap/common';
8+
import { ICON, ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, HotswappableChangeCandidate, ListStackResources } from './hotswap/common';
79
import { isHotswappableEcsServiceChange } from './hotswap/ecs-services';
810
import { EvaluateCloudFormationTemplate } from './hotswap/evaluate-cloudformation-template';
911
import { isHotswappableLambdaFunctionChange } from './hotswap/lambda-functions';
@@ -139,6 +141,7 @@ export function isCandidateForHotswapping(change: cfn_diff.ResourceDifference):
139141
async function applyAllHotswappableChanges(
140142
sdk: ISDK, hotswappableChanges: HotswapOperation[],
141143
): Promise<void[]> {
144+
print(`\n${ICON} hotswapping resources:`);
142145
return Promise.all(hotswappableChanges.map(hotswapOperation => {
143146
return applyHotswappableChange(sdk, hotswapOperation);
144147
}));
@@ -150,8 +153,14 @@ async function applyHotswappableChange(sdk: ISDK, hotswapOperation: HotswapOpera
150153
sdk.appendCustomUserAgent(customUserAgent);
151154

152155
try {
156+
for (const name of hotswapOperation.resourceNames) {
157+
print(` ${ICON} hotswapping ${hotswapOperation.service}: %s`, colors.bold(name));
158+
}
153159
return await hotswapOperation.apply(sdk);
154160
} finally {
161+
for (const name of hotswapOperation.resourceNames) {
162+
print(`${ICON} ${hotswapOperation.service}: %s %s`, colors.bold(name), colors.green('hotswapped!'));
163+
}
155164
sdk.removeCustomUserAgent(customUserAgent);
156165
}
157166
}

packages/aws-cdk/lib/api/hotswap/common.ts

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { CloudFormation } from 'aws-sdk';
33
import { ISDK } from '../aws-auth';
44
import { CfnEvaluationException, EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template';
55

6+
export const ICON = '✨';
67
export interface ListStackResources {
78
listStackResources(): Promise<CloudFormation.StackResourceSummary[]>;
89
}
@@ -17,6 +18,11 @@ export interface HotswapOperation {
1718
*/
1819
readonly service: string;
1920

21+
/**
22+
* The names of the resources being hotswapped.
23+
*/
24+
readonly resourceNames: string[];
25+
2026
apply(sdk: ISDK): Promise<any>;
2127
}
2228

packages/aws-cdk/lib/api/hotswap/ecs-services.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,14 @@ interface EcsService {
7777

7878
class EcsServiceHotswapOperation implements HotswapOperation {
7979
public readonly service = 'ecs-service';
80+
public readonly resourceNames: string[] = [];
8081

8182
constructor(
8283
private readonly taskDefinitionResource: any,
8384
private readonly servicesReferencingTaskDef: EcsService[],
84-
) {}
85+
) {
86+
this.resourceNames = servicesReferencingTaskDef.map(ecsService => ecsService.serviceArn.split('/')[2]);
87+
}
8588

8689
public async apply(sdk: ISDK): Promise<any> {
8790
// Step 1 - update the changed TaskDefinition, creating a new TaskDefinition Revision

packages/aws-cdk/lib/api/hotswap/lambda-functions.ts

+2
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,10 @@ interface LambdaFunctionResource {
153153

154154
class LambdaFunctionHotswapOperation implements HotswapOperation {
155155
public readonly service = 'lambda-function';
156+
public readonly resourceNames: string[];
156157

157158
constructor(private readonly lambdaFunctionResource: LambdaFunctionResource) {
159+
this.resourceNames = [lambdaFunctionResource.physicalName];
158160
}
159161

160162
public async apply(sdk: ISDK): Promise<any> {

packages/aws-cdk/lib/api/hotswap/s3-bucket-deployments.ts

+3
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ export async function isHotswappableS3BucketDeploymentChange(
3737

3838
class S3BucketDeploymentHotswapOperation implements HotswapOperation {
3939
public readonly service = 'custom-s3-deployment';
40+
public readonly resourceNames: string[];
4041

4142
constructor(private readonly functionName: string, private readonly customResourceProperties: any) {
43+
this.resourceNames = [this.customResourceProperties.DestinationBucketName];
4244
}
4345

4446
public async apply(sdk: ISDK): Promise<any> {
@@ -116,6 +118,7 @@ function stringifyObject(obj: any): any {
116118

117119
class EmptyHotswapOperation implements HotswapOperation {
118120
readonly service = 'empty';
121+
public readonly resourceNames = [];
119122
public async apply(sdk: ISDK): Promise<any> {
120123
return Promise.resolve(sdk);
121124
}

packages/aws-cdk/lib/api/hotswap/stepfunctions-state-machines.ts

+2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ interface StateMachineResource {
5454

5555
class StateMachineHotswapOperation implements HotswapOperation {
5656
public readonly service = 'stepfunctions-state-machine';
57+
public readonly resourceNames: string[];
5758

5859
constructor(private readonly stepFunctionResource: StateMachineResource) {
60+
this.resourceNames = [this.stepFunctionResource.stateMachineArn.split(':')[6]];
5961
}
6062

6163
public async apply(sdk: ISDK): Promise<any> {

0 commit comments

Comments
 (0)