Skip to content

Commit 727cb0a

Browse files
authored
Chore: [AEA-0000] - handle stack does not exist in check destructive changes (#710)
## Summary - Routine Change ### Details - handle stack not exist in check destructive changes
1 parent 2aebb48 commit 727cb0a

2 files changed

Lines changed: 55 additions & 5 deletions

File tree

packages/cdkConstructs/src/changesets/checkDestructiveChanges.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
CloudFormationClient,
3+
DescribeStacksCommand,
34
DescribeChangeSetCommand,
45
DescribeChangeSetCommandOutput,
56
Change as CloudFormationChange
@@ -128,6 +129,18 @@ export async function checkDestructiveChangeSet(
128129
}
129130

130131
const client = new CloudFormationClient({region})
132+
133+
try {
134+
await client.send(new DescribeStacksCommand({StackName: stackName}))
135+
} catch (error) {
136+
if (error instanceof Error && error.name === "ValidationError" && error.message.includes("does not exist")) {
137+
console.log(`Stack ${stackName} does not exist. Skipping destructive change check.`)
138+
return
139+
}
140+
141+
throw error
142+
}
143+
131144
const command = new DescribeChangeSetCommand({
132145
ChangeSetName: changeSetName,
133146
StackName: stackName

packages/cdkConstructs/tests/changesets/checkDestructiveChanges.test.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,16 @@ vi.mock("@aws-sdk/client-cloudformation", () => {
4040
}
4141
}
4242

43-
return {CloudFormationClient, DescribeChangeSetCommand}
43+
class DescribeStacksCommand {
44+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
45+
input: any
46+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47+
constructor(input: any) {
48+
this.input = input
49+
}
50+
}
51+
52+
return {CloudFormationClient, DescribeChangeSetCommand, DescribeStacksCommand}
4453
})
4554

4655
const __filename = fileURLToPath(import.meta.url)
@@ -190,30 +199,42 @@ describe("checkDestructiveChanges", () => {
190199
describe("checkDestructiveChangeSet", () => {
191200
const logSpy = vi.spyOn(console, "log").mockImplementation(() => undefined)
192201
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => undefined)
202+
const mockStackExists = () => {
203+
mockCloudFormationSend.mockResolvedValueOnce({
204+
Stacks: [
205+
{
206+
StackName: "stack"
207+
}
208+
]
209+
})
210+
}
211+
193212
afterEach(() => {
194213
logSpy.mockReset()
195214
errorSpy.mockReset()
196215
})
197216

198217
test("logs success when no destructive changes are present", async () => {
218+
mockStackExists()
199219
mockCloudFormationSend.mockResolvedValueOnce(safeChangeSet)
200220

201221
await expect(checkDestructiveChangeSet("cs", "stack", "eu-west-2")).resolves.toBeUndefined()
202222

203-
expect(mockCloudFormationSend).toHaveBeenCalledTimes(1)
204-
const command = mockCloudFormationSend.mock.calls[0][0] as { input: { ChangeSetName: string; StackName: string } }
223+
expect(mockCloudFormationSend).toHaveBeenCalledTimes(2)
224+
const command = mockCloudFormationSend.mock.calls[1][0] as { input: { ChangeSetName: string; StackName: string } }
205225
expect(command.input).toEqual({ChangeSetName: "cs", StackName: "stack"})
206226
expect(logSpy).toHaveBeenCalledWith("Change set cs for stack stack has no destructive changes that are not waived.")
207227
expect(errorSpy).not.toHaveBeenCalled()
208228
})
209229

210230
test("logs details and throws when destructive changes exist", async () => {
231+
mockStackExists()
211232
mockCloudFormationSend.mockResolvedValueOnce(destructiveChangeSet)
212233

213234
await expect(checkDestructiveChangeSet("cs", "stack", "eu-west-2"))
214235
.rejects.toThrow("Change set cs contains destructive changes")
215236

216-
expect(mockCloudFormationSend).toHaveBeenCalledTimes(1)
237+
expect(mockCloudFormationSend).toHaveBeenCalledTimes(2)
217238
expect(logSpy).not.toHaveBeenCalled()
218239
expect(errorSpy).toHaveBeenCalledWith("Resources that require attention:")
219240
})
@@ -234,6 +255,7 @@ describe("checkDestructiveChangeSet", () => {
234255
}
235256
]
236257
}
258+
mockStackExists()
237259
mockCloudFormationSend.mockResolvedValueOnce(changeSet)
238260

239261
const allowedChanges: Array<AllowedDestructiveChange> = [
@@ -253,7 +275,7 @@ describe("checkDestructiveChangeSet", () => {
253275
await expect(checkDestructiveChangeSet("cs", "stack", "eu-west-2", allowedChanges))
254276
.resolves.toBeUndefined()
255277

256-
expect(mockCloudFormationSend).toHaveBeenCalledTimes(1)
278+
expect(mockCloudFormationSend).toHaveBeenCalledTimes(2)
257279
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Allowing destructive change ResourceToRemove"))
258280
expect(logSpy).toHaveBeenCalledWith("Change set cs for stack stack has no destructive changes that are not waived.")
259281
expect(errorSpy).not.toHaveBeenCalled()
@@ -275,6 +297,7 @@ describe("checkDestructiveChangeSet", () => {
275297
}
276298
]
277299
}
300+
mockStackExists()
278301
mockCloudFormationSend.mockResolvedValueOnce(changeSet)
279302

280303
const allowedChanges: Array<AllowedDestructiveChange> = [
@@ -315,6 +338,7 @@ describe("checkDestructiveChangeSet", () => {
315338
}
316339
]
317340
}
341+
mockStackExists()
318342
mockCloudFormationSend.mockResolvedValueOnce(changeSet)
319343

320344
const allowedChanges: Array<AllowedDestructiveChange> = [
@@ -336,4 +360,17 @@ describe("checkDestructiveChangeSet", () => {
336360

337361
expect(errorSpy).toHaveBeenCalledWith("Resources that require attention:")
338362
})
363+
364+
test("logs and exits without error when the stack does not exist", async () => {
365+
const stackMissingError = new Error("Stack with id stack does not exist")
366+
stackMissingError.name = "ValidationError"
367+
368+
mockCloudFormationSend.mockRejectedValueOnce(stackMissingError)
369+
370+
await expect(checkDestructiveChangeSet("cs", "stack", "eu-west-2")).resolves.toBeUndefined()
371+
372+
expect(mockCloudFormationSend).toHaveBeenCalledTimes(1)
373+
expect(logSpy).toHaveBeenCalledWith("Stack stack does not exist. Skipping destructive change check.")
374+
expect(errorSpy).not.toHaveBeenCalled()
375+
})
339376
})

0 commit comments

Comments
 (0)