rastack 0.0.35 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/deploy/config.d.ts +33 -5
- package/dist/deploy/config.js +98 -24
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/index.js +1 -0
- package/dist/deploy/io.d.ts +19 -0
- package/dist/deploy/io.js +81 -0
- package/dist/deploy/zip.d.ts +24 -0
- package/dist/deploy/zip.js +95 -0
- package/dist/rastack-ci.js +1 -1
- package/dist/rastack-init.d.ts +18 -7
- package/dist/rastack-init.js +187 -18
- package/dist/rastack-update.d.ts +18 -0
- package/dist/rastack-update.js +139 -0
- package/dist/rastack.d.ts +3 -2
- package/dist/rastack.js +16 -8
- package/dist/update.d.ts +48 -0
- package/dist/update.js +110 -0
- package/package.json +1 -1
- package/src/deploy/config.ts +126 -22
- package/src/deploy/index.ts +1 -0
- package/src/deploy/io.ts +88 -1
- package/src/deploy/zip.ts +109 -0
- package/src/rastack-ci.ts +1 -1
- package/src/rastack-init.ts +271 -21
- package/src/rastack-update.ts +124 -0
- package/src/rastack.ts +16 -8
- package/src/update.ts +114 -0
- package/test/deploy.spec.ts +100 -12
- package/test/update.spec.ts +95 -0
- package/dist/rastack-deploy.d.ts +0 -20
- package/dist/rastack-deploy.js +0 -196
- package/src/rastack-deploy.ts +0 -257
package/test/deploy.spec.ts
CHANGED
|
@@ -4,8 +4,14 @@ import {
|
|
|
4
4
|
buildSteps,
|
|
5
5
|
checkSteps,
|
|
6
6
|
ciPlan,
|
|
7
|
+
deployStackArgs,
|
|
7
8
|
deployStackCommand,
|
|
8
9
|
deploySteps,
|
|
10
|
+
bootstrapStackArgs,
|
|
11
|
+
bootstrapStackCommand,
|
|
12
|
+
bootstrapStackName,
|
|
13
|
+
bootstrapStackParameters,
|
|
14
|
+
APP_STACK_OUTPUTS,
|
|
9
15
|
lambdaEnv,
|
|
10
16
|
mergeConfig,
|
|
11
17
|
normalizeConfig,
|
|
@@ -13,8 +19,8 @@ import {
|
|
|
13
19
|
repoVariables,
|
|
14
20
|
scaffoldFiles,
|
|
15
21
|
stackParameters,
|
|
16
|
-
templateUrl,
|
|
17
22
|
validateConfig,
|
|
23
|
+
zipStore,
|
|
18
24
|
renderCiWorkflow,
|
|
19
25
|
renderDeployWorkflow,
|
|
20
26
|
CI_WORKFLOW_PATH,
|
|
@@ -180,25 +186,107 @@ describe("stack parameters + launch command", () => {
|
|
|
180
186
|
);
|
|
181
187
|
});
|
|
182
188
|
|
|
183
|
-
it("
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it("launches by URL when hosted, else from the in-repo template", () => {
|
|
189
|
+
it("always launches from the in-repo --template-file (deploy takes no URL)", () => {
|
|
190
|
+
// `aws cloudformation deploy` accepts ONLY `--template-file`; `--template-url`
|
|
191
|
+
// is exclusive to create-stack/update-stack and makes deploy reject the
|
|
192
|
+
// command. Even with a known templates bucket, the local file is used.
|
|
191
193
|
const hosted = deployStackCommand(
|
|
192
194
|
base({ templatesBucket: "tpl", artifactsBucket: "art" }),
|
|
193
195
|
);
|
|
194
|
-
expect(hosted).toContain(
|
|
195
|
-
|
|
196
|
-
);
|
|
196
|
+
expect(hosted).toContain("--template-file deploy/cloudformation/app.yaml");
|
|
197
|
+
expect(hosted).not.toContain("--template-url");
|
|
197
198
|
expect(hosted).toContain("--stack-name rastack-airline");
|
|
198
199
|
expect(hosted).toContain("ArtifactsBucket=art");
|
|
199
200
|
|
|
200
201
|
const local = deployStackCommand(base());
|
|
201
202
|
expect(local).toContain("--template-file deploy/cloudformation/app.yaml");
|
|
203
|
+
expect(local).not.toContain("--template-url");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("emits ONE line (PowerShell-safe — no backslash continuations)", () => {
|
|
207
|
+
// A `\`-continued command is bash-only; pasted into PowerShell each `--flag`
|
|
208
|
+
// becomes its own statement and errors. Keep it to a single line.
|
|
209
|
+
const cmd = deployStackCommand(base({ artifactsBucket: "art" }));
|
|
210
|
+
expect(cmd).not.toContain("\\");
|
|
211
|
+
expect(cmd.split("\n")).toHaveLength(1);
|
|
212
|
+
expect(cmd.startsWith("aws cloudformation deploy ")).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("deployStackArgs is the argv the printed command joins", () => {
|
|
216
|
+
const cfg = base({ artifactsBucket: "art" });
|
|
217
|
+
expect(`aws ${deployStackArgs(cfg).join(" ")}`).toBe(
|
|
218
|
+
deployStackCommand(cfg),
|
|
219
|
+
);
|
|
220
|
+
expect(deployStackArgs(cfg).slice(0, 2)).toEqual([
|
|
221
|
+
"cloudformation",
|
|
222
|
+
"deploy",
|
|
223
|
+
]);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe("bootstrap stack", () => {
|
|
228
|
+
it("derives the bootstrap stack name from the prefix", () => {
|
|
229
|
+
expect(bootstrapStackName(base())).toBe("rastack-bootstrap");
|
|
230
|
+
expect(bootstrapStackName(base({ namePrefix: "acme" }))).toBe(
|
|
231
|
+
"acme-bootstrap",
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("passes the publisher repo coordinates as parameters", () => {
|
|
236
|
+
const params = bootstrapStackParameters(base());
|
|
237
|
+
const map = Object.fromEntries(params.map((p) => [p.key, p.value]));
|
|
238
|
+
expect(map.NamePrefix).toBe("rastack");
|
|
239
|
+
expect(map.GitHubOwner).toBe("theserverkid");
|
|
240
|
+
expect(map.PublisherRepo).toBe("reactapistack-demo");
|
|
241
|
+
expect(map.PublisherBranch).toBe("master");
|
|
242
|
+
expect(map.CreateOIDCProvider).toBeUndefined();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("adds CreateOIDCProvider=false when reusing an existing provider", () => {
|
|
246
|
+
const params = bootstrapStackParameters(base(), true);
|
|
247
|
+
expect(params.find((p) => p.key === "CreateOIDCProvider")!.value).toBe(
|
|
248
|
+
"false",
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("builds a single-line command from the bootstrap template", () => {
|
|
253
|
+
const cmd = bootstrapStackCommand(base());
|
|
254
|
+
expect(cmd).not.toContain("\\");
|
|
255
|
+
expect(cmd.split("\n")).toHaveLength(1);
|
|
256
|
+
expect(cmd).toContain(
|
|
257
|
+
"--template-file deploy/cloudformation/bootstrap.yaml",
|
|
258
|
+
);
|
|
259
|
+
expect(cmd).toContain("--stack-name rastack-bootstrap");
|
|
260
|
+
expect(`aws ${bootstrapStackArgs(base()).join(" ")}`).toBe(cmd);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("app stack outputs map", () => {
|
|
265
|
+
it("maps each stack Output key to a DeployOutputs field", () => {
|
|
266
|
+
const keys = APP_STACK_OUTPUTS.map((o) => o.key);
|
|
267
|
+
expect(keys).toContain("FunctionName");
|
|
268
|
+
expect(keys).toContain("ApiUrl");
|
|
269
|
+
expect(keys).toContain("DeployRoleArn");
|
|
270
|
+
expect(APP_STACK_OUTPUTS.find((o) => o.key === "FunctionName")!.field).toBe(
|
|
271
|
+
"functionName",
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe("zipStore — placeholder packaging", () => {
|
|
277
|
+
it("produces a valid, deterministic STORE archive", () => {
|
|
278
|
+
const data = Buffer.from("#!/bin/sh\necho placeholder\n");
|
|
279
|
+
const a = zipStore([{ name: "bootstrap", data, mode: 0o755 }]);
|
|
280
|
+
const b = zipStore([{ name: "bootstrap", data, mode: 0o755 }]);
|
|
281
|
+
// Deterministic (fixed DOS timestamp) → idempotent uploads.
|
|
282
|
+
expect(a.equals(b)).toBe(true);
|
|
283
|
+
// Local file header + End-of-central-directory signatures.
|
|
284
|
+
expect(a.readUInt32LE(0)).toBe(0x04034b50);
|
|
285
|
+
expect(a.readUInt32LE(a.length - 22)).toBe(0x06054b50);
|
|
286
|
+
// One entry recorded in the EOCD.
|
|
287
|
+
expect(a.readUInt16LE(a.length - 12)).toBe(1);
|
|
288
|
+
// STORE method → the file bytes appear verbatim after the header + name.
|
|
289
|
+
expect(a.includes(data)).toBe(true);
|
|
202
290
|
});
|
|
203
291
|
});
|
|
204
292
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compareSemver,
|
|
3
|
+
globalPrefixFromPackageDir,
|
|
4
|
+
installSpec,
|
|
5
|
+
npmInstallArgs,
|
|
6
|
+
parseUpdateFlags,
|
|
7
|
+
updateAvailable,
|
|
8
|
+
} from "../src/update";
|
|
9
|
+
|
|
10
|
+
describe("update — flag parsing", () => {
|
|
11
|
+
it("defaults to a latest, non-check, non-dry-run update", () => {
|
|
12
|
+
expect(parseUpdateFlags([])).toEqual({
|
|
13
|
+
version: "latest",
|
|
14
|
+
check: false,
|
|
15
|
+
dryRun: false,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("takes a bare positional as the target version", () => {
|
|
20
|
+
expect(parseUpdateFlags(["0.0.40"]).version).toBe("0.0.40");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("accepts --version / --to and the check + dry-run flags", () => {
|
|
24
|
+
expect(parseUpdateFlags(["--version", "1.2.3"]).version).toBe("1.2.3");
|
|
25
|
+
expect(parseUpdateFlags(["--to", "1.2.3"]).version).toBe("1.2.3");
|
|
26
|
+
expect(parseUpdateFlags(["--check"]).check).toBe(true);
|
|
27
|
+
expect(parseUpdateFlags(["--dry-run"]).dryRun).toBe(true);
|
|
28
|
+
expect(parseUpdateFlags(["--print"]).dryRun).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("update — npm spec + args", () => {
|
|
33
|
+
it("installs bare `rastack` for latest, pinned otherwise", () => {
|
|
34
|
+
expect(installSpec("latest")).toBe("rastack");
|
|
35
|
+
expect(installSpec("")).toBe("rastack");
|
|
36
|
+
expect(installSpec("0.0.40")).toBe("rastack@0.0.40");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("builds a quiet global install argv", () => {
|
|
40
|
+
expect(npmInstallArgs("latest")).toEqual([
|
|
41
|
+
"install",
|
|
42
|
+
"-g",
|
|
43
|
+
"rastack",
|
|
44
|
+
"--no-fund",
|
|
45
|
+
"--no-audit",
|
|
46
|
+
"--loglevel=error",
|
|
47
|
+
]);
|
|
48
|
+
expect(npmInstallArgs("0.0.40")[2]).toBe("rastack@0.0.40");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("update — global prefix derivation", () => {
|
|
53
|
+
it("derives the per-user prefix from a POSIX global install", () => {
|
|
54
|
+
expect(
|
|
55
|
+
globalPrefixFromPackageDir("/home/me/.rastack/lib/node_modules/rastack"),
|
|
56
|
+
).toBe("/home/me/.rastack");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("derives the prefix from a Windows global install", () => {
|
|
60
|
+
expect(
|
|
61
|
+
globalPrefixFromPackageDir(
|
|
62
|
+
"C:\\Users\\me\\.rastack\\node_modules\\rastack",
|
|
63
|
+
),
|
|
64
|
+
).toBe("C:\\Users\\me\\.rastack");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("prefers the lib/node_modules layout when both could match", () => {
|
|
68
|
+
// POSIX path also contains `/node_modules/` — the lib form must win so the
|
|
69
|
+
// prefix is the install root, not `<root>/lib`.
|
|
70
|
+
expect(
|
|
71
|
+
globalPrefixFromPackageDir("/opt/tools/lib/node_modules/rastack"),
|
|
72
|
+
).toBe("/opt/tools");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("returns null for a source checkout (not under node_modules)", () => {
|
|
76
|
+
expect(
|
|
77
|
+
globalPrefixFromPackageDir("/home/me/src/reactapistack/tools"),
|
|
78
|
+
).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("update — semver comparison", () => {
|
|
83
|
+
it("orders versions numerically, ignoring a `v` prefix and pre-release", () => {
|
|
84
|
+
expect(compareSemver("0.0.9", "0.0.10")).toBe(-1);
|
|
85
|
+
expect(compareSemver("v1.2.0", "1.2.0")).toBe(0);
|
|
86
|
+
expect(compareSemver("2.0.0", "1.9.9")).toBe(1);
|
|
87
|
+
expect(compareSemver("1.0.0-beta", "1.0.0")).toBe(0);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("reports whether an update is available", () => {
|
|
91
|
+
expect(updateAvailable("0.0.33", "0.0.40")).toBe(true);
|
|
92
|
+
expect(updateAvailable("0.0.40", "0.0.40")).toBe(false);
|
|
93
|
+
expect(updateAvailable("0.1.0", "0.0.40")).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
package/dist/rastack-deploy.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* `rastack deploy` — configure a repo's serverless deployment.
|
|
4
|
-
*
|
|
5
|
-
* rastack deploy [--app <slug>] [--region <r>] [--owner <o>] [--repo <r>]
|
|
6
|
-
* [--branch <b>] [--namespace <n>] [--templates-bucket <b>]
|
|
7
|
-
* [--artifacts-bucket <b>] [--arch arm64|x86_64]
|
|
8
|
-
* [--print] [--run] [--yes]
|
|
9
|
-
*
|
|
10
|
-
* Writes/updates `.rastack/deploy.json` (creating it if `rastack init` has not
|
|
11
|
-
* run) and prints exactly how to stand the app up: the one-time
|
|
12
|
-
* `aws cloudformation deploy` that creates all infrastructure, the GitHub repo
|
|
13
|
-
* Variables CI reads, and the Lambda's runtime env. Infra is created once by a
|
|
14
|
-
* human — this command *configures* that step, it does not silently mutate the
|
|
15
|
-
* cloud. `--run` executes the launch command for you; `--print` is
|
|
16
|
-
* non-interactive (config as-is).
|
|
17
|
-
*
|
|
18
|
-
* The recurring code deploy is CI's job (`rastack ci deploy`), not this command.
|
|
19
|
-
*/
|
|
20
|
-
export {};
|
package/dist/rastack-deploy.js
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/**
|
|
4
|
-
* `rastack deploy` — configure a repo's serverless deployment.
|
|
5
|
-
*
|
|
6
|
-
* rastack deploy [--app <slug>] [--region <r>] [--owner <o>] [--repo <r>]
|
|
7
|
-
* [--branch <b>] [--namespace <n>] [--templates-bucket <b>]
|
|
8
|
-
* [--artifacts-bucket <b>] [--arch arm64|x86_64]
|
|
9
|
-
* [--print] [--run] [--yes]
|
|
10
|
-
*
|
|
11
|
-
* Writes/updates `.rastack/deploy.json` (creating it if `rastack init` has not
|
|
12
|
-
* run) and prints exactly how to stand the app up: the one-time
|
|
13
|
-
* `aws cloudformation deploy` that creates all infrastructure, the GitHub repo
|
|
14
|
-
* Variables CI reads, and the Lambda's runtime env. Infra is created once by a
|
|
15
|
-
* human — this command *configures* that step, it does not silently mutate the
|
|
16
|
-
* cloud. `--run` executes the launch command for you; `--print` is
|
|
17
|
-
* non-interactive (config as-is).
|
|
18
|
-
*
|
|
19
|
-
* The recurring code deploy is CI's job (`rastack ci deploy`), not this command.
|
|
20
|
-
*/
|
|
21
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
const child_process_1 = require("child_process");
|
|
23
|
-
const config_1 = require("./deploy/config");
|
|
24
|
-
const io_1 = require("./deploy/io");
|
|
25
|
-
function parseFlags(argv) {
|
|
26
|
-
const patch = { github: {}, lambda: {} };
|
|
27
|
-
let print = false;
|
|
28
|
-
let run = false;
|
|
29
|
-
let nonInteractive = false;
|
|
30
|
-
for (let i = 0; i < argv.length; i++) {
|
|
31
|
-
const a = argv[i];
|
|
32
|
-
const next = () => argv[++i] ?? "";
|
|
33
|
-
switch (a) {
|
|
34
|
-
case "--app":
|
|
35
|
-
patch.app = next();
|
|
36
|
-
break;
|
|
37
|
-
case "--region":
|
|
38
|
-
patch.region = next();
|
|
39
|
-
break;
|
|
40
|
-
case "--owner":
|
|
41
|
-
patch.github.owner = next();
|
|
42
|
-
break;
|
|
43
|
-
case "--repo":
|
|
44
|
-
patch.github.repo = next();
|
|
45
|
-
break;
|
|
46
|
-
case "--branch":
|
|
47
|
-
patch.github.branch = next();
|
|
48
|
-
break;
|
|
49
|
-
case "--prefix":
|
|
50
|
-
patch.namePrefix = next();
|
|
51
|
-
break;
|
|
52
|
-
case "--namespace":
|
|
53
|
-
patch.namespace = next();
|
|
54
|
-
break;
|
|
55
|
-
case "--stack-name":
|
|
56
|
-
patch.stackName = next();
|
|
57
|
-
break;
|
|
58
|
-
case "--templates-bucket":
|
|
59
|
-
patch.templatesBucket = next();
|
|
60
|
-
break;
|
|
61
|
-
case "--artifacts-bucket":
|
|
62
|
-
patch.artifactsBucket = next();
|
|
63
|
-
break;
|
|
64
|
-
case "--arch":
|
|
65
|
-
patch.lambda.arch = next();
|
|
66
|
-
break;
|
|
67
|
-
case "--print":
|
|
68
|
-
print = true;
|
|
69
|
-
nonInteractive = true;
|
|
70
|
-
break;
|
|
71
|
-
case "--run":
|
|
72
|
-
run = true;
|
|
73
|
-
break;
|
|
74
|
-
case "--yes":
|
|
75
|
-
case "-y":
|
|
76
|
-
case "--non-interactive":
|
|
77
|
-
nonInteractive = true;
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
if (a.startsWith("-")) {
|
|
81
|
-
console.error(`Unknown flag: ${a}`);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return { patch, print, run, nonInteractive };
|
|
87
|
-
}
|
|
88
|
-
function seedConfig(patch) {
|
|
89
|
-
const existing = (0, io_1.loadConfig)();
|
|
90
|
-
return existing ? (0, config_1.mergeConfig)(existing, patch) : (0, config_1.normalizeConfig)(patch);
|
|
91
|
-
}
|
|
92
|
-
async function promptMissing(cfg) {
|
|
93
|
-
return (0, io_1.withPrompt)(async (rl) => {
|
|
94
|
-
const app = await (0, io_1.ask)(rl, "App slug", cfg.app);
|
|
95
|
-
const owner = await (0, io_1.ask)(rl, "GitHub owner", cfg.github.owner);
|
|
96
|
-
const repo = await (0, io_1.ask)(rl, "GitHub repo", cfg.github.repo);
|
|
97
|
-
const branch = await (0, io_1.ask)(rl, "Deploy branch", cfg.github.branch);
|
|
98
|
-
const region = await (0, io_1.ask)(rl, "AWS region", cfg.region);
|
|
99
|
-
const namespace = await (0, io_1.ask)(rl, "Iceberg namespace", cfg.namespace);
|
|
100
|
-
const artifactsBucket = await (0, io_1.ask)(rl, "Artifacts bucket (from bootstrap stack)", cfg.artifactsBucket ?? "");
|
|
101
|
-
const templatesBucket = await (0, io_1.ask)(rl, "Templates bucket (from bootstrap stack, optional)", cfg.templatesBucket ?? "");
|
|
102
|
-
return (0, config_1.mergeConfig)(cfg, {
|
|
103
|
-
app,
|
|
104
|
-
region,
|
|
105
|
-
namespace,
|
|
106
|
-
artifactsBucket,
|
|
107
|
-
templatesBucket,
|
|
108
|
-
github: { owner, repo, branch },
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
/** Pad a list of `Key=Value` rows into an aligned table. */
|
|
113
|
-
function table(rows) {
|
|
114
|
-
const width = Math.max(0, ...rows.map((r) => r.key.length));
|
|
115
|
-
return rows.map((r) => ` ${r.key.padEnd(width)} ${r.value}`).join("\n");
|
|
116
|
-
}
|
|
117
|
-
function printSummary(cfg) {
|
|
118
|
-
const src = (0, config_1.templateUrl)(cfg);
|
|
119
|
-
console.log(`\n Deployment config (${cfg.stackName} @ ${cfg.region})\n`);
|
|
120
|
-
console.log(" ── 1. Create the infrastructure (once, by a human) ──");
|
|
121
|
-
if (!cfg.artifactsBucket) {
|
|
122
|
-
console.log(" ⚠ artifactsBucket is unset — app.yaml requires it. Run the bootstrap\n" +
|
|
123
|
-
" stack first, then set --artifacts-bucket (its ArtifactsBucketName output).");
|
|
124
|
-
}
|
|
125
|
-
if (!src) {
|
|
126
|
-
console.log(" (launching from the in-repo template; set --templates-bucket to launch\n" +
|
|
127
|
-
" the hosted app.yaml by URL instead)");
|
|
128
|
-
}
|
|
129
|
-
console.log("\n" + (0, config_1.deployStackCommand)(cfg) + "\n");
|
|
130
|
-
console.log(" ── 2. Wire the GitHub repo Variables (from the stack Outputs) ──");
|
|
131
|
-
console.log(table((0, config_1.repoVariables)(cfg).map((v) => ({
|
|
132
|
-
key: v.name,
|
|
133
|
-
value: v.value || `<${v.from}>`,
|
|
134
|
-
}))));
|
|
135
|
-
console.log("\n ── 3. The Lambda runtime env (set by the stack) ──");
|
|
136
|
-
console.log(table((0, config_1.lambdaEnv)(cfg)));
|
|
137
|
-
console.log(`\n ── 4. Then every push to ${cfg.github.branch} runs \`rastack ci deploy\`. ──\n`);
|
|
138
|
-
}
|
|
139
|
-
function runLaunch(cfg) {
|
|
140
|
-
const params = (0, config_1.stackParameters)(cfg).map((p) => `${p.key}=${p.value}`);
|
|
141
|
-
const src = (0, config_1.templateUrl)(cfg);
|
|
142
|
-
const args = [
|
|
143
|
-
"cloudformation",
|
|
144
|
-
"deploy",
|
|
145
|
-
...(src
|
|
146
|
-
? ["--template-url", src]
|
|
147
|
-
: ["--template-file", "deploy/cloudformation/app.yaml"]),
|
|
148
|
-
"--stack-name",
|
|
149
|
-
cfg.stackName,
|
|
150
|
-
"--capabilities",
|
|
151
|
-
"CAPABILITY_NAMED_IAM",
|
|
152
|
-
"--region",
|
|
153
|
-
cfg.region,
|
|
154
|
-
"--parameter-overrides",
|
|
155
|
-
...params,
|
|
156
|
-
];
|
|
157
|
-
console.log(`\n ▸ aws ${args.join(" ")}\n`);
|
|
158
|
-
try {
|
|
159
|
-
// Runs the developer's own AWS CLI with args built from their config — no
|
|
160
|
-
// untrusted input, and `execFileSync` (no shell) avoids any injection.
|
|
161
|
-
(0, child_process_1.execFileSync)("aws", args, { stdio: "inherit" });
|
|
162
|
-
}
|
|
163
|
-
catch (err) {
|
|
164
|
-
console.error(`\n ✗ aws cloudformation deploy failed. Is the AWS CLI installed and are` +
|
|
165
|
-
` your credentials configured?\n ${err.message}`);
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
async function main(argv) {
|
|
170
|
-
const flags = parseFlags(argv);
|
|
171
|
-
let cfg = seedConfig(flags.patch);
|
|
172
|
-
if ((0, io_1.canPrompt)(flags.nonInteractive)) {
|
|
173
|
-
console.log("\n rastack deploy — configure the serverless deployment\n");
|
|
174
|
-
cfg = await promptMissing(cfg);
|
|
175
|
-
}
|
|
176
|
-
const errors = (0, config_1.validateConfig)(cfg);
|
|
177
|
-
if (errors.length) {
|
|
178
|
-
for (const e of errors)
|
|
179
|
-
console.error(` ✗ ${e}`);
|
|
180
|
-
console.error(`\n ${errors.length} problem(s) — fix the config and re-run.`);
|
|
181
|
-
process.exit(1);
|
|
182
|
-
}
|
|
183
|
-
if (!flags.print) {
|
|
184
|
-
const file = (0, io_1.saveConfig)(cfg);
|
|
185
|
-
console.log(` ✓ saved ${file}`);
|
|
186
|
-
}
|
|
187
|
-
printSummary(cfg);
|
|
188
|
-
if (flags.run)
|
|
189
|
-
runLaunch(cfg);
|
|
190
|
-
}
|
|
191
|
-
if (require.main === module) {
|
|
192
|
-
main(process.argv.slice(2)).catch((err) => {
|
|
193
|
-
console.error(` ✗ ${err.message}`);
|
|
194
|
-
process.exit(1);
|
|
195
|
-
});
|
|
196
|
-
}
|