@reventlessdev/reventless-aws 3.0.0-alpha.372 → 3.0.0-alpha.374

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 CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.374 (2026-10-06)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/reventless-aws
9
+
10
+
11
+
12
+
13
+
14
+ # 3.0.0-alpha.373 (2026-10-05)
15
+
16
+ ### Bug Fixes
17
+
18
+ * **deploy:** the bake waits for a review's plugins, and never follows a cancelled deploy ([84bdfbd](https://github.com/ReventlessDev/reventless-core/commit/84bdfbd13a892ceb9741a573e7928328e45f9d79))
19
+
20
+
6
21
  # 3.0.0-alpha.372 (2026-10-05)
7
22
 
8
23
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-aws",
3
- "version": "3.0.0-alpha.372",
3
+ "version": "3.0.0-alpha.374",
4
4
  "description": "AWS adapters for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -22,19 +22,19 @@
22
22
  "sury": "11.0.0",
23
23
  "uuid": "^13.0.0",
24
24
  "yaml": "^2.8.3",
25
- "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.28",
25
+ "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.29",
26
26
  "@reventlessdev/rescript-jest": "1.0.0-alpha.11",
27
- "@reventlessdev/rescript-node": "2.0.0-alpha.20",
27
+ "@reventlessdev/rescript-node": "2.0.0-alpha.21",
28
+ "@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.24",
28
29
  "@reventlessdev/rescript-effect": "0.1.0-alpha.34",
29
- "@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.23",
30
30
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.23",
31
31
  "@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
32
32
  "@reventlessdev/rescript-web": "1.0.0-alpha.7",
33
- "@reventlessdev/reventless-core": "3.0.0-alpha.287",
34
- "@reventlessdev/reventless-infra": "3.0.0-alpha.185",
35
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.151",
33
+ "@reventlessdev/reventless-core": "3.0.0-alpha.288",
34
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.186",
35
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.158",
36
36
  "@reventlessdev/reventless-interop": "3.0.0-alpha.39",
37
- "@reventlessdev/reventless-spec": "3.0.0-alpha.157"
37
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.152"
38
38
  },
