in packages/aws-cdk/lib/cli/cdk-toolkit.ts [202:340]
public async diff(options: DiffOptions): Promise<number> {
const stacks = await this.selectStacksForDiff(options.stackNames, options.exclusively);
const strict = !!options.strict;
const contextLines = options.contextLines || 3;
const quiet = options.quiet || false;
let diffs = 0;
const parameterMap = buildParameterMap(options.parameters);
if (options.templatePath !== undefined) {
// Compare single stack against fixed template
if (stacks.stackCount !== 1) {
throw new ToolkitError(
'Can only select one stack when comparing to fixed template. Use --exclusively to avoid selecting multiple stacks.',
);
}
if (!(await fs.pathExists(options.templatePath))) {
throw new ToolkitError(`There is no file at ${options.templatePath}`);
}
const template = deserializeStructure(await fs.readFile(options.templatePath, { encoding: 'UTF-8' }));
const formatter = new DiffFormatter({
ioHelper: asIoHelper(this.ioHost, 'diff'),
templateInfo: {
oldTemplate: template,
newTemplate: stacks.firstStack,
},
});
if (options.securityOnly) {
const securityDiff = formatter.formatSecurityDiff();
// Warn, count, and display the diff only if the reported changes are broadening permissions
if (securityDiff.permissionChangeType === PermissionChangeType.BROADENING) {
warning('This deployment will make potentially sensitive changes according to your current security approval level.\nPlease confirm you intend to make the following modifications:\n');
info(securityDiff.formattedDiff);
diffs += 1;
}
} else {
const diff = formatter.formatStackDiff({
strict,
context: contextLines,
quiet,
});
diffs = diff.numStacksWithChanges;
info(diff.formattedDiff);
}
} else {
// Compare N stacks against deployed templates
for (const stack of stacks.stackArtifacts) {
const templateWithNestedStacks = await this.props.deployments.readCurrentTemplateWithNestedStacks(
stack,
options.compareAgainstProcessedTemplate,
);
const currentTemplate = templateWithNestedStacks.deployedRootTemplate;
const nestedStacks = templateWithNestedStacks.nestedStacks;
const migrator = new ResourceMigrator({
deployments: this.props.deployments,
ioHelper: asIoHelper(this.ioHost, 'diff'),
});
const resourcesToImport = await migrator.tryGetResources(await this.props.deployments.resolveEnvironment(stack));
if (resourcesToImport) {
removeNonImportResources(stack);
}
let changeSet = undefined;
if (options.changeSet) {
let stackExists = false;
try {
stackExists = await this.props.deployments.stackExists({
stack,
deployName: stack.stackName,
tryLookupRole: true,
});
} catch (e: any) {
debug(formatErrorMessage(e));
if (!quiet) {
info(
`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`,
);
}
stackExists = false;
}
if (stackExists) {
changeSet = await cfnApi.createDiffChangeSet(asIoHelper(this.ioHost, 'diff'), {
stack,
uuid: uuid.v4(),
deployments: this.props.deployments,
willExecute: false,
sdkProvider: this.props.sdkProvider,
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
resourcesToImport,
});
} else {
debug(
`the stack '${stack.stackName}' has not been deployed to CloudFormation or describeStacks call failed, skipping changeset creation.`,
);
}
}
const formatter = new DiffFormatter({
ioHelper: asIoHelper(this.ioHost, 'diff'),
templateInfo: {
oldTemplate: currentTemplate,
newTemplate: stack,
changeSet,
isImport: !!resourcesToImport,
nestedStacks,
},
});
if (options.securityOnly) {
const securityDiff = formatter.formatSecurityDiff();
// Warn, count, and display the diff only if the reported changes are broadening permissions
if (securityDiff.permissionChangeType === PermissionChangeType.BROADENING) {
warning('This deployment will make potentially sensitive changes according to your current security approval level.\nPlease confirm you intend to make the following modifications:\n');
info(securityDiff.formattedDiff);
diffs += 1;
}
} else {
const diff = formatter.formatStackDiff({
strict,
context: contextLines,
quiet,
});
info(diff.formattedDiff);
diffs += diff.numStacksWithChanges;
}
}
}
info(format('\n✨ Number of stacks with differences: %s\n', diffs));
return diffs && options.fail ? 1 : 0;
}