Skip to content

Commit cd35a1c

Browse files
kaizenccgithub-actions
andauthored
feat(toolkit-lib): diff (#279)
introduces diff support for programmatic toolkit. - has feature parity with the existing CLI diff - programmatic toolkit functionality is unit tested. - AI disclosure: no AI does most of aws/aws-cdk#33182, but typed return will come later --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license --------- Signed-off-by: github-actions <[email protected]> Co-authored-by: github-actions <[email protected]>
1 parent f9f6d1d commit cd35a1c

File tree

18 files changed

+525
-53
lines changed

18 files changed

+525
-53
lines changed

packages/@aws-cdk/tmp-toolkit-helpers/src/api/diff/diff-formatter.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class StringWriteStream extends Writable {
4343
/**
4444
* Output of formatSecurityDiff
4545
*/
46-
export interface FormatSecurityDiffOutput {
46+
interface FormatSecurityDiffOutput {
4747
/**
4848
* Complete formatted security diff, if it is prompt-worthy
4949
*/
@@ -53,7 +53,7 @@ export interface FormatSecurityDiffOutput {
5353
/**
5454
* Output of formatStackDiff
5555
*/
56-
export interface FormatStackDiffOutput {
56+
interface FormatStackDiffOutput {
5757
/**
5858
* Number of stacks with diff changes
5959
*/
@@ -68,7 +68,7 @@ export interface FormatStackDiffOutput {
6868
/**
6969
* Props for the Diff Formatter
7070
*/
71-
export interface DiffFormatterProps {
71+
interface DiffFormatterProps {
7272
/**
7373
* Helper for the IoHost class
7474
*/
@@ -88,7 +88,7 @@ export interface DiffFormatterProps {
8888
/**
8989
* Properties specific to formatting the security diff
9090
*/
91-
export interface FormatSecurityDiffOptions {
91+
interface FormatSecurityDiffOptions {
9292
/**
9393
* The approval level of the security diff
9494
*/
@@ -110,7 +110,7 @@ export interface FormatSecurityDiffOptions {
110110
/**
111111
* PRoperties specific to formatting the stack diff
112112
*/
113-
export interface FormatStackDiffOptions {
113+
interface FormatStackDiffOptions {
114114
/**
115115
* do not filter out AWS::CDK::Metadata or Rules
116116
*
@@ -326,15 +326,15 @@ function diffRequiresApproval(diff: TemplateDiff, requireApproval: RequireApprov
326326
}
327327
}
328328

329-
export function buildLogicalToPathMap(stack: cxapi.CloudFormationStackArtifact) {
329+
function buildLogicalToPathMap(stack: cxapi.CloudFormationStackArtifact) {
330330
const map: { [id: string]: string } = {};
331331
for (const md of stack.findMetadataByType(cxschema.ArtifactMetadataEntryType.LOGICAL_ID)) {
332332
map[md.data as string] = md.path;
333333
}
334334
return map;
335335
}
336336

337-
export function logicalIdMapFromTemplate(template: any) {
337+
function logicalIdMapFromTemplate(template: any) {
338338
const ret: Record<string, string> = {};
339339

340340
for (const [logicalId, resource] of Object.entries(template.Resources ?? {})) {
@@ -352,7 +352,7 @@ export function logicalIdMapFromTemplate(template: any) {
352352
* - AWS::CDK::Metadata resource
353353
* - CheckBootstrapVersion Rule
354354
*/
355-
export function obscureDiff(diff: TemplateDiff) {
355+
function obscureDiff(diff: TemplateDiff) {
356356
if (diff.unknown) {
357357
// see https://github.com/aws/aws-cdk/issues/17942
358358
diff.unknown = diff.unknown.filter(change => {

packages/@aws-cdk/tmp-toolkit-helpers/src/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './diff';
44
export * from './io';
55
export * from './toolkit-error';
66
export * from './require-approval';
7+
export * from './resource-import';

packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/payloads/diff.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Duration } from './types';
2+
13
/**
24
* Different types of permission related changes in a diff
35
*/
@@ -17,3 +19,18 @@ export enum PermissionChangeType {
1719
*/
1820
NON_BROADENING = 'non-broadening',
1921
}
22+
23+
/**
24+
* Output of the diff command
25+
*/
26+
export interface DiffResult extends Duration {
27+
/**
28+
* Stack diff formatted as a string
29+
*/
30+
readonly formattedStackDiff: string;
31+
32+
/**
33+
* Security diff formatted as a string
34+
*/
35+
readonly formattedSecurityDiff: string;
36+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { StackDetails } from './stack-details';
22

33
export interface StackDetailsPayload {
4-
stacks: StackDetails[];
4+
readonly stacks: StackDetails[];
55
}

packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/private/messages.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type * as cxapi from '@aws-cdk/cx-api';
22
import * as make from './message-maker';
33
import type { SpanDefinition } from './span';
4+
import type { DiffResult } from '../payloads';
45
import type { BootstrapEnvironmentProgress } from '../payloads/bootstrap-environment-progress';
56
import type { MissingContext, UpdatedContext } from '../payloads/context';
67
import type { BuildAsset, DeployConfirmationRequest, PublishAsset, StackDeployProgress, SuccessfulDeployStackResult } from '../payloads/deploy';
@@ -81,6 +82,16 @@ export const IO = {
8182
}),
8283

8384
// 4: Diff (4xxx)
85+
CDK_TOOLKIT_I4000: make.trace<StackSelectionDetails>({
86+
code: 'CDK_TOOLKIT_I4000',
87+
description: 'Diff stacks is starting',
88+
interface: 'StackSelectionDetails',
89+
}),
90+
CDK_TOOLKIT_I4001: make.info<DiffResult>({
91+
code: 'CDK_TOOLKIT_I4001',
92+
description: 'Output of the diff command',
93+
interface: 'DiffResult',
94+
}),
8495

8596
// 5: Deploy & Watch (5xxx)
8697
CDK_TOOLKIT_I5000: make.info<Duration>({
@@ -484,6 +495,9 @@ export const IO = {
484495

485496
//////////////////////////////////////////////////////////////////////////////////////////
486497

498+
/**
499+
* Payload type of the end message must extend Duration
500+
*/
487501
export const SPAN = {
488502
SYNTH_ASSEMBLY: {
489503
name: 'Synthesis',
@@ -500,6 +514,11 @@ export const SPAN = {
500514
start: IO.CDK_TOOLKIT_I6100,
501515
end: IO.CDK_TOOLKIT_I6000,
502516
},
517+
DIFF_STACK: {
518+
name: 'Diff',
519+
start: IO.CDK_TOOLKIT_I4000,
520+
end: IO.CDK_TOOLKIT_I4001,
521+
},
503522
DESTROY_STACK: {
504523
name: 'Destroy',
505524
start: IO.CDK_TOOLKIT_I7100,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { CloudFormationStackArtifact } from '@aws-cdk/cx-api';
2+
3+
/**
4+
* Removes CDKMetadata and Outputs in the template so that only resources for importing are left.
5+
* @returns template with import resources only
6+
*/
7+
export function removeNonImportResources(stack: CloudFormationStackArtifact) {
8+
const template = stack.template;
9+
delete template.Resources.CDKMetadata;
10+
delete template.Outputs;
11+
return template;
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './importer';

packages/@aws-cdk/tmp-toolkit-helpers/test/api/diff/diff.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ describe('formatSecurityDiff', () => {
236236
});
237237

238238
// THEN
239-
expect(result).toEqual({});
239+
expect(result.formattedDiff).toBeUndefined();
240240
expect(mockIoDefaultMessages.warning).not.toHaveBeenCalled();
241241
});
242242

@@ -320,7 +320,7 @@ describe('formatSecurityDiff', () => {
320320
});
321321

322322
// THEN
323-
expect(result).toEqual({});
323+
expect(result.formattedDiff).toBeUndefined();
324324
expect(mockIoDefaultMessages.warning).not.toHaveBeenCalled();
325325
});
326326
});

packages/@aws-cdk/toolkit-lib/docs/message-registry.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ group: Documents
1717
| `CDK_TOOLKIT_I1902` | Successfully deployed stacks | `result` | {@link AssemblyData} |
1818
| `CDK_TOOLKIT_I2901` | Provides details on the selected stacks and their dependencies | `result` | {@link StackDetailsPayload} |
1919
| `CDK_TOOLKIT_E3900` | Resource import failed | `error` | {@link ErrorPayload} |
20+
| `CDK_TOOLKIT_I4000` | Diff stacks is starting | `trace` | {@link StackSelectionDetails} |
21+
| `CDK_TOOLKIT_I4001` | Output of the diff command | `info` | {@link DiffResult} |
2022
| `CDK_TOOLKIT_I5000` | Provides deployment times | `info` | {@link Duration} |
2123
| `CDK_TOOLKIT_I5001` | Provides total time in deploy action, including synth and rollback | `info` | {@link Duration} |
2224
| `CDK_TOOLKIT_I5002` | Provides time for resource migration | `info` | {@link Duration} |

packages/@aws-cdk/toolkit-lib/lib/actions/diff/index.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ export interface CloudFormationDiffOptions {
1111
}
1212

1313
export interface ChangeSetDiffOptions extends CloudFormationDiffOptions {
14-
/**
15-
* Enable falling back to template-based diff in case creating the changeset is not possible or results in an error.
16-
*
17-
* Should be used for stacks containing nested stacks or when change set permissions aren't available.
18-
*
19-
* @default true
20-
*/
21-
readonly fallbackToTemplate?: boolean;
14+
// @TODO: add this as a feature
15+
// /**
16+
// * Enable falling back to template-based diff in case creating the changeset is not possible or results in an error.
17+
// *
18+
// * Should be used for stacks containing nested stacks or when change set permissions aren't available.
19+
// *
20+
// * @default true
21+
// */
22+
// readonly fallbackToTemplate?: boolean;
2223

2324
/**
2425
* Additional parameters for CloudFormation when creating a diff change set
@@ -28,6 +29,13 @@ export interface ChangeSetDiffOptions extends CloudFormationDiffOptions {
2829
readonly parameters?: { [name: string]: string | undefined };
2930
}
3031

32+
export interface LocalFileDiffOptions {
33+
/**
34+
* Path to the local file.
35+
*/
36+
readonly path: string;
37+
}
38+
3139
export class DiffMethod {
3240
/**
3341
* Use a changeset to compute the diff.
@@ -54,10 +62,13 @@ export class DiffMethod {
5462
}(options);
5563
}
5664

65+
/**
66+
* Use a local template file to compute the diff.
67+
*/
5768
public static LocalFile(path: string): DiffMethod {
5869
return new class extends DiffMethod {
5970
public override readonly options: { path: string };
60-
public constructor(opts: { path: string }) {
71+
public constructor(opts: LocalFileDiffOptions) {
6172
super('local-file', opts);
6273
this.options = opts;
6374
}
@@ -66,32 +77,35 @@ export class DiffMethod {
6677

6778
private constructor(
6879
public readonly method: 'change-set' | 'template-only' | 'local-file',
69-
public readonly options: ChangeSetDiffOptions | CloudFormationDiffOptions | { path: string },
80+
public readonly options: ChangeSetDiffOptions | CloudFormationDiffOptions | LocalFileDiffOptions,
7081
) {
7182
}
7283
}
7384

85+
/**
86+
* Optins for the diff method
87+
*/
7488
export interface DiffOptions {
7589
/**
7690
* Select the stacks
7791
*/
7892
readonly stacks: StackSelector;
7993

8094
/**
81-
* The mode to create a stack diff.
95+
* The method to create a stack diff.
8296
*
8397
* Use changeset diff for the highest fidelity, including analyze resource replacements.
84-
* In this mode, diff will use the deploy role instead of the lookup role.
98+
* In this method, diff will use the deploy role instead of the lookup role.
8599
*
86100
* Use template-only diff for a faster, less accurate diff that doesn't require
87101
* permissions to create a change-set.
88102
*
89103
* Use local-template diff for a fast, local-only diff that doesn't require
90104
* any permissions or internet access.
91105
*
92-
* @default DiffMode.ChangeSet
106+
* @default DiffMethod.ChangeSet
93107
*/
94-
readonly method: DiffMethod;
108+
readonly method?: DiffMethod;
95109

96110
/**
97111
* Strict diff mode
@@ -112,6 +126,8 @@ export interface DiffOptions {
112126
* Only include broadened security changes in the diff
113127
*
114128
* @default false
129+
*
130+
* @deprecated implement in IoHost
115131
*/
116132
readonly securityOnly?: boolean;
117133
}

0 commit comments

Comments
 (0)