Skip to content

Commit 5777c88

Browse files
authored
feat(cdk): cdk diff --quiet suppresses progress messages (#26652)
Hello maintainers This is my first PR, so all feedback is welcome. This change adds support for the `--quiet` flag within cdk diff command, for users that would not like the following messages 'Stack <name>' and 'There were no differences' to be silenced for stacks which do not have *any* identified differences. The request was made by @nomike in the #26526, I simply followed the very well detailed description. The change follows similar structure to existing command and how they are passed, I have also added to the README as per the contributing guidelines. Before submitting I have. - Built the packages & linted them - Ran unit tests for the entire module - Ran all integration tests in the suite from `@aws-cdk-testing/cli-integ/bin/run-suite -a cli-integ-tests` - E2E tested by launching my small stack in account and executing diffs on it from my build. Closes #26526 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent cc52e2d commit 5777c88

File tree

6 files changed

+57
-5
lines changed

6 files changed

+57
-5
lines changed

packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts

+12
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,18 @@ integTest('cdk diff --security-only --fail exits when security changes are prese
651651
await expect(fixture.cdk(['diff', '--security-only', '--fail', fixture.fullStackName(stackName)])).rejects.toThrow('exited with error');
652652
}));
653653

654+
integTest('cdk diff --quiet does not print \'There were no differences\' message for stacks which have no differences', withDefaultFixture(async (fixture) => {
655+
// GIVEN
656+
await fixture.cdkDeploy('test-1');
657+
658+
// WHEN
659+
const diff = await fixture.cdk(['diff', '--quiet', fixture.fullStackName('test-1')]);
660+
661+
// THEN
662+
expect(diff).not.toContain('Stack test-1');
663+
expect(diff).not.toContain('There were no differences');
664+
}));
665+
654666
integTest('deploy stack with docker asset', withDefaultFixture(async (fixture) => {
655667
await fixture.cdkDeploy('docker');
656668
}));

packages/aws-cdk/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ $ # Diff against a specific template document
157157
$ cdk diff --app='node bin/main.js' MyStackName --template=path/to/template.yml
158158
```
159159

160+
The `quiet` flag can also be passed to the `cdk diff` command. Assuming there are no differences detected the output to the console will **not** contain strings such as the *Stack* `MyStackName` and `There were no differences`.
161+
162+
```console
163+
$ # Diff against the currently deployed stack with quiet parameter enabled
164+
$ cdk diff --quiet --app='node bin/main.js' MyStackName
165+
```
166+
160167
### `cdk deploy`
161168

162169
Deploys a stack of your CDK app to its environment. During the deployment, the toolkit will output progress

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

+14-3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export class CdkToolkit {
117117
const strict = !!options.strict;
118118
const contextLines = options.contextLines || 3;
119119
const stream = options.stream || process.stderr;
120+
const quiet = options.quiet || false;
120121

121122
let diffs = 0;
122123
if (options.templatePath !== undefined) {
@@ -131,15 +132,18 @@ export class CdkToolkit {
131132
const template = deserializeStructure(await fs.readFile(options.templatePath, { encoding: 'UTF-8' }));
132133
diffs = options.securityOnly
133134
? numberFromBool(printSecurityDiff(template, stacks.firstStack, RequireApproval.Broadening))
134-
: printStackDiff(template, stacks.firstStack, strict, contextLines, stream);
135+
: printStackDiff(template, stacks.firstStack, strict, contextLines, quiet, stream);
135136
} else {
136137
// Compare N stacks against deployed templates
137138
for (const stack of stacks.stackArtifacts) {
138-
stream.write(format('Stack %s\n', chalk.bold(stack.displayName)));
139+
if (!quiet) {
140+
stream.write(format('Stack %s\n', chalk.bold(stack.displayName)));
141+
}
142+
139143
const currentTemplate = await this.props.deployments.readCurrentTemplateWithNestedStacks(stack, options.compareAgainstProcessedTemplate);
140144
diffs += options.securityOnly
141145
? numberFromBool(printSecurityDiff(currentTemplate, stack, RequireApproval.Broadening))
142-
: printStackDiff(currentTemplate, stack, strict, contextLines, stream);
146+
: printStackDiff(currentTemplate, stack, strict, contextLines, quiet, stream);
143147
}
144148
}
145149

@@ -890,6 +894,13 @@ export interface DiffOptions {
890894
* @default false
891895
*/
892896
compareAgainstProcessedTemplate?: boolean;
897+
898+
/*
899+
* Run diff in quiet mode without printing the diff statuses
900+
*
901+
* @default false
902+
*/
903+
quiet?: boolean;
893904
}
894905

895906
interface CfnDeployOptions {

packages/aws-cdk/lib/cli.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ async function parseCommandLineArguments(args: string[]) {
261261
.option('strict', { type: 'boolean', desc: 'Do not filter out AWS::CDK::Metadata resources or mangled non-ASCII characters', default: false })
262262
.option('security-only', { type: 'boolean', desc: 'Only diff for broadened security changes', default: false })
263263
.option('fail', { type: 'boolean', desc: 'Fail with exit code 1 in case of diff' })
264-
.option('processed', { type: 'boolean', desc: 'Whether to compare against the template with Transforms already processed', default: false }))
264+
.option('processed', { type: 'boolean', desc: 'Whether to compare against the template with Transforms already processed', default: false })
265+
.option('quiet', { type: 'boolean', alias: 'q', desc: 'Do not print stack name and default message when there is no diff to stdout', default: false }))
265266
.command('metadata [STACK]', 'Returns all metadata associated with this stack')
266267
.command(['acknowledge [ID]', 'ack [ID]'], 'Acknowledge a notice so that it does not show up anymore')
267268
.command('notices', 'Returns a list of relevant notices')
@@ -489,6 +490,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
489490
fail: args.fail != null ? args.fail : !enableDiffNoFail,
490491
stream: args.ci ? process.stdout : undefined,
491492
compareAgainstProcessedTemplate: args.processed,
493+
quiet: args.quiet,
492494
});
493495

494496
case 'bootstrap':

packages/aws-cdk/lib/diff.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { print, warning } from './logging';
1111
* @param newTemplate the new/target state of the stack.
1212
* @param strict do not filter out AWS::CDK::Metadata
1313
* @param context lines of context to use in arbitrary JSON diff
14+
* @param quiet silences \'There were no differences\' messages
1415
*
1516
* @returns the count of differences that were rendered.
1617
*/
@@ -19,6 +20,7 @@ export function printStackDiff(
1920
newTemplate: cxapi.CloudFormationStackArtifact,
2021
strict: boolean,
2122
context: number,
23+
quiet: boolean,
2224
stream?: cfnDiff.FormatStream): number {
2325

2426
let diff = cfnDiff.diffTemplate(oldTemplate, newTemplate.template);
@@ -49,7 +51,7 @@ export function printStackDiff(
4951
...logicalIdMapFromTemplate(oldTemplate),
5052
...buildLogicalToPathMap(newTemplate),
5153
}, context);
52-
} else {
54+
} else if (!quiet) {
5355
print(chalk.green('There were no differences'));
5456
}
5557
if (filteredChangesCount > 0) {

packages/aws-cdk/test/diff.test.ts

+18
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ describe('non-nested stacks', () => {
136136
stream: buffer,
137137
})).rejects.toThrow(/Found errors/);
138138
});
139+
140+
test('when quiet mode is enabled, stacks with no diffs should not print stack name & no differences to stdout', async () => {
141+
// GIVEN
142+
const buffer = new StringWritable();
143+
144+
// WHEN
145+
const exitCode = await toolkit.diff({
146+
stackNames: ['A', 'A'],
147+
stream: buffer,
148+
fail: false,
149+
quiet: true,
150+
});
151+
152+
// THEN
153+
expect(buffer.data.trim()).not.toContain('Stack A');
154+
expect(buffer.data.trim()).not.toContain('There were no differences');
155+
expect(exitCode).toBe(0);
156+
});
139157
});
140158

141159
describe('nested stacks', () => {

0 commit comments

Comments
 (0)