rastack 0.0.41 → 0.0.42

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.
@@ -56,6 +56,7 @@ import {
56
56
  ghAvailable,
57
57
  gitRemoteUrl,
58
58
  loadConfig,
59
+ resolveDeployAsset,
59
60
  saveConfig,
60
61
  setRepoVariable,
61
62
  stackOutput,
@@ -209,13 +210,15 @@ function printPlan(cfg: DeployConfig): void {
209
210
  const withBucket = mergeConfig(cfg, {
210
211
  artifactsBucket: bucket ?? "<ArtifactsBucketName from bootstrap stack>",
211
212
  });
213
+ const bootstrapTemplate = resolveDeployAsset("bootstrap.yaml") ?? undefined;
214
+ const appTemplate = resolveDeployAsset("app.yaml") ?? undefined;
212
215
  console.log(`\n Deployment plan (${cfg.stackName} @ ${cfg.region})\n`);
213
216
  console.log(
214
217
  ` ── 1. Bootstrap stack (${bootstrapStackName(cfg)}) — run only if it does not exist ──`,
215
218
  );
216
- console.log("\n " + bootstrapStackCommand(cfg) + "\n");
219
+ console.log("\n " + bootstrapStackCommand(cfg, false, bootstrapTemplate) + "\n");
217
220
  console.log(" ── 2. Per-app backend (app.yaml) ──");
218
- console.log("\n " + deployStackCommand(withBucket) + "\n");
221
+ console.log("\n " + deployStackCommand(withBucket, appTemplate) + "\n");
219
222
  console.log(
220
223
  " ── 3. Wire these GitHub repo Variables from the stack Outputs ──",
221
224
  );
@@ -285,7 +288,7 @@ async function standUp(
285
288
  console.log("\n▸ Uploading the Lambda placeholder bundle");
286
289
  if (!uploadPlaceholder(artifactsBucket, cfg.region)) {
287
290
  console.error(
288
- " ✗ deploy/cloudformation/placeholder/bootstrap not found — cannot create the function.",
291
+ " ✗ Lambda placeholder bundle not found in the rastack package — cannot create the function.",
289
292
  );
290
293
  process.exit(1);
291
294
  }
@@ -295,9 +298,17 @@ async function standUp(
295
298
  artifactsBucket,
296
299
  templatesBucket: templatesBucket ?? undefined,
297
300
  });
301
+ const appTemplate = resolveDeployAsset("app.yaml");
302
+ if (!appTemplate) {
303
+ console.error(
304
+ " ✗ app.yaml template not found in the rastack package. Reinstall rastack\n" +
305
+ " (`npm i -g rastack`) or run from the framework repo.",
306
+ );
307
+ process.exit(1);
308
+ }
298
309
  console.log(`\n▸ Deploying ${cfg.stackName}`);
299
310
  try {
300
- awsRun(deployStackArgs(cfg));
311
+ awsRun(deployStackArgs(cfg, appTemplate));
301
312
  } catch (err) {
302
313
  console.error(
303
314
  `\n ✗ aws cloudformation deploy failed for ${cfg.stackName}.\n ${(err as Error).message}`,
@@ -372,8 +383,16 @@ function wireRepoVariables(cfg: DeployConfig, interactive: boolean): void {
372
383
 
373
384
  /** Deploy the bootstrap stack, retrying once against an existing OIDC provider. */
374
385
  function deployBootstrap(cfg: DeployConfig): void {
386
+ const template = resolveDeployAsset("bootstrap.yaml");
387
+ if (!template) {
388
+ console.error(
389
+ " ✗ bootstrap.yaml template not found in the rastack package. Reinstall\n" +
390
+ " rastack (`npm i -g rastack`) or run from the framework repo.",
391
+ );
392
+ process.exit(1);
393
+ }
375
394
  try {
376
- awsRun(bootstrapStackArgs(cfg));
395
+ awsRun(bootstrapStackArgs(cfg, false, template));
377
396
  } catch {
378
397
  // The most common cause is an account that already has a GitHub OIDC
379
398
  // provider (only one is allowed per URL). Retry telling the template to
@@ -382,7 +401,7 @@ function deployBootstrap(cfg: DeployConfig): void {
382
401
  " • retrying bootstrap, reusing the account's existing GitHub OIDC provider",
383
402
  );
384
403
  try {
385
- awsRun(bootstrapStackArgs(cfg, true));
404
+ awsRun(bootstrapStackArgs(cfg, true, template));
386
405
  } catch (err) {
387
406
  console.error(
388
407
  `\n ✗ bootstrap stack deploy failed.\n ${(err as Error).message}`,
@@ -243,6 +243,19 @@ describe("stack parameters + launch command", () => {
243
243
  "deploy",
244
244
  ]);
245
245
  });
246
+
247
+ it("accepts a template-file override (the package-resolved path)", () => {
248
+ // `init` runs in a consumer repo that carries no framework IaC, so it passes
249
+ // the path the template was resolved to inside the `rastack` package.
250
+ const cfg = base({ artifactsBucket: "art" });
251
+ const abs = "/opt/rastack/dist/templates/cloudformation/app.yaml";
252
+ expect(deployStackArgs(cfg, abs)).toContain(abs);
253
+ expect(deployStackCommand(cfg, abs)).toContain(`--template-file ${abs}`);
254
+ // Default is unchanged when no override is given.
255
+ expect(deployStackCommand(cfg)).toContain(
256
+ "--template-file deploy/cloudformation/app.yaml",
257
+ );
258
+ });
246
259
  });
247
260
 
248
261
  describe("bootstrap stack", () => {
@@ -281,6 +294,21 @@ describe("bootstrap stack", () => {
281
294
  expect(`aws ${bootstrapStackArgs(base()).join(" ")}`).toBe(cmd);
282
295
  });
283
296
 
297
+ it("accepts a template-file override (the package-resolved path)", () => {
298
+ const abs = "/opt/rastack/dist/templates/cloudformation/bootstrap.yaml";
299
+ expect(bootstrapStackArgs(base(), false, abs)).toContain(abs);
300
+ expect(bootstrapStackCommand(base(), true, abs)).toContain(
301
+ `--template-file ${abs}`,
302
+ );
303
+ // Reuse-OIDC + override compose without disturbing the default path.
304
+ expect(bootstrapStackArgs(base(), true, abs)).toContain(
305
+ "CreateOIDCProvider=false",
306
+ );
307
+ expect(bootstrapStackCommand(base())).toContain(
308
+ "--template-file deploy/cloudformation/bootstrap.yaml",
309
+ );
310
+ });
311
+
284
312
  it("validates only the account-level fields, not the per-app ones", () => {
285
313
  // A config with no `app` is fine for bootstrap — it never touches app.yaml.
286
314
  const cfg = normalizeConfig({
@@ -513,3 +541,28 @@ describe("scaffold", () => {
513
541
  expect(files.map((f) => f.path)).toEqual([CONFIG_PATH]);
514
542
  });
515
543
  });
544
+
545
+ describe("resolveDeployAsset — bundled template resolution", () => {
546
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
547
+ const { resolveDeployAsset } = require("../src/deploy/io");
548
+ const path = require("path");
549
+
550
+ it("resolves the framework templates to an existing file", () => {
551
+ for (const name of ["app.yaml", "bootstrap.yaml"]) {
552
+ const resolved = resolveDeployAsset(name);
553
+ expect(resolved).not.toBeNull();
554
+ expect(path.isAbsolute(resolved)).toBe(true);
555
+ expect(resolved.endsWith(name)).toBe(true);
556
+ }
557
+ });
558
+
559
+ it("resolves the Lambda placeholder bundle", () => {
560
+ const resolved = resolveDeployAsset(path.join("placeholder", "bootstrap"));
561
+ expect(resolved).not.toBeNull();
562
+ expect(resolved.endsWith(path.join("placeholder", "bootstrap"))).toBe(true);
563
+ });
564
+
565
+ it("returns null for an asset that does not exist", () => {
566
+ expect(resolveDeployAsset("does-not-exist.yaml")).toBeNull();
567
+ });
568
+ });