From a6757b06f764938981aa82c82b2d21feea05b2f4 Mon Sep 17 00:00:00 2001 From: Alex Rewa Date: Thu, 18 Aug 2022 01:09:56 +0300 Subject: [PATCH] fix(cli): empty non top-level stack does not get deleted (#21624) Fixed selector pattern for the empty stack which must be deleted during the deployment. I set stack selector pattern as `stack.hierarchicalId` because hierarchicalId is used in `selectMatchingStacks` method which is called when destroy logic is looking for the stack to be deleted. https://github.com/aws/aws-cdk/blob/92d6d58029595735df6902db5f820b1182dfb27b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts#L138 There is also existing integration test which covers destroy logic and it works now without additional modifications: https://github.com/aws/aws-cdk/blob/92d6d58029595735df6902db5f820b1182dfb27b/packages/aws-cdk/test/integ/cli/cli.integtest.ts#L685 **How I tested it locally?** - Prepared a package with fix with `yarn package` and installed with `npm install -g dist/js/aws-cdk-0.0.0.tgz` - Reproduced steps from the bug #20822 - Ensured that the issue is fixed closes #20822 ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk/lib/cdk-toolkit.ts | 2 +- packages/aws-cdk/test/cdk-toolkit.test.ts | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 7ae1c18b602b7..93518b4bf6394 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -188,7 +188,7 @@ export class CdkToolkit { } else { warning('%s: stack has no resources, deleting existing stack.', chalk.bold(stack.displayName)); await this.destroy({ - selector: { patterns: [stack.stackName] }, + selector: { patterns: [stack.hierarchicalId] }, exclusively: true, force: true, roleArn: options.roleArn, diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 3e73a97eec015..b0359fbb6dbc7 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -56,7 +56,7 @@ jest.mock('../lib/logging', () => ({ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cxapi from '@aws-cdk/cx-api'; import { Bootstrapper } from '../lib/api/bootstrap'; -import { CloudFormationDeployments, DeployStackOptions } from '../lib/api/cloudformation-deployments'; +import { CloudFormationDeployments, DeployStackOptions, DestroyStackOptions } from '../lib/api/cloudformation-deployments'; import { DeployStackResult } from '../lib/api/deploy-stack'; import { Template } from '../lib/api/util/cloudformation'; import { CdkToolkit, Tag } from '../lib/cdk-toolkit'; @@ -558,6 +558,21 @@ describe('deploy', () => { }); }); +describe('destroy', () => { + test('destroy correct stack', async () => { + const toolkit = defaultToolkitSetup(); + + await expect(() => { + return toolkit.destroy({ + selector: { patterns: ['Test-Stack-A/Test-Stack-C'] }, + exclusively: true, + force: true, + fromDeploy: true, + }); + }).resolves; + }); +}); + describe('watch', () => { test("fails when no 'watch' settings are found", async () => { const toolkit = defaultToolkitSetup(); @@ -931,6 +946,11 @@ class FakeCloudFormation extends CloudFormationDeployments { }); } + public destroyStack(options: DestroyStackOptions): Promise { + expect(options.stack).toBeDefined(); + return Promise.resolve(); + } + public readCurrentTemplate(stack: cxapi.CloudFormationStackArtifact): Promise