From 5777c88394e2834bd56d6a20ace41e8d317a0d85 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 10 Aug 2023 15:15:10 +0100 Subject: [PATCH] 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 ' 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* --- .../tests/cli-integ-tests/cli.integtest.ts | 12 ++++++++++++ packages/aws-cdk/README.md | 7 +++++++ packages/aws-cdk/lib/cdk-toolkit.ts | 17 ++++++++++++++--- packages/aws-cdk/lib/cli.ts | 4 +++- packages/aws-cdk/lib/diff.ts | 4 +++- packages/aws-cdk/test/diff.test.ts | 18 ++++++++++++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 6b1d04f6268ac..b5b55ba5a6a75 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -651,6 +651,18 @@ integTest('cdk diff --security-only --fail exits when security changes are prese await expect(fixture.cdk(['diff', '--security-only', '--fail', fixture.fullStackName(stackName)])).rejects.toThrow('exited with error'); })); +integTest('cdk diff --quiet does not print \'There were no differences\' message for stacks which have no differences', withDefaultFixture(async (fixture) => { + // GIVEN + await fixture.cdkDeploy('test-1'); + + // WHEN + const diff = await fixture.cdk(['diff', '--quiet', fixture.fullStackName('test-1')]); + + // THEN + expect(diff).not.toContain('Stack test-1'); + expect(diff).not.toContain('There were no differences'); +})); + integTest('deploy stack with docker asset', withDefaultFixture(async (fixture) => { await fixture.cdkDeploy('docker'); })); diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 8c54bdf563369..825285ff35c39 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -157,6 +157,13 @@ $ # Diff against a specific template document $ cdk diff --app='node bin/main.js' MyStackName --template=path/to/template.yml ``` +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`. + +```console +$ # Diff against the currently deployed stack with quiet parameter enabled +$ cdk diff --quiet --app='node bin/main.js' MyStackName +``` + ### `cdk deploy` Deploys a stack of your CDK app to its environment. During the deployment, the toolkit will output progress diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index e5ff7cc642af3..1117271325e69 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -117,6 +117,7 @@ export class CdkToolkit { const strict = !!options.strict; const contextLines = options.contextLines || 3; const stream = options.stream || process.stderr; + const quiet = options.quiet || false; let diffs = 0; if (options.templatePath !== undefined) { @@ -131,15 +132,18 @@ export class CdkToolkit { const template = deserializeStructure(await fs.readFile(options.templatePath, { encoding: 'UTF-8' })); diffs = options.securityOnly ? numberFromBool(printSecurityDiff(template, stacks.firstStack, RequireApproval.Broadening)) - : printStackDiff(template, stacks.firstStack, strict, contextLines, stream); + : printStackDiff(template, stacks.firstStack, strict, contextLines, quiet, stream); } else { // Compare N stacks against deployed templates for (const stack of stacks.stackArtifacts) { - stream.write(format('Stack %s\n', chalk.bold(stack.displayName))); + if (!quiet) { + stream.write(format('Stack %s\n', chalk.bold(stack.displayName))); + } + const currentTemplate = await this.props.deployments.readCurrentTemplateWithNestedStacks(stack, options.compareAgainstProcessedTemplate); diffs += options.securityOnly ? numberFromBool(printSecurityDiff(currentTemplate, stack, RequireApproval.Broadening)) - : printStackDiff(currentTemplate, stack, strict, contextLines, stream); + : printStackDiff(currentTemplate, stack, strict, contextLines, quiet, stream); } } @@ -890,6 +894,13 @@ export interface DiffOptions { * @default false */ compareAgainstProcessedTemplate?: boolean; + + /* + * Run diff in quiet mode without printing the diff statuses + * + * @default false + */ + quiet?: boolean; } interface CfnDeployOptions { diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index d97a7d3b2b21e..6a00e74105efb 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -261,7 +261,8 @@ async function parseCommandLineArguments(args: string[]) { .option('strict', { type: 'boolean', desc: 'Do not filter out AWS::CDK::Metadata resources or mangled non-ASCII characters', default: false }) .option('security-only', { type: 'boolean', desc: 'Only diff for broadened security changes', default: false }) .option('fail', { type: 'boolean', desc: 'Fail with exit code 1 in case of diff' }) - .option('processed', { type: 'boolean', desc: 'Whether to compare against the template with Transforms already processed', default: false })) + .option('processed', { type: 'boolean', desc: 'Whether to compare against the template with Transforms already processed', default: false }) + .option('quiet', { type: 'boolean', alias: 'q', desc: 'Do not print stack name and default message when there is no diff to stdout', default: false })) .command('metadata [STACK]', 'Returns all metadata associated with this stack') .command(['acknowledge [ID]', 'ack [ID]'], 'Acknowledge a notice so that it does not show up anymore') .command('notices', 'Returns a list of relevant notices') @@ -489,6 +490,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise 0) { diff --git a/packages/aws-cdk/test/diff.test.ts b/packages/aws-cdk/test/diff.test.ts index ad8202a64db63..789c80c9a1e06 100644 --- a/packages/aws-cdk/test/diff.test.ts +++ b/packages/aws-cdk/test/diff.test.ts @@ -136,6 +136,24 @@ describe('non-nested stacks', () => { stream: buffer, })).rejects.toThrow(/Found errors/); }); + + test('when quiet mode is enabled, stacks with no diffs should not print stack name & no differences to stdout', async () => { + // GIVEN + const buffer = new StringWritable(); + + // WHEN + const exitCode = await toolkit.diff({ + stackNames: ['A', 'A'], + stream: buffer, + fail: false, + quiet: true, + }); + + // THEN + expect(buffer.data.trim()).not.toContain('Stack A'); + expect(buffer.data.trim()).not.toContain('There were no differences'); + expect(exitCode).toBe(0); + }); }); describe('nested stacks', () => {