diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index f7585f6bface8..d7011d743ffaf 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -394,14 +394,15 @@ export class CdkToolkit { private async selectStacksForDiff(stackNames: string[], exclusively?: boolean) { const assembly = await this.assembly(); - const stacks = await assembly.selectStacks(stackNames, { + + const idsToValidate = process.env.STACKS_TO_VALIDATE ? process.env.STACKS_TO_VALIDATE.split(';') : stackNames; + const stacksToValidate = await this.selectStacksForList(idsToValidate); + await this.validateStacks(stacksToValidate); + + return assembly.selectStacks(stackNames, { extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, defaultBehavior: DefaultSelection.MainAssembly, }); - - await this.validateStacks(stacks); - - return stacks; } private async selectStacksForDestroy(stackNames: string[], exclusively?: boolean) { diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 444025ae8d16d..5b918889e55a8 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -159,6 +159,40 @@ describe('synth', () => { // THEN await expect(toolkit.synth(['Test-Stack-A'], false, true)).resolves.toBeUndefined(); }); + + describe('post-synth validation', () => { + beforeEach(() => { + cloudExecutable = new MockCloudExecutable({ + stacks: [ + MockStack.MOCK_STACK_A, + MockStack.MOCK_STACK_B, + ], + nestedAssemblies: [{ + stacks: [MockStack.MOCK_STACK_WITH_ERROR], + }], + }); + }); + }); + + afterEach(() => { + process.env.STACKS_TO_VALIDATE = undefined; + }); + + test('with STACKS_TO_VALIDATE containing a failed stack', async() => { + process.env.STACKS_TO_VALIDATE = 'Test-Stack-A;Test-Stack-A/witherrors'; + + const toolkit = defaultToolkitSetup(); + + await expect(toolkit.synth(['Test-Stack-A'], false, true)).rejects.toBeDefined(); + }); + + test('with STACKS_TO_VALIDATE not containing a failed stack', async() => { + process.env.STACKS_TO_VALIDATE = 'Test-Stack-A'; + + const toolkit = defaultToolkitSetup(); + + await toolkit.synth(['Test-Stack-A'], false, true); + }); }); class MockStack { @@ -208,6 +242,20 @@ class MockStack { }, displayName: 'Test-Stack-A/Test-Stack-C', }; + public static readonly MOCK_STACK_WITH_ERROR: TestStackArtifact = { + stackName: 'witherrors', + env: 'aws://123456789012/bermuda-triangle-1', + template: { resource: 'errorresource' }, + metadata: { + '/resource': [ + { + type: cxschema.ArtifactMetadataEntryType.ERROR, + data: 'this is an error', + }, + ], + }, + displayName: 'Test-Stack-A/witherrors', + } } class FakeCloudFormation extends CloudFormationDeployments {