Skip to content

Commit 762e57f

Browse files
authored
refactor(cli): stack/security diff no longer prints directly to a stream (#264)
part of https://github.com/orgs/aws/projects/257 this refactor removes direct prints to `stderr` or `stdout` for the diff cli command. the diff result will instead be printed through the global `CliIoHost`. the diff format is determined by the `Formatter` class, which takes in a `stream` that previously was `stdout` (or `stderr`). now, we are sending our own stream into `Formatter`, capturing what was previously immediately printed and instead returning it as a string. we then print the resulting string through `CliIoHost`. it should have no functional change to how the diff cli works today. this effort will help support diff in the toolkit lib because it allows the `IoHost` governance of the diff print. as this is a pure refactor, successful existing tests is enough to ensure that this works. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent ee0d87d commit 762e57f

File tree

5 files changed

+262
-229
lines changed

5 files changed

+262
-229
lines changed

packages/aws-cdk/lib/api/deployments/cfn-api.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ export type PrepareChangeSetOptions = {
140140
uuid: string;
141141
willExecute: boolean;
142142
sdkProvider: SdkProvider;
143-
stream: NodeJS.WritableStream;
144143
parameters: { [name: string]: string | undefined };
145144
resourcesToImport?: ResourcesToImport;
146145
}
@@ -224,9 +223,9 @@ async function uploadBodyParameterAndCreateChangeSet(
224223
const exists = (await CloudFormationStack.lookup(cfn, options.stack.stackName, false)).exists;
225224

226225
const executionRoleArn = await env.replacePlaceholders(options.stack.cloudFormationExecutionRoleArn);
227-
options.stream.write(
226+
await ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg(
228227
'Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)\n',
229-
);
228+
));
230229

231230
return await createChangeSet(ioHelper, {
232231
cfn,
@@ -242,9 +241,9 @@ async function uploadBodyParameterAndCreateChangeSet(
242241
});
243242
} catch (e: any) {
244243
await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(e));
245-
options.stream.write(
244+
await ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg(
246245
'Could not create a change set, will base the diff on template differences (run again with -v to see the reason)\n',
247-
);
246+
));
248247

249248
return undefined;
250249
}

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

+49-32
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { tagsForStack, type Tag } from '../api/tags';
3636
import type { AssetBuildNode, AssetPublishNode, Concurrency, StackNode, WorkGraph } from '../api/work-graph';
3737
import { WorkGraphBuilder } from '../api/work-graph/work-graph-builder';
3838
import { StackActivityProgress } from '../commands/deploy';
39-
import { printSecurityDiff, printStackDiff, RequireApproval } from '../commands/diff';
39+
import { formatSecurityDiff, formatStackDiff, RequireApproval } from '../commands/diff';
4040
import { listStacks } from '../commands/list-stacks';
4141
import type {
4242
FromScan,
@@ -60,7 +60,7 @@ import {
6060
} from '../commands/migrate';
6161
import { result as logResult, debug, error, highlight, info, success, warning } from '../logging';
6262
import { CliIoHost } from './io-host';
63-
import { numberFromBool, partition, validateSnsTopicArn, formatErrorMessage, deserializeStructure, obscureTemplate, serializeStructure, formatTime } from '../util';
63+
import { partition, validateSnsTopicArn, formatErrorMessage, deserializeStructure, obscureTemplate, serializeStructure, formatTime } from '../util';
6464

6565
// Must use a require() otherwise esbuild complains about calling a namespace
6666
// eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/consistent-type-imports
@@ -177,7 +177,6 @@ export class CdkToolkit {
177177

178178
const strict = !!options.strict;
179179
const contextLines = options.contextLines || 3;
180-
const stream = options.stream || process.stderr;
181180
const quiet = options.quiet || false;
182181

183182
let diffs = 0;
@@ -196,9 +195,31 @@ export class CdkToolkit {
196195
}
197196

198197
const template = deserializeStructure(await fs.readFile(options.templatePath, { encoding: 'UTF-8' }));
199-
diffs = options.securityOnly
200-
? numberFromBool(printSecurityDiff(template, stacks.firstStack, RequireApproval.Broadening, quiet))
201-
: printStackDiff(template, stacks.firstStack, strict, contextLines, quiet, undefined, undefined, false, stream);
198+
199+
if (options.securityOnly) {
200+
const securityDiff = formatSecurityDiff(
201+
template,
202+
stacks.firstStack,
203+
RequireApproval.Broadening,
204+
);
205+
if (securityDiff.formattedDiff) {
206+
info(securityDiff.formattedDiff);
207+
diffs += 1;
208+
}
209+
} else {
210+
const diff = formatStackDiff(
211+
template,
212+
stacks.firstStack,
213+
strict,
214+
contextLines,
215+
quiet,
216+
undefined,
217+
undefined,
218+
false,
219+
);
220+
diffs = diff.numStacksWithChanges;
221+
info(diff.formattedDiff);
222+
}
202223
} else {
203224
// Compare N stacks against deployed templates
204225
for (const stack of stacks.stackArtifacts) {
@@ -231,7 +252,7 @@ export class CdkToolkit {
231252
} catch (e: any) {
232253
debug(formatErrorMessage(e));
233254
if (!quiet) {
234-
stream.write(
255+
info(
235256
`Checking if the stack ${stack.stackName} exists before creating the changeset has failed, will base the diff on template differences (run again with -v to see the reason)\n`,
236257
);
237258
}
@@ -247,7 +268,6 @@ export class CdkToolkit {
247268
sdkProvider: this.props.sdkProvider,
248269
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
249270
resourcesToImport,
250-
stream,
251271
});
252272
} else {
253273
debug(
@@ -256,18 +276,20 @@ export class CdkToolkit {
256276
}
257277
}
258278

259-
const stackCount = options.securityOnly
260-
? numberFromBool(
261-
printSecurityDiff(
262-
currentTemplate,
263-
stack,
264-
RequireApproval.Broadening,
265-
quiet,
266-
stack.displayName,
267-
changeSet,
268-
),
269-
)
270-
: printStackDiff(
279+
if (options.securityOnly) {
280+
const securityDiff = formatSecurityDiff(
281+
currentTemplate,
282+
stack,
283+
RequireApproval.Broadening,
284+
stack.displayName,
285+
changeSet,
286+
);
287+
if (securityDiff.formattedDiff) {
288+
info(securityDiff.formattedDiff);
289+
diffs += 1;
290+
}
291+
} else {
292+
const diff = formatStackDiff(
271293
currentTemplate,
272294
stack,
273295
strict,
@@ -276,15 +298,15 @@ export class CdkToolkit {
276298
stack.displayName,
277299
changeSet,
278300
!!resourcesToImport,
279-
stream,
280301
nestedStacks,
281302
);
282-
283-
diffs += stackCount;
303+
info(diff.formattedDiff);
304+
diffs += diff.numStacksWithChanges;
305+
}
284306
}
285307
}
286308

287-
stream.write(format('\n✨ Number of stacks with differences: %s\n', diffs));
309+
info(format('\n✨ Number of stacks with differences: %s\n', diffs));
288310

289311
return diffs && options.fail ? 1 : 0;
290312
}
@@ -401,7 +423,9 @@ export class CdkToolkit {
401423

402424
if (requireApproval !== RequireApproval.Never) {
403425
const currentTemplate = await this.props.deployments.readCurrentTemplate(stack);
404-
if (printSecurityDiff(currentTemplate, stack, requireApproval)) {
426+
const securityDiff = formatSecurityDiff(currentTemplate, stack, requireApproval);
427+
if (securityDiff.formattedDiff) {
428+
info(securityDiff.formattedDiff);
405429
await askUserConfirmation(
406430
this.ioHost,
407431
concurrency,
@@ -1360,13 +1384,6 @@ export interface DiffOptions {
13601384
*/
13611385
contextLines?: number;
13621386

1363-
/**
1364-
* Where to write the default
1365-
*
1366-
* @default stderr
1367-
*/
1368-
stream?: NodeJS.WritableStream;
1369-
13701387
/**
13711388
* Whether to fail with exit code 1 in case of diff
13721389
*

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

-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
274274
contextLines: args.contextLines,
275275
securityOnly: args.securityOnly,
276276
fail: args.fail != null ? args.fail : !enableDiffNoFail,
277-
stream: args.ci ? process.stdout : undefined,
278277
compareAgainstProcessedTemplate: args.processed,
279278
quiet: args.quiet,
280279
changeSet: args['change-set'],

0 commit comments

Comments
 (0)