Skip to content

Commit 019afa8

Browse files
committed
fix(toolkit-lib): replace force from DeployOptions with more targeted options
- Rename `force` option to more specific names based on functionality: - `forceDeployment`: Deploy even if templates are identical - `forceAssetPublishing`: Force asset publishing even if assets haven't changed - `orphanFailedResourcesDuringRollback`: Automatically orphan resources during rollback - Rename helper function `removePublishedAssets` to more descriptive `removePublishedAssetsFromWorkGraph` - Update related code paths in toolkit.ts, deploy-stack.ts, deployments.ts and deploy-bootstrap.ts to use the new parameter names - Remove deprecated comment as options are now properly split BREAKING CHANGE: The deprecated `force` option on `DeployOptions` has been removed. This option previously caused multiple different "force" actions. Each action now has a more targeted alternative. To force a deployment even if the CDK Toolkit has not detected any changes, use `forceDeployment`. To force re-publishing of previously published assets, use `forceAssetPublishing`. To force failing resource being orphaned during a rollback, use `orphanFailedResourcesDuringRollback`. To skip confirmation of deployment in bla
1 parent 3e8359c commit 019afa8

File tree

9 files changed

+54
-49
lines changed

9 files changed

+54
-49
lines changed

packages/@aws-cdk/toolkit-lib/lib/actions/deploy/private/deploy-options.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ export interface BaseDeployOptions {
1616
readonly roleArn?: string;
1717

1818
/**
19-
* Always deploy, even if templates are identical.
19+
* Deploy even if the deployed template is identical to the one we are about to deploy.
2020
*
2121
* @default false
22-
* @deprecated the options currently covers multiple different functionalities and will be split out in future
2322
*/
24-
readonly force?: boolean;
23+
readonly forceDeployment?: boolean;
2524

2625
/**
2726
* Deployment method
@@ -44,6 +43,21 @@ export interface BaseDeployOptions {
4443
*/
4544
readonly rollback?: boolean;
4645

46+
/**
47+
* Automatically orphan resources that failed during rollback
48+
*
49+
* Has no effect if `rollback` is `false`.
50+
*
51+
* @default false
52+
*/
53+
readonly orphanFailedResourcesDuringRollback?: boolean;
54+
55+
/**
56+
* Force asset publishing even if the assets have not changed
57+
* @default false
58+
*/
59+
readonly forceAssetPublishing?: boolean;
60+
4761
/**
4862
* Reuse the assets with the given asset IDs
4963
*/

packages/@aws-cdk/toolkit-lib/lib/actions/deploy/private/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function buildParameterMap(parameters?: Map<string, string | undefined>):
2727
/**
2828
* Remove the asset publishing and building from the work graph for assets that are already in place
2929
*/
30-
export async function removePublishedAssets(graph: WorkGraph, deployments: Deployments, options: DeployOptions) {
30+
export async function removePublishedAssetsFromWorkGraph(graph: WorkGraph, deployments: Deployments, options: DeployOptions) {
3131
await graph.removeUnnecessaryAssets(assetNode => deployments.isSingleAssetPublished(assetNode.assetManifest, assetNode.asset, {
3232
stack: assetNode.parentStack,
3333
roleArn: options.roleArn,

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

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { assemblyFromSource } from './private';
99
import type { BootstrapEnvironments, BootstrapOptions, BootstrapResult, EnvironmentBootstrapResult } from '../actions/bootstrap';
1010
import { BootstrapSource } from '../actions/bootstrap';
1111
import { AssetBuildTime, type DeployOptions } from '../actions/deploy';
12-
import { type ExtendedDeployOptions, buildParameterMap, createHotswapPropertyOverrides, removePublishedAssets } from '../actions/deploy/private';
12+
import { type ExtendedDeployOptions, buildParameterMap, createHotswapPropertyOverrides, removePublishedAssetsFromWorkGraph } from '../actions/deploy/private';
1313
import { type DestroyOptions } from '../actions/destroy';
1414
import type { ChangeSetDiffOptions, DiffOptions, LocalFileDiffOptions } from '../actions/diff';
1515
import { DiffMethod } from '../actions/diff';
@@ -487,7 +487,7 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
487487
stack: assetNode.parentStack,
488488
roleArn: options.roleArn,
489489
stackName: assetNode.parentStack.stackName,
490-
forcePublish: options.force,
490+
forcePublish: options.forceAssetPublishing,
491491
});
492492
await publishAssetSpan.end();
493493
};
@@ -584,7 +584,7 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
584584
notificationArns,
585585
tags,
586586
deploymentMethod: options.deploymentMethod,
587-
force: options.force,
587+
forceDeployment: options.forceDeployment,
588588
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
589589
usePreviousParameters: options.parameters?.keepExistingParameters,
590590
rollback,
@@ -605,22 +605,18 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
605605
: `Stack is in a paused fail state (${r.status}) and command line arguments do not include "--no-rollback"`;
606606
const question = `${motivation}. Perform a regular deployment`;
607607

608-
if (options.force) {
609-
await ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg(`${motivation}. Rolling back first (--force).`));
610-
} else {
611-
const confirmed = await ioHelper.requestResponse(IO.CDK_TOOLKIT_I5050.req(question, {
612-
motivation,
613-
concurrency,
614-
}));
615-
if (!confirmed) {
616-
throw new ToolkitError('Aborted by user');
617-
}
608+
const confirmed = await ioHelper.requestResponse(IO.CDK_TOOLKIT_I5050.req(question, {
609+
motivation,
610+
concurrency,
611+
}));
612+
if (!confirmed) {
613+
throw new ToolkitError('Aborted by user');
618614
}
619615

620616
// Perform a rollback
621617
await this._rollback(assembly, action, {
622618
stacks: { patterns: [stack.hierarchicalId], strategy: StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE },
623-
orphanFailedResources: options.force,
619+
orphanFailedResources: options.orphanFailedResourcesDuringRollback,
624620
});
625621

626622
// Go around through the 'while' loop again but switch rollback to true.
@@ -632,17 +628,12 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
632628
const motivation = 'Change includes a replacement which cannot be deployed with "--no-rollback"';
633629
const question = `${motivation}. Perform a regular deployment`;
634630

635-
// @todo no force here
636-
if (options.force) {
637-
await ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg(`${motivation}. Proceeding with regular deployment (--force).`));
638-
} else {
639-
const confirmed = await ioHelper.requestResponse(IO.CDK_TOOLKIT_I5050.req(question, {
640-
motivation,
641-
concurrency,
642-
}));
643-
if (!confirmed) {
644-
throw new ToolkitError('Aborted by user');
645-
}
631+
const confirmed = await ioHelper.requestResponse(IO.CDK_TOOLKIT_I5050.req(question, {
632+
motivation,
633+
concurrency,
634+
}));
635+
if (!confirmed) {
636+
throw new ToolkitError('Aborted by user');
646637
}
647638

648639
// Go around through the 'while' loop again but switch rollback to true.
@@ -718,8 +709,8 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
718709
const workGraph = new WorkGraphBuilder(ioHelper, prebuildAssets).build(stacksAndTheirAssetManifests);
719710

720711
// Unless we are running with '--force', skip already published assets
721-
if (!options.force) {
722-
await removePublishedAssets(workGraph, deployments, options);
712+
if (!options.forceAssetPublishing) {
713+
await removePublishedAssetsFromWorkGraph(workGraph, deployments, options);
723714
}
724715

725716
const graphConcurrency: Concurrency = {
@@ -892,7 +883,7 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
892883
stack,
893884
roleArn: options.roleArn,
894885
toolkitStackName: this.toolkitStackName,
895-
force: options.orphanFailedResources,
886+
orphanFailedResources: options.orphanFailedResources,
896887
validateBootstrapStackVersion: options.validateBootstrapStackVersion,
897888
orphanLogicalIds: options.orphanLogicalIds,
898889
});

packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface BootstrapEnvironmentOptions {
2121
readonly toolkitStackName?: string;
2222
readonly roleArn?: StringWithoutPlaceholders;
2323
readonly parameters?: BootstrappingParameters;
24-
readonly force?: boolean;
24+
readonly forceDeployment?: boolean;
2525

2626
/**
2727
* The source of the bootstrap stack

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class BootstrapStack {
7676
parameters: Record<string, string | undefined>,
7777
options: Omit<BootstrapEnvironmentOptions, 'parameters'>,
7878
): Promise<SuccessfulDeployStackResult> {
79-
if (this.currentToolkitInfo.found && !options.force) {
79+
if (this.currentToolkitInfo.found && !options.forceDeployment) {
8080
// Safety checks
8181
const abortResponse = {
8282
type: 'did-deploy-stack',
@@ -136,7 +136,7 @@ export class BootstrapStack {
136136
resolvedEnvironment: this.resolvedEnvironment,
137137
sdk: this.sdk,
138138
sdkProvider: this.sdkProvider,
139-
force: options.force,
139+
forceDeployment: options.forceDeployment,
140140
roleArn: options.roleArn,
141141
tags: options.tags,
142142
deploymentMethod: { method: 'change-set', execute: options.execute },

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export interface DeployStackOptions {
149149
* Deploy even if the deployed template is identical to the one we are about to deploy.
150150
* @default false
151151
*/
152-
readonly force?: boolean;
152+
readonly forceDeployment?: boolean;
153153

154154
/**
155155
* Rollback failed deployments
@@ -414,7 +414,7 @@ class FullCloudFormationDeployment {
414414
});
415415
}
416416

417-
if (this.options.force) {
417+
if (this.options.forceDeployment) {
418418
await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_WARN.msg(
419419
[
420420
'You used the --force flag, but CloudFormation reported that the deployment would not make any changes.',
@@ -713,7 +713,7 @@ async function canSkipDeploy(
713713
await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`${deployName}: checking if we can skip deploy`));
714714

715715
// Forced deploy
716-
if (deployStackOptions.force) {
716+
if (deployStackOptions.forceDeployment) {
717717
await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(`${deployName}: forced deployment`));
718718
return false;
719719
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export interface DeployStackOptions {
112112
* Force deployment, even if the deployed template is identical to the one we are about to deploy.
113113
* @default false deployment will be skipped if the template is identical
114114
*/
115-
readonly force?: boolean;
115+
readonly forceDeployment?: boolean;
116116

117117
/**
118118
* Extra parameters for CloudFormation
@@ -219,13 +219,13 @@ export interface RollbackStackOptions {
219219
readonly toolkitStackName?: string;
220220

221221
/**
222-
* Whether to force a rollback or not
222+
* Whether to automatically orphan all failed resources during the rollback
223223
*
224-
* Forcing a rollback will orphan all undeletable resources.
224+
* This will force a rollback that otherwise would have failed.
225225
*
226226
* @default false
227227
*/
228-
readonly force?: boolean;
228+
readonly orphanFailedResources?: boolean;
229229

230230
/**
231231
* Orphan the resources with the given logical IDs
@@ -444,7 +444,7 @@ export class Deployments {
444444
envResources: env.resources,
445445
tags: options.tags,
446446
deploymentMethod,
447-
force: options.force,
447+
forceDeployment: options.forceDeployment,
448448
parameters: options.parameters,
449449
usePreviousParameters: options.usePreviousParameters,
450450
rollback: options.rollback,
@@ -459,7 +459,7 @@ export class Deployments {
459459

460460
public async rollbackStack(options: RollbackStackOptions): Promise<RollbackStackResult> {
461461
let resourcesToSkip: string[] = options.orphanLogicalIds ?? [];
462-
if (options.force && resourcesToSkip.length > 0) {
462+
if (options.orphanFailedResources && resourcesToSkip.length > 0) {
463463
throw new ToolkitError('Cannot combine --force with --orphan');
464464
}
465465

@@ -501,7 +501,7 @@ export class Deployments {
501501
break;
502502

503503
case RollbackChoice.CONTINUE_UPDATE_ROLLBACK:
504-
if (options.force) {
504+
if (options.orphanFailedResources) {
505505
// Find the failed resources from the deployment and automatically skip them
506506
// (Using deployment log because we definitely have `DescribeStackEvents` permissions, and we might not have
507507
// `DescribeStackResources` permissions).
@@ -569,7 +569,7 @@ export class Deployments {
569569
}
570570

571571
// Either we need to ignore some resources to continue the rollback, or something went wrong
572-
if (finalStackState.stackStatus.rollbackChoice === RollbackChoice.CONTINUE_UPDATE_ROLLBACK && options.force) {
572+
if (finalStackState.stackStatus.rollbackChoice === RollbackChoice.CONTINUE_UPDATE_ROLLBACK && options.orphanFailedResources) {
573573
// Do another loop-de-loop
574574
continue;
575575
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ export class CdkToolkit {
487487
execute: options.execute,
488488
changeSetName: options.changeSetName,
489489
deploymentMethod: options.deploymentMethod,
490-
force: options.force,
490+
forceDeployment: options.force,
491491
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
492492
usePreviousParameters: options.usePreviousParameters,
493493
rollback,
@@ -670,7 +670,7 @@ export class CdkToolkit {
670670
stack,
671671
roleArn: options.roleArn,
672672
toolkitStackName: options.toolkitStackName,
673-
force: options.force,
673+
orphanFailedResources: options.force,
674674
validateBootstrapStackVersion: options.validateBootstrapStackVersion,
675675
orphanLogicalIds: options.orphanLogicalIds,
676676
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
295295
return cli.bootstrap(args.ENVIRONMENTS, {
296296
source,
297297
roleArn: args.roleArn,
298-
force: argv.force,
298+
forceDeployment: argv.force,
299299
toolkitStackName: toolkitStackName,
300300
execute: args.execute,
301301
tags: configuration.settings.get(['tags']),

0 commit comments

Comments
 (0)