Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
04e800c
add diff to toolkit wip
kaizencc Mar 19, 2025
8a2da40
Merge branch 'main' into conroy/diffs
kaizencc Mar 24, 2025
8ac30ca
more refactoring
kaizencc Mar 24, 2025
6958274
mslall
kaizencc Mar 24, 2025
31b2ec2
another small one
kaizencc Mar 24, 2025
8f3eaa6
Merge branch 'main' into conroy/diffs
kaizencc Mar 26, 2025
1d1ef8e
more merge
kaizencc Mar 26, 2025
ec39825
small changes
kaizencc Mar 26, 2025
ba7d5fa
update tmp-toolkit-helpers to return information i need
kaizencc Mar 26, 2025
964e226
wip tests
kaizencc Mar 26, 2025
737dfee
more tests
kaizencc Mar 26, 2025
17d88c1
final tests
kaizencc Mar 26, 2025
b18dc89
changeset tests
kaizencc Mar 26, 2025
2f69880
refactor a bunch of things
kaizencc Mar 27, 2025
af827ea
export createDiffChangeSet
kaizencc Mar 27, 2025
b0be263
synth span
kaizencc Mar 27, 2025
d523372
revert templatediff return
kaizencc Mar 27, 2025
54c2a25
ugly tests
kaizencc Mar 27, 2025
9b1e483
small
kaizencc Mar 28, 2025
883f5e9
default messages now
kaizencc Mar 28, 2025
0ce153e
fix tess
kaizencc Mar 28, 2025
92ed6b4
newlines
kaizencc Mar 28, 2025
1fa9eee
messages now printed only one time
kaizencc Mar 28, 2025
1ad4bd0
Merge branch 'main' into conroy/diffs
kaizencc Mar 28, 2025
dd9f7de
fix merge
kaizencc Mar 28, 2025
719ad2a
span
kaizencc Mar 28, 2025
222860f
span
kaizencc Mar 28, 2025
f70b343
typo
kaizencc Mar 28, 2025
a8c724c
move em around
kaizencc Mar 28, 2025
67269a5
messages make more sense
kaizencc Mar 28, 2025
3cfbc58
pr feedback
kaizencc Mar 28, 2025
cc17758
iffoptions
kaizencc Mar 28, 2025
8cedfb7
export file
kaizencc Mar 28, 2025
c96788f
chore: self mutation
invalid-email-address Mar 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class StringWriteStream extends Writable {
/**
* Output of formatSecurityDiff
*/
export interface FormatSecurityDiffOutput {
interface FormatSecurityDiffOutput {
/**
* Complete formatted security diff, if it is prompt-worthy
*/
Expand All @@ -53,7 +53,7 @@ export interface FormatSecurityDiffOutput {
/**
* Output of formatStackDiff
*/
export interface FormatStackDiffOutput {
interface FormatStackDiffOutput {
/**
* Number of stacks with diff changes
*/
Expand All @@ -68,7 +68,7 @@ export interface FormatStackDiffOutput {
/**
* Props for the Diff Formatter
*/
export interface DiffFormatterProps {
interface DiffFormatterProps {
/**
* Helper for the IoHost class
*/
Expand All @@ -88,7 +88,7 @@ export interface DiffFormatterProps {
/**
* Properties specific to formatting the security diff
*/
export interface FormatSecurityDiffOptions {
interface FormatSecurityDiffOptions {
/**
* The approval level of the security diff
*/
Expand All @@ -110,7 +110,7 @@ export interface FormatSecurityDiffOptions {
/**
* PRoperties specific to formatting the stack diff
*/
export interface FormatStackDiffOptions {
interface FormatStackDiffOptions {
/**
* do not filter out AWS::CDK::Metadata or Rules
*
Expand Down Expand Up @@ -326,15 +326,15 @@ function diffRequiresApproval(diff: TemplateDiff, requireApproval: RequireApprov
}
}

export function buildLogicalToPathMap(stack: cxapi.CloudFormationStackArtifact) {
function buildLogicalToPathMap(stack: cxapi.CloudFormationStackArtifact) {
const map: { [id: string]: string } = {};
for (const md of stack.findMetadataByType(cxschema.ArtifactMetadataEntryType.LOGICAL_ID)) {
map[md.data as string] = md.path;
}
return map;
}

export function logicalIdMapFromTemplate(template: any) {
function logicalIdMapFromTemplate(template: any) {
const ret: Record<string, string> = {};

for (const [logicalId, resource] of Object.entries(template.Resources ?? {})) {
Expand All @@ -352,7 +352,7 @@ export function logicalIdMapFromTemplate(template: any) {
* - AWS::CDK::Metadata resource
* - CheckBootstrapVersion Rule
*/
export function obscureDiff(diff: TemplateDiff) {
function obscureDiff(diff: TemplateDiff) {
if (diff.unknown) {
// see https://github.com/aws/aws-cdk/issues/17942
diff.unknown = diff.unknown.filter(change => {
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/tmp-toolkit-helpers/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './diff';
export * from './io';
export * from './toolkit-error';
export * from './require-approval';
export * from './resource-import';
17 changes: 17 additions & 0 deletions packages/@aws-cdk/tmp-toolkit-helpers/src/api/io/payloads/diff.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Duration } from './types';

/**
* Different types of permission related changes in a diff
*/
Expand All @@ -17,3 +19,18 @@ export enum PermissionChangeType {
*/
NON_BROADENING = 'non-broadening',
}

/**
* Output of the diff command
*/
export interface DiffResult extends Duration {
/**
* Stack diff formatted as a string
*/
readonly formattedStackDiff: string;

/**
* Security diff formatted as a string
*/
readonly formattedSecurityDiff: string;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { StackDetails } from './stack-details';

export interface StackDetailsPayload {
stacks: StackDetails[];
readonly stacks: StackDetails[];
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type * as cxapi from '@aws-cdk/cx-api';
import * as make from './message-maker';
import type { SpanDefinition } from './span';
import type { DiffResult } from '../payloads';
import type { BootstrapEnvironmentProgress } from '../payloads/bootstrap-environment-progress';
import type { MissingContext, UpdatedContext } from '../payloads/context';
import type { BuildAsset, DeployConfirmationRequest, PublishAsset, StackDeployProgress, SuccessfulDeployStackResult } from '../payloads/deploy';
Expand Down Expand Up @@ -81,6 +82,16 @@ export const IO = {
}),

// 4: Diff (4xxx)
CDK_TOOLKIT_I4000: make.trace<StackSelectionDetails>({
code: 'CDK_TOOLKIT_I4000',
description: 'Diff stacks is starting',
interface: 'StackSelectionDetails',
}),
CDK_TOOLKIT_I4001: make.info<DiffResult>({
code: 'CDK_TOOLKIT_I4001',
description: 'Output of the diff command',
interface: 'DiffResult',
}),

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

//////////////////////////////////////////////////////////////////////////////////////////

/**
* Payload type of the end message must extend Duration
*/
export const SPAN = {
SYNTH_ASSEMBLY: {
name: 'Synthesis',
Expand All @@ -500,6 +514,11 @@ export const SPAN = {
start: IO.CDK_TOOLKIT_I6100,
end: IO.CDK_TOOLKIT_I6000,
},
DIFF_STACK: {
name: 'Diff',
start: IO.CDK_TOOLKIT_I4000,
end: IO.CDK_TOOLKIT_I4001,
},
DESTROY_STACK: {
name: 'Destroy',
start: IO.CDK_TOOLKIT_I7100,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { CloudFormationStackArtifact } from '@aws-cdk/cx-api';

/**
* Removes CDKMetadata and Outputs in the template so that only resources for importing are left.
* @returns template with import resources only
*/
export function removeNonImportResources(stack: CloudFormationStackArtifact) {
const template = stack.template;
delete template.Resources.CDKMetadata;
delete template.Outputs;
return template;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './importer';
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ describe('formatSecurityDiff', () => {
});

// THEN
expect(result).toEqual({});
expect(result.formattedDiff).toBeUndefined();
expect(mockIoDefaultMessages.warning).not.toHaveBeenCalled();
});

Expand Down Expand Up @@ -320,7 +320,7 @@ describe('formatSecurityDiff', () => {
});

// THEN
expect(result).toEqual({});
expect(result.formattedDiff).toBeUndefined();
expect(mockIoDefaultMessages.warning).not.toHaveBeenCalled();
});
});
2 changes: 2 additions & 0 deletions packages/@aws-cdk/toolkit-lib/docs/message-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ group: Documents
| `CDK_TOOLKIT_I1902` | Successfully deployed stacks | `result` | {@link AssemblyData} |
| `CDK_TOOLKIT_I2901` | Provides details on the selected stacks and their dependencies | `result` | {@link StackDetailsPayload} |
| `CDK_TOOLKIT_E3900` | Resource import failed | `error` | {@link ErrorPayload} |
| `CDK_TOOLKIT_I4000` | Diff stacks is starting | `trace` | {@link StackSelectionDetails} |
| `CDK_TOOLKIT_I4001` | Output of the diff command | `info` | {@link DiffResult} |
| `CDK_TOOLKIT_I5000` | Provides deployment times | `info` | {@link Duration} |
| `CDK_TOOLKIT_I5001` | Provides total time in deploy action, including synth and rollback | `info` | {@link Duration} |
| `CDK_TOOLKIT_I5002` | Provides time for resource migration | `info` | {@link Duration} |
Expand Down
44 changes: 30 additions & 14 deletions packages/@aws-cdk/toolkit-lib/lib/actions/diff/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ export interface CloudFormationDiffOptions {
}

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

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

export interface LocalFileDiffOptions {
/**
* Path to the local file.
*/
readonly path: string;
}

export class DiffMethod {
/**
* Use a changeset to compute the diff.
Expand All @@ -54,10 +62,13 @@ export class DiffMethod {
}(options);
}

/**
* Use a local template file to compute the diff.
*/
public static LocalFile(path: string): DiffMethod {
return new class extends DiffMethod {
public override readonly options: { path: string };
public constructor(opts: { path: string }) {
public constructor(opts: LocalFileDiffOptions) {
super('local-file', opts);
this.options = opts;
}
Expand All @@ -66,32 +77,35 @@ export class DiffMethod {

private constructor(
public readonly method: 'change-set' | 'template-only' | 'local-file',
public readonly options: ChangeSetDiffOptions | CloudFormationDiffOptions | { path: string },
public readonly options: ChangeSetDiffOptions | CloudFormationDiffOptions | LocalFileDiffOptions,
) {
}
}

/**
* Optins for the diff method
*/
export interface DiffOptions {
/**
* Select the stacks
*/
readonly stacks: StackSelector;

/**
* The mode to create a stack diff.
* The method to create a stack diff.
*
* Use changeset diff for the highest fidelity, including analyze resource replacements.
* In this mode, diff will use the deploy role instead of the lookup role.
* In this method, diff will use the deploy role instead of the lookup role.
*
* Use template-only diff for a faster, less accurate diff that doesn't require
* permissions to create a change-set.
*
* Use local-template diff for a fast, local-only diff that doesn't require
* any permissions or internet access.
*
* @default DiffMode.ChangeSet
* @default DiffMethod.ChangeSet
*/
readonly method: DiffMethod;
readonly method?: DiffMethod;

/**
* Strict diff mode
Expand All @@ -112,6 +126,8 @@ export interface DiffOptions {
* Only include broadened security changes in the diff
*
* @default false
*
* @deprecated implement in IoHost
*/
readonly securityOnly?: boolean;
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/toolkit-lib/lib/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './bootstrap';
export * from './deploy';
export * from './destroy';
export * from './diff';
export * from './list';
export * from './rollback';
export * from './synth';
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/toolkit-lib/lib/api/aws-cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// APIs
export { SdkProvider } from '../../../../aws-cdk/lib/api/aws-auth';
export { Context, PROJECT_CONTEXT } from '../../../../aws-cdk/lib/api/context';
export { Deployments, type SuccessfulDeployStackResult, type DeployStackOptions, type DeployStackResult } from '../../../../aws-cdk/lib/api/deployments';
export { createDiffChangeSet, Deployments, type SuccessfulDeployStackResult, type DeployStackOptions, type DeployStackResult } from '../../../../aws-cdk/lib/api/deployments';
export { Settings } from '../../../../aws-cdk/lib/api/settings';
export { type Tag, tagsForStack } from '../../../../aws-cdk/lib/api/tags';
export { DEFAULT_TOOLKIT_STACK_NAME } from '../../../../aws-cdk/lib/api/toolkit-info';
Expand Down
Loading