Skip to content

Commit 94bd3fc

Browse files
committed
feat: allow stateless stack destroy
This update adds new features to the destroy script to allow stack destruction without an existing build state and to make it more robust. Changes are: + Added a --default-projects flag to use the paths to the default pulumi projects when calling destroy + Added a -s flag to set the stack name explicitly + Added a retry loop in the event of a timeout error (such as might happen for lamba@edge) + Added a -f and --force flag which will run pulumi cancel before trying to start a destroy operation.
1 parent 3ff7331 commit 94bd3fc

File tree

1 file changed

+76
-12
lines changed

1 file changed

+76
-12
lines changed

bin/destroy.ts

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@
22

33
import * as path from 'path'
44
import { realpathSync } from 'fs'
5-
import { pathToFileURL } from 'url'
6-
import { spawnSync } from 'child_process'
5+
import { fileURLToPath, pathToFileURL } from 'url'
6+
import { spawnSync, SpawnSyncReturns } from 'child_process'
77
import { createRequire } from 'node:module'
88

99
import parseArgs from 'minimist'
1010

1111
import { AWSAdapterProps } from '../adapter'
1212

13+
const __dirname = fileURLToPath(new URL('.', import.meta.url))
14+
1315
export async function main(args: string[]): Promise<void> {
14-
let artifactPath = 'build'
16+
let pulumiPaths: string[] | undefined
17+
let stackName: string | undefined
18+
1519
const argv = parseArgs(args.slice(2))
20+
21+
let artifactPath = 'build'
22+
1623
if (argv._.length) {
1724
artifactPath = argv._[0]
1825
}
@@ -25,24 +32,81 @@ export async function main(args: string[]): Promise<void> {
2532

2633
try {
2734
adapterProps = require(propsPath)
35+
pulumiPaths = adapterProps.pulumiPaths
36+
stackName = adapterProps.stackName
2837
} catch (error: any) {
29-
if (error.message.includes('Cannot find module')) {
30-
return
31-
} else {
38+
if (!error.message.includes('Cannot find module')) {
3239
throw error
3340
}
3441
}
3542

36-
for (const pulumiPath of adapterProps.pulumiPaths!) {
37-
spawnSync(
38-
'pulumi',
39-
['destroy', '-f', '-s', adapterProps.stackName!, '-y', '--refresh'],
40-
{
43+
if ('default-projects' in argv) {
44+
const serverPath = path.resolve(__dirname, '..', 'stacks', 'server')
45+
const mainPath = path.resolve(__dirname, '..', 'stacks', 'main')
46+
pulumiPaths = [serverPath, mainPath]
47+
}
48+
49+
if ('s' in argv) {
50+
stackName = argv.s
51+
}
52+
53+
let abort: boolean = false
54+
55+
if (pulumiPaths === undefined) {
56+
console.log('Paths to pulumi projects could not be determined.')
57+
abort = true
58+
}
59+
60+
if (pulumiPaths === undefined) {
61+
console.log('Stack name could not be determined')
62+
abort = true
63+
}
64+
65+
if (abort) {
66+
console.log('Aborting')
67+
return
68+
}
69+
70+
const maxRetries: number = 3
71+
let retries: number
72+
let exitCode: number
73+
let comRes: SpawnSyncReturns<Buffer>
74+
75+
for (const pulumiPath of pulumiPaths!) {
76+
retries = 0
77+
exitCode = 1
78+
79+
if ('f' in argv || 'force' in argv) {
80+
spawnSync('pulumi', ['cancel', '-s', stackName!, '-y'], {
4181
cwd: pulumiPath,
4282
stdio: [process.stdin, process.stdout, process.stderr],
4383
env: process.env,
84+
})
85+
}
86+
87+
while (exitCode !== 0 && retries !== maxRetries) {
88+
if (retries > 0) {
89+
console.log(`Retry ${retries} of ${maxRetries}`)
90+
}
91+
92+
comRes = spawnSync(
93+
'pulumi',
94+
['destroy', '-f', '-s', stackName!, '-y', '--refresh'],
95+
{
96+
cwd: pulumiPath,
97+
stdio: [process.stdin, process.stdout, process.stderr],
98+
env: process.env,
99+
}
100+
)
101+
102+
if (comRes.status === null) {
103+
exitCode = 0
104+
} else {
105+
exitCode = comRes.status
44106
}
45-
)
107+
108+
retries += 1
109+
}
46110
}
47111
}
48112

0 commit comments

Comments
 (0)