39
39
  "devDependencies": {
40
40
  "rescript": "12.3.1",
@@ -27,21 +27,23 @@ type args = {
27
27
  manifest: option<string>,
28
28
  stack: option<string>,
29
29
  since: option<string>,
30
+ review: bool,
30
31
  help: bool,
31
32
  }
32
33
 
33
34
  let parseArgs = (argv: array<string>): result<args, string> =>
34
- Reventless.CliArgs.parse(~strings=["manifest", "stack", "since"], argv)
35
+ Reventless.CliArgs.parse(~strings=["manifest", "stack", "since"], ~bools=["review"], argv)
35
36
  ->Result.flatMap(Reventless.CliArgs.noPositionals)
36
37
  ->Result.map(a => {
37
38
  manifest: a->Reventless.CliArgs.string("manifest"),
38
39
  stack: a->Reventless.CliArgs.string("stack"),
39
40
  since: a->Reventless.CliArgs.string("since")->Option.flatMap(v => v == "" ? None : Some(v)),
41
+ review: a->Reventless.CliArgs.bool("review"),
40
42
  help: a->Reventless.CliArgs.help,
41
43
  })
42
44
 
43
45
  let usage = `
44
- Usage: bake-manifest [--manifest <path>] [--stack <name>] [--since <instant>]
46
+ Usage: bake-manifest [--manifest <path>] [--stack <name>] [--since <instant>] [--review]
45
47
 
46
48
  Bake the component manifest of a deployed platform.
47
49
 
@@ -51,6 +53,9 @@ Bake the component manifest of a deployed platform.
51
53
  platform's folder.
52
54
  --since <instant> When this deploy started (ISO 8601). Lets the report tell a
53
55
  plugin that re-registered from one that was unchanged.
56
+ --review The stack is a pull request's review environment. Its stacks'
57
+ settings are not in this checkout, so every plugin with a
58
+ review stack is waited for, not only those with a file here.
54
59
 
55
60
  Reads the bake function from the platform stack and each plugin's structure key
56
61
  from its stack, then asks the function to bake — again every
@@ -61,6 +66,17 @@ waiting, so that stops the run at once.
61
66
 
62
67
  // ── What the stacks say ──────────────────────────────────────────────────────
63
68
 
69
+ /** The plugins whose registration the bake waits for. A stack with no settings
70
+ file here was never deployed, except in a review environment, whose settings
71
+ exist only in the runner that created it: there it is every plugin with a
72
+ review stack. */
73
+ let pluginsToRead = (
74
+ plugins: array<DeployManifest.project>,
75
+ ~stack: string,
76
+ ~review: bool,
77
+ ~hasStackFile: (~dir: string, ~stack: string) => bool,
78
+ ) => plugins->Array.filter(p => review ? p.review : hasStackFile(~dir=p.dir, ~stack))
79
+
64
80
  type target = {functionName: string, bucket: string, key: string}
65
81
 
66
82
  /** `None` when the platform declares no bake. */
@@ -278,7 +294,12 @@ let invokeWith = (client: Lambda.client, ~functionName: string, ~payload: JSON.t
278
294
  | exception exn => Error(`could not invoke ${functionName}: ${Util_AwsError.describe(exn)}`)
279
295
  }
280
296
 
281
- let bake = async (~manifest: DeployManifest.resolved, ~stack: string, ~since: option<string>) =>
297
+ let bake = async (
298
+ ~manifest: DeployManifest.resolved,
299
+ ~stack: string,
300
+ ~since: option<string>,
301
+ ~review: bool,
302
+ ) =>
282
303
  switch PulumiCli.stackOutputs(~dir=manifest.platform.dir, ~stack) {
283
304
  | Error(_) as e => e
284
305
  | Ok(outputs) =>
@@ -288,12 +309,12 @@ let bake = async (~manifest: DeployManifest.resolved, ~stack: string, ~since: op
288
309
  Ok()
289
310
  | Some(target) =>
290
311
  let refs = []
291
- manifest.plugins->Array.forEach(p =>
292
- if PulumiCli.hasStackFile(~dir=p.dir, ~stack) {
293
- switch PulumiCli.stackOutputs(~dir=p.dir, ~stack) {
294
- | Ok(o) => o->structureRefOf->Option.forEach(r => refs->Array.push(r))
295
- | Error(message) => Console.error(`${p.name}: ${message} — not waited for`)
296
- }
312
+ manifest.plugins
313
+ ->pluginsToRead(~stack, ~review, ~hasStackFile=PulumiCli.hasStackFile)
314
+ ->Array.forEach(p =>
315
+ switch PulumiCli.stackOutputs(~dir=p.dir, ~stack) {
316
+ | Ok(o) => o->structureRefOf->Option.forEach(r => refs->Array.push(r))
317
+ | Error(message) => Console.error(`${p.name}: ${message} — not waited for`)
297
318
  }
298
319
  )
299
320
  let expect = refs->Dict.fromArray
@@ -352,7 +373,7 @@ let run = async (args: args): result<unit, string> =>
352
373
  | Ok(manifest) =>
353
374
  switch args.stack->Option.orElse(PulumiCli.selectedStack(~dir=manifest.platform.dir)) {
354
375
  | None => Error(`no stack selected in ${manifest.platform.dir} — pass --stack`)
355
- | Some(stack) => await bake(~manifest, ~stack, ~since=args.since)
376
+ | Some(stack) => await bake(~manifest, ~stack, ~since=args.since, ~review=args.review)
356
377
  }
357
378
  }
358
379
 
@@ -19,7 +19,7 @@ function parseArgs(argv) {
19
19
  "manifest",
20
20
  "stack",
21
21
  "since"
22
- ], undefined, undefined, undefined, argv), CliArgs$Reventless.noPositionals), a => ({
22
+ ], ["review"], undefined, undefined, argv), CliArgs$Reventless.noPositionals), a => ({
23
23
  manifest: CliArgs$Reventless.string(a, "manifest"),
24
24
  stack: CliArgs$Reventless.string(a, "stack"),
25
25
  since: Stdlib_Option.flatMap(CliArgs$Reventless.string(a, "since"), v => {
@@ -29,12 +29,13 @@ function parseArgs(argv) {
29
29
  return v;
30
30
  }
31
31
  }),
32
+ review: CliArgs$Reventless.bool(a, "review"),
32
33
  help: CliArgs$Reventless.help(a)
33
34
  }));
34
35
  }
35
36
 
36
37
  let usage = `
37
- Usage: bake-manifest [--manifest <path>] [--stack <name>] [--since <instant>]
38
+ Usage: bake-manifest [--manifest <path>] [--stack <name>] [--since <instant>] [--review]
38
39
 
39
40
  Bake the component manifest of a deployed platform.
40
41
 
@@ -44,6 +45,9 @@ Bake the component manifest of a deployed platform.
44
45
  platform's folder.
45
46
  --since <instant> When this deploy started (ISO 8601). Lets the report tell a
46
47
  plugin that re-registered from one that was unchanged.
48
+ --review The stack is a pull request's review environment. Its stacks'
49
+ settings are not in this checkout, so every plugin with a
50
+ review stack is waited for, not only those with a file here.
47
51
 
48
52
  Reads the bake function from the platform stack and each plugin's structure key
49
53
  from its stack, then asks the function to bake — again every
@@ -52,6 +56,16 @@ not arrived. A registration this deploy wrote with another key cannot arrive by
52
56
  waiting, so that stops the run at once.
53
57
  `;
54
58
 
59
+ function pluginsToRead(plugins, stack, review, hasStackFile) {
60
+ return plugins.filter(p => {
61
+ if (review) {
62
+ return p.review;
63
+ } else {
64
+ return hasStackFile(p.dir, stack);
65
+ }
66
+ });
67
+ }
68
+
55
69
  function targetOf(outputs) {
56
70
  let match = PulumiCli$ReventlessAws.stringOutput(outputs, "bakedManifestFunction");
57
71
  let match$1 = PulumiCli$ReventlessAws.stringOutput(outputs, "bakedManifestBucket");
@@ -269,7 +283,7 @@ function invokeWith(client, functionName, payload) {
269
283
  };
270
284
  }
271
285
 
272
- async function bake(manifest, stack, since) {
286
+ async function bake(manifest, stack, since, review) {
273
287
  let e = PulumiCli$ReventlessAws.stackOutputs(manifest.platform.dir, stack);
274
288
  if (e.TAG !== "Ok") {
275
289
  return e;
@@ -277,10 +291,7 @@ async function bake(manifest, stack, since) {
277
291
  let target = targetOf(e._0);
278
292
  if (target !== undefined) {
279
293
  let refs = [];
280
- manifest.plugins.forEach(p => {
281
- if (!PulumiCli$ReventlessAws.hasStackFile(p.dir, stack)) {
282
- return;
283
- }
294
+ pluginsToRead(manifest.plugins, stack, review, PulumiCli$ReventlessAws.hasStackFile).forEach(p => {
284
295
  let o = PulumiCli$ReventlessAws.stackOutputs(p.dir, stack);
285
296
  if (o.TAG === "Ok") {
286
297
  return Stdlib_Option.forEach(structureRefOf(o._0), r => {
@@ -336,7 +347,7 @@ async function run(args) {
336
347
  let manifest = e._0;
337
348
  let stack = Stdlib_Option.orElse(args.stack, PulumiCli$ReventlessAws.selectedStack(manifest.platform.dir));
338
349
  if (stack !== undefined) {
339
- return await bake(manifest, stack, args.since);
350
+ return await bake(manifest, stack, args.since, args.review);
340
351
  } else {
341
352
  return {
342
353
  TAG: "Error",
@@ -381,6 +392,7 @@ export {
381
392
  Lambda,
382
393
  parseArgs,
383
394
  usage,
395
+ pluginsToRead,
384
396
  targetOf,
385
397
  structureRefOf,
386
398
  payload,
@@ -570,7 +570,12 @@ let up = async (~manifest: DeployManifest.resolved, ~stack: string): result<unit
570
570
  | Error(_) as e => e
571
571
  | Ok() =>
572
572
  Console.log("\n── Baking the component manifest ──\n")
573
- switch await BakeManifest.bake(~manifest, ~stack, ~since=Some(startedAt)) {
573
+ switch await BakeManifest.bake(
574
+ ~manifest,
575
+ ~stack,
576
+ ~since=Some(startedAt),
577
+ ~review=false,
578
+ ) {
574
579
  | Error(_) as e => e
575
580
  | Ok() =>
576
581
  let accounts = switch (
@@ -718,7 +718,7 @@ async function up(manifest, stack) {
718
718
  return e$4;
719
719
  }
720
720
  console.log("\n── Baking the component manifest ──\n");
721
- let e$5 = await BakeManifest$ReventlessAws.bake(manifest, stack, startedAt);
721
+ let e$5 = await BakeManifest$ReventlessAws.bake(manifest, stack, startedAt, false);
722
722
  if (e$5.TAG !== "Ok") {
723
723
  return e$5;
724
724
  }
@@ -38,7 +38,14 @@ type t = {
38
38
  }
39
39
 
40
40
  /** One stack folder, with its path made absolute. */
41
- type project = {name: string, dir: string, stackDefaults: dict<string>, region: option<string>}
41
+ type project = {
42
+ name: string,
43
+ dir: string,
44
+ stackDefaults: dict<string>,
45
+ region: option<string>,
46
+ /** Whether a review environment deploys it: false only on a plugin marked so. */
47
+ review: bool,
48
+ }
42
49
 
43
50
  type resolved = {
44
51
  file: string,
@@ -65,6 +72,7 @@ let resolve = (manifest: t, ~file: string): resolved => {
65
72
  dir: NodePath.resolve([base, manifest.platform.path]),
66
73
  stackDefaults: manifest.platform.stackDefaults->Option.getOr(Dict.make()),
67
74
  region: None,
75
+ review: true,
68
76
  },
69
77
  plugins: manifest.plugins
70
78
  ->Option.getOr([])
@@ -73,6 +81,7 @@ let resolve = (manifest: t, ~file: string): resolved => {
73
81
  dir: NodePath.resolve([base, p.path]),
74
82
  stackDefaults: p.stackDefaults->Option.getOr(Dict.make()),
75
83
  region: p.region,
84
+ review: p.review->Option.getOr(true),
76
85
  }),
77
86
  }
78
87
  }
@@ -60,13 +60,15 @@ function resolve(manifest, file) {
60
60
  name: Stdlib_Option.getOr(manifest.platform.name, "platform"),
61
61
  dir: Nodepath.resolve(base, manifest.platform.path),
62
62
  stackDefaults: Stdlib_Option.getOr(manifest.platform["stack-defaults"], {}),
63
- region: undefined
63
+ region: undefined,
64
+ review: true
64
65
  },
65
66
  plugins: Stdlib_Option.getOr(manifest.plugins, []).map(p => ({
66
67
  name: p.name,
67
68
  dir: Nodepath.resolve(base, p.path),
68
69
  stackDefaults: Stdlib_Option.getOr(p["stack-defaults"], {}),
69
- region: p.region
70
+ region: p.region,
71
+ review: Stdlib_Option.getOr(p.review, true)
70
72
  }))
71
73
  };
72
74
  }
@@ -39,6 +39,7 @@ plugins:
39
39
  dir: "/repo/shop/platform-aws",
40
40
  stackDefaults: Dict.fromArray([("platform:messagingEmailProvider", "log")]),
41
41
  region: None,
42
+ review: true,
42
43
  },
43
44
  plugins: [
44
45
  {
@@ -46,12 +47,14 @@ plugins:
46
47
  dir: "/repo/shop/catalog-aws",
47
48
  stackDefaults: Dict.make(),
48
49
  region: None,
50
+ review: true,
49
51
  },
50
52
  {
51
53
  name: "ordering",
52
54
  dir: "/repo/shop/ordering-aws",
53
55
  stackDefaults: Dict.make(),
54
56
  region: Some("eu-central-1"),
57
+ review: false,
55
58
  },
56
59
  ],
57
60
  }),
@@ -79,6 +82,7 @@ describe("BakeManifest.parseArgs", () => {
79
82
  Bake.manifest: Some("m.yaml"),
80
83
  stack: Some("alpha"),
81
84
  since: Some("2026-09-16T10:00:00Z"),
85
+ review: false,
82
86
  help: false,
83
87
  }),
84
88
  )
@@ -89,11 +93,44 @@ describe("BakeManifest.parseArgs", () => {
89
93
  expect(Bake.parseArgs(["--since", ""])->Result.map(a => a.since))->toEqual(Ok(None))
90
94
  )
91
95
 
96
+ testSync("--review says the stack is a review environment", () =>
97
+ expect(
98
+ Bake.parseArgs(["--stack", "review-pr-7", "--review"])->Result.map(a => a.review),
99
+ )->toEqual(Ok(true))
100
+ )
101
+
92
102
  testSync("an unknown flag refuses", () =>
93
103
  expect(Bake.parseArgs(["--stak", "alpha"]))->toEqual(Error(`unknown argument "--stak"`))
94
104
  )
95
105
  })
96
106
 
107
+ describe("BakeManifest.pluginsToRead", () => {
108
+ let plugin = (name, ~review) => {
109
+ DeployManifest.name,
110
+ dir: `/repo/shop/${name}-aws`,
111
+ stackDefaults: Dict.make(),
112
+ region: None,
113
+ review,
114
+ }
115
+ let plugins = [plugin("catalog", ~review=true), plugin("ingest", ~review=false)]
116
+ let names = ps => ps->Array.map((p: DeployManifest.project) => p.name)
117
+
118
+ testSync("outside a review, the plugins whose stack has a settings file here", () => {
119
+ let hasStackFile = (~dir, ~stack as _) => dir == "/repo/shop/ingest-aws"
120
+ expect(
121
+ plugins->Bake.pluginsToRead(~stack="alpha", ~review=false, ~hasStackFile)->names,
122
+ )->toEqual(["ingest"])
123
+ })
124
+
125
+ // A review stack's settings exist only in the runner that created it.
126
+ testSync("in a review, every plugin with a review stack, files or not", () => {
127
+ let hasStackFile = (~dir as _, ~stack as _) => false
128
+ expect(
129
+ plugins->Bake.pluginsToRead(~stack="review-pr-7", ~review=true, ~hasStackFile)->names,
130
+ )->toEqual(["catalog"])
131
+ })
132
+ })
133
+
97
134
  describe("BakeManifest reads the stacks", () => {
98
135
  testSync("a platform without a bake function declares no bake", () =>
99
136
  expect(
@@ -40,20 +40,23 @@ plugins:
40
40
  "platform:messagingEmailProvider",
41
41
  "log"
42
42
  ]]),
43
- region: undefined
43
+ region: undefined,
44
+ review: true
44
45
  },
45
46
  plugins: [
46
47
  {
47
48
  name: "catalog",
48
49
  dir: "/repo/shop/catalog-aws",
49
50
  stackDefaults: {},
50
- region: undefined
51
+ region: undefined,
52
+ review: true
51
53
  },
52
54
  {
53
55
  name: "ordering",
54
56
  dir: "/repo/shop/ordering-aws",
55
57
  stackDefaults: {},
56
- region: "eu-central-1"
58
+ region: "eu-central-1",
59
+ review: false
57
60
  }
58
61
  ]
59
62
  }
@@ -79,6 +82,7 @@ globalThis.describe("BakeManifest.parseArgs", () => {
79
82
  manifest: "m.yaml",
80
83
  stack: "alpha",
81
84
  since: "2026-09-16T10:00:00Z",
85
+ review: false,
82
86
  help: false
83
87
  }
84
88
  });
@@ -92,6 +96,16 @@ globalThis.describe("BakeManifest.parseArgs", () => {
92
96
  _0: undefined
93
97
  });
94
98
  });
99
+ globalThis.test("--review says the stack is a review environment", () => {
100
+ globalThis.expect(Stdlib_Result.map(BakeManifest$ReventlessAws.parseArgs([
101
+ "--stack",
102
+ "review-pr-7",
103
+ "--review"
104
+ ]), a => a.review)).toEqual({
105
+ TAG: "Ok",
106
+ _0: true
107
+ });
108
+ });
95
109
  globalThis.test("an unknown flag refuses", () => {
96
110
  globalThis.expect(BakeManifest$ReventlessAws.parseArgs([
97
111
  "--stak",
@@ -103,6 +117,30 @@ globalThis.describe("BakeManifest.parseArgs", () => {
103
117
  });
104
118
  });
105
119
 
120
+ globalThis.describe("BakeManifest.pluginsToRead", () => {
121
+ let plugin = (name, review) => ({
122
+ name: name,
123
+ dir: `/repo/shop/` + name + `-aws`,
124
+ stackDefaults: {},
125
+ region: undefined,
126
+ review: review
127
+ });
128
+ let plugins = [
129
+ plugin("catalog", true),
130
+ plugin("ingest", false)
131
+ ];
132
+ globalThis.test("outside a review, the plugins whose stack has a settings file here", () => {
133
+ let hasStackFile = (dir, param) => dir === "/repo/shop/ingest-aws";
134
+ let ps = BakeManifest$ReventlessAws.pluginsToRead(plugins, "alpha", false, hasStackFile);
135
+ globalThis.expect(ps.map(p => p.name)).toEqual(["ingest"]);
136
+ });
137
+ globalThis.test("in a review, every plugin with a review stack, files or not", () => {
138
+ let hasStackFile = (param, param$1) => false;
139
+ let ps = BakeManifest$ReventlessAws.pluginsToRead(plugins, "review-pr-7", true, hasStackFile);
140
+ globalThis.expect(ps.map(p => p.name)).toEqual(["catalog"]);
141
+ });
142
+ });
143
+
106
144
  globalThis.describe("BakeManifest reads the stacks", () => {
107
145
  globalThis.test("a platform without a bake function declares no bake", () => {
108
146
  globalThis.expect(BakeManifest$ReventlessAws.targetOf(Stdlib_Option.getOr(Stdlib_JSON.Decode.object(JSON.parse(`{"bakedManifestBucket": "b", "bakedManifestFunction": ""}`)), {}))).toEqual(undefined);