-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathapply.ts
153 lines (111 loc) · 4.1 KB
/
apply.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { flags } from "@oclif/command"
import chalk from "chalk"
import ux from "cli-ux"
import execa from "execa"
import open from "open"
import BaseInfrastructureCommand from "../BaseInfrastructureCommand"
import InfrastructureFactory from "../lib/infrastructures/InfrastructureFactory"
import environmentsManager from "../lib/environments"
import getNodeEnv from "../lib/environments/getNodeEnv"
/**
* Represents the "scaffold apply {environment}" command
* used to update the infrastructure of an environment.
*/
class Apply extends BaseInfrastructureCommand {
static args = [{
name: "environment",
required: true,
}]
static description = "update infrastructure for passed environment"
static flags = {
help: flags.help({
char: "h",
}),
sandbox: flags.boolean({
default: false,
}),
}
static strict = false
async run() {
const { args, flags } = this.parse(Apply)
await this.ensureAllRequirements()
const environment: string = args.environment
const infrastructurePath = await this.infrastructurePath()
if (!infrastructurePath) {
this.error("No infrastructures found.")
}
const infrastructurePackage = await this.infrastructurePackage(infrastructurePath)
if (!infrastructurePackage) {
this.error("Invalid scaffold.json file.")
}
const infrastructure = InfrastructureFactory.infrastructure(infrastructurePackage.type)
if (!infrastructure) {
this.error("Unknown infrastructure.")
}
const environments = await environmentsManager.findAll(infrastructurePath)
if (!environments.all.includes(environment)) {
this.error(`"${chalk.bold(environment)}" environment doesn't exist.`)
}
if (!flags.sandbox) {
if (!environments.configured.includes(environment)) {
this.error(`"${chalk.bold(environment)}" environment not configured. Run "${chalk.bold(chalk.cyan("scaffold") + " env:configure " + environment)}" first.`)
}
} else if (!environments.sandboxed.includes(environment)) {
this.error(`Sandbox for "${chalk.bold(environment)}" environment doesn't exist. Run "${chalk.bold(chalk.cyan("scaffold") + " sandbox:create " + environment)}" first.`)
}
const cdktfPath = this.cdktfPath(infrastructurePath)
const terraformPlanPath = await this.terraformPlanPath(infrastructurePath)
const terraformPath = BaseInfrastructureCommand.terraformBinaryPath()
ux.action.start("Synthesizing")
await execa(cdktfPath, ["synth"], {
cwd: infrastructurePath,
env: {
NODE_ENV: getNodeEnv(environment, flags.sandbox),
},
})
await execa(terraformPath, ["init", "-reconfigure"], {
cwd: terraformPlanPath,
})
const { stdout } = await execa(terraformPath, ["state", "pull"], {
cwd: terraformPlanPath,
})
const state = JSON.parse(stdout)
const isFirstCreation = state.serial === 0 && !state.resources.length
ux.action.stop()
this.log("")
// Remove ["node", "{path}", "apply", "{environment}"]
const argsToPassToTF = process.argv.slice(4).filter(arg => !["--sandbox", "-sandbox"].includes(arg))
const terraformApply = execa(terraformPath, ["apply"].concat(argsToPassToTF), {
cwd: terraformPlanPath,
})
terraformApply.stderr.pipe(process.stderr)
terraformApply.stdout.pipe(process.stdout)
process.stdin.pipe(terraformApply.stdin)
try {
await terraformApply
if (isFirstCreation && (environments.all.length + environments.sandboxed.length) === 1) {
const afterInstallURL = infrastructure.afterInstallURL()
let urlDisplayed = false
const showUrl = () => {
if (!urlDisplayed) {
ux.warn(`\nCannot open browser, visit\n${chalk.blueBright(afterInstallURL)}`)
}
urlDisplayed = true
}
const cp = await open(afterInstallURL)
cp.on("error", err => {
ux.warn(`\n${err}`)
showUrl()
})
cp.on("close", code => {
if (code !== 0) {
showUrl()
}
})
}
} catch (error) {
this.exit(1)
}
}
}
export default Apply