Skip to content

Commit ef0017a

Browse files
author
Elad Ben-Israel
authored
feat(toolkit): by default hide AWS::CDK::Metadata from "cdk diff" (#1186)
`DifferenceCollection#filter` returns a new collection with changes filtered. Changed `DifferenceCollection#count` to do a lazy calculation since now `changes` is mutable. The toolkit switch `cdk diff --strict` disables this behavior. Fixes #465
1 parent b3a5cb3 commit ef0017a

File tree

3 files changed

+66
-34
lines changed

3 files changed

+66
-34
lines changed

packages/@aws-cdk/cloudformation-diff/lib/diff/types.ts

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,60 @@ import { deepEqual } from './util';
33

44
/** Semantic differences between two CloudFormation templates. */
55
export class TemplateDiff implements ITemplateDiff {
6-
public readonly awsTemplateFormatVersion?: Difference<string>;
7-
public readonly description?: Difference<string>;
8-
public readonly transform?: Difference<string>;
9-
public readonly conditions: DifferenceCollection<Condition, ConditionDifference>;
10-
public readonly mappings: DifferenceCollection<Mapping, MappingDifference>;
11-
public readonly metadata: DifferenceCollection<Metadata, MetadataDifference>;
12-
public readonly outputs: DifferenceCollection<Output, OutputDifference>;
13-
public readonly parameters: DifferenceCollection<Parameter, ParameterDifference>;
14-
public readonly resources: DifferenceCollection<Resource, ResourceDifference>;
6+
public awsTemplateFormatVersion?: Difference<string>;
7+
public description?: Difference<string>;
8+
public transform?: Difference<string>;
9+
public conditions: DifferenceCollection<Condition, ConditionDifference>;
10+
public mappings: DifferenceCollection<Mapping, MappingDifference>;
11+
public metadata: DifferenceCollection<Metadata, MetadataDifference>;
12+
public outputs: DifferenceCollection<Output, OutputDifference>;
13+
public parameters: DifferenceCollection<Parameter, ParameterDifference>;
14+
public resources: DifferenceCollection<Resource, ResourceDifference>;
1515
/** The differences in unknown/unexpected parts of the template */
16-
public readonly unknown: DifferenceCollection<any, Difference<any>>;
17-
18-
public readonly count: number;
16+
public unknown: DifferenceCollection<any, Difference<any>>;
1917

2018
constructor(args: ITemplateDiff) {
21-
let count = 0;
2219
if (args.awsTemplateFormatVersion !== undefined) {
2320
this.awsTemplateFormatVersion = args.awsTemplateFormatVersion;
24-
count += 1;
2521
}
2622
if (args.description !== undefined) {
2723
this.description = args.description;
28-
count += 1;
2924
}
3025
if (args.transform !== undefined) {
3126
this.transform = args.transform;
32-
count += 1;
3327
}
3428

3529
this.conditions = args.conditions || new DifferenceCollection({});
36-
count += this.conditions.count;
37-
3830
this.mappings = args.mappings || new DifferenceCollection({});
39-
count += this.mappings.count;
40-
4131
this.metadata = args.metadata || new DifferenceCollection({});
42-
count += this.metadata.count;
43-
4432
this.outputs = args.outputs || new DifferenceCollection({});
45-
count += this.outputs.count;
46-
4733
this.parameters = args.parameters || new DifferenceCollection({});
48-
count += this.parameters.count;
49-
5034
this.resources = args.resources || new DifferenceCollection({});
51-
count += this.resources.count;
52-
5335
this.unknown = args.unknown || new DifferenceCollection({});
36+
}
37+
38+
public get count() {
39+
let count = 0;
40+
41+
if (this.awsTemplateFormatVersion !== undefined) {
42+
count += 1;
43+
}
44+
if (this.description !== undefined) {
45+
count += 1;
46+
}
47+
if (this.transform !== undefined) {
48+
count += 1;
49+
}
50+
51+
count += this.conditions.count;
52+
count += this.mappings.count;
53+
count += this.metadata.count;
54+
count += this.outputs.count;
55+
count += this.parameters.count;
56+
count += this.resources.count;
5457
count += this.unknown.count;
5558

56-
this.count = count;
59+
return count;
5760
}
5861

5962
public get isEmpty(): boolean {
@@ -117,6 +120,23 @@ export class DifferenceCollection<V, T extends Difference<V>> {
117120
return Object.keys(this.changes);
118121
}
119122

123+
/**
124+
* Returns a new TemplateDiff which only contains changes for which `predicate`
125+
* returns `true`.
126+
*/
127+
public filter(predicate: (diff: T | undefined) => boolean): DifferenceCollection<V, T> {
128+
const newChanges: { [logicalId: string]: T | undefined } = { };
129+
for (const id of Object.keys(this.changes)) {
130+
const diff = this.changes[id];
131+
132+
if (predicate(diff)) {
133+
newChanges[id] = diff;
134+
}
135+
}
136+
137+
return new DifferenceCollection<V, T>(newChanges);
138+
}
139+
120140
public forEach(cb: (logicalId: string, change: T) => any): void {
121141
for (const logicalId of this.logicalIds) {
122142
cb(logicalId, this.changes[logicalId]!);

packages/aws-cdk/bin/cdk.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ async function parseCommandLineArguments() {
5757
.command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs
5858
.option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' }))
5959
.command('diff [STACK]', 'Compares the specified stack with the deployed stack or a local template file', yargs => yargs
60-
.option('template', { type: 'string', desc: 'the path to the CloudFormation template to compare with' }))
60+
.option('template', { type: 'string', desc: 'the path to the CloudFormation template to compare with' })
61+
.option('strict', { type: 'boolean', desc: 'do not filter out AWS::CDK::Metadata resources', default: false }))
6162
.command('metadata [STACK]', 'Returns all metadata associated with this stack')
6263
.command('init [TEMPLATE]', 'Create a new, empty CDK project from a template. Invoked without TEMPLATE, the app template will be used.', yargs => yargs
6364
.option('language', { type: 'string', alias: 'l', desc: 'the language to be used for the new project (default can be configured in ~/.cdk.json)', choices: initTemplateLanuages })
@@ -187,7 +188,7 @@ async function initCommandLine() {
187188
return await cliList({ long: args.long });
188189

189190
case 'diff':
190-
return await diffStack(await findStack(args.STACK), args.template);
191+
return await diffStack(await findStack(args.STACK), args.template, args.strict);
191192

192193
case 'bootstrap':
193194
return await cliBootstrap(args.ENVIRONMENTS, toolkitStackName, args.roleArn);
@@ -394,10 +395,10 @@ async function initCommandLine() {
394395
}
395396
}
396397
397-
async function diffStack(stackName: string, templatePath?: string): Promise<number> {
398+
async function diffStack(stackName: string, templatePath: string | undefined, strict: boolean): Promise<number> {
398399
const stack = await appStacks.synthesizeStack(stackName);
399400
const currentTemplate = await readCurrentTemplate(stack, templatePath);
400-
if (printStackDiff(currentTemplate, stack) === 0) {
401+
if (printStackDiff(currentTemplate, stack, strict) === 0) {
401402
return 0;
402403
} else {
403404
return 1;

packages/aws-cdk/lib/diff.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,19 @@ import { print } from './logging';
1111
*
1212
* @returns the count of differences that were rendered.
1313
*/
14-
export function printStackDiff(oldTemplate: any, newTemplate: cxapi.SynthesizedStack): number {
14+
export function printStackDiff(oldTemplate: any, newTemplate: cxapi.SynthesizedStack, strict: boolean): number {
1515
const diff = cfnDiff.diffTemplate(oldTemplate, newTemplate.template);
16+
17+
// filter out 'AWS::CDK::Metadata' resources from the template
18+
if (diff.resources && !strict) {
19+
diff.resources = diff.resources.filter(change => {
20+
if (!change) { return true; }
21+
if (change.newResourceType === 'AWS::CDK::Metadata') { return false; }
22+
if (change.oldResourceType === 'AWS::CDK::Metadata') { return false; }
23+
return true;
24+
});
25+
}
26+
1627
if (!diff.isEmpty) {
1728
cfnDiff.formatDifferences(process.stderr, diff);
1829
} else {

0 commit comments

Comments
 (0)