@intentius/chant 0.18.29 → 0.18.31
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/dist/cli/handlers/components.d.ts +27 -0
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +2 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +13 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/driver.d.ts +22 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +94 -0
- package/dist/components/run-progress.d.ts.map +1 -0
- package/dist/lifecycle/observe.d.ts +13 -0
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/handlers/components.ts +8 -2
- package/src/cli/handlers/graph.test.ts +92 -0
- package/src/cli/handlers/graph.ts +27 -1
- package/src/cli/handlers/run.test.ts +54 -0
- package/src/cli/handlers/run.ts +9 -1
- package/src/cli/main.test.ts +14 -0
- package/src/cli/main.ts +7 -0
- package/src/cli/registry.ts +2 -0
- package/src/components/cli-support.test.ts +92 -1
- package/src/components/cli-support.ts +36 -2
- package/src/components/driver.test.ts +190 -0
- package/src/components/driver.ts +100 -33
- package/src/components/run-progress.ts +117 -0
- package/src/lifecycle/observe.test.ts +48 -0
- package/src/lifecycle/observe.ts +37 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandContext } from "../registry.js";
|
|
2
|
+
import type { Phase } from "../../components/component.js";
|
|
2
3
|
/**
|
|
3
4
|
* chant components release <env> --component <name> --digest <sha256:...>
|
|
4
5
|
* [--git-sha <sha>] [--run-id <id>] [--actor <name>]
|
|
@@ -17,6 +18,32 @@ import type { CommandContext } from "../registry.js";
|
|
|
17
18
|
* timestamp from the environment/CLI at record time."
|
|
18
19
|
*/
|
|
19
20
|
export declare function runComponentsReleaseRecord(ctx: CommandContext): Promise<number>;
|
|
21
|
+
/**
|
|
22
|
+
* chant components status [env] [--live] [--json] [--compare-to <env>]
|
|
23
|
+
*
|
|
24
|
+
* Answers "what's built" and "what's deployed where," joined by digest.
|
|
25
|
+
* Without `--live`, reports the release ledger alone (recorded vs unrecorded
|
|
26
|
+
* is meaningless without live evidence, so every recorded row reports
|
|
27
|
+
* `unknown` reconciliation — still useful as a pure ledger read). With
|
|
28
|
+
* `--live`, joins against `lifecycle diff --live` + ownership (reusing
|
|
29
|
+
* `buildChangeSet`, the same classification `lifecycle plan` already
|
|
30
|
+
* trusts) to flag unrecorded deploys and drift.
|
|
31
|
+
*
|
|
32
|
+
* Omitting `<env>` reports every environment that has release records.
|
|
33
|
+
* `--compare-to <env>` answers the single-query cross-environment question
|
|
34
|
+
* the epic names explicitly: "which build is in `<env>`, and is it the one
|
|
35
|
+
* tested in `<compare-to>`."
|
|
36
|
+
*/
|
|
37
|
+
/** Every distinct `cfn-deploy` stack name a component's deploy phases target. A
|
|
38
|
+
* step may itself be a nested `Phase`, so walk recursively; a resolved component
|
|
39
|
+
* carries the stack as a concrete string.
|
|
40
|
+
*
|
|
41
|
+
* Exported for `chant graph --live` (../handlers/graph.ts's `runGraphLive`,
|
|
42
|
+
* #57): the same per-component stack resolution this file uses for `chant
|
|
43
|
+
* components status --live` is also how the live graph learns which stacks to
|
|
44
|
+
* observe on a multi-stack, per-component project (`describeResources`'s
|
|
45
|
+
* single-stack-named-after-the-environment convention never matches one). */
|
|
46
|
+
export declare function cfnDeployStacks(deploy: Phase[]): string[];
|
|
20
47
|
export declare function runComponentsStatus(ctx: CommandContext): Promise<number>;
|
|
21
48
|
/** Fallback for `chant components` with no/unknown subcommand. */
|
|
22
49
|
export declare function runComponentsUnknown(ctx: CommandContext): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/components.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/components.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,KAAK,EAAa,MAAM,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAuErF;AAyCD;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;;6EAQ6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAiBzD;AAwCD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAuN9E;AAED,kEAAkE;AAClE,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAM/E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/graph.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/graph.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/run.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/run.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA2ClD,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM;;;;GAO5F;AA8BD,wBAAsB,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAgEpE;AAoFD,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCtE;AA0CD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CnE;AA2DD;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBtE;AAID,2LAA2L;AAC3L,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BtE;AAmCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAchE;AA6ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAsE1E;AAkOD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAiFrE;AAuLD,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMjE"}
|
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAMA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAkB9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAMA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAkB9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6LpD;AA2VD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5E"}
|
package/dist/cli/registry.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface ParsedArgs {
|
|
|
25
25
|
temporal?: boolean;
|
|
26
26
|
/** `chant run` — emit the structured OpRunResult as JSON on stdout. */
|
|
27
27
|
json?: boolean;
|
|
28
|
+
/** `chant run --components <name|all> --progress-json` — stream one NDJSON `RunProgressEvent` (../../components/run-progress.ts) per line to stdout while the run executes (local executor only), so a consumer can render live wave/component/phase/step progress instead of tailing raw logs. Purely additive: run semantics, ordering, and exit code are unchanged; omitted (undefined, not false) when the flag isn't passed. */
|
|
29
|
+
progressJson?: boolean;
|
|
28
30
|
live: boolean;
|
|
29
31
|
/** `chant migrate --from <name>` (default "github") */
|
|
30
32
|
migrateFrom?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;mFAC+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;oFACgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;2EAGuE;IACvE,aAAa,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClC;iFAC6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;6DAEyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;uFACmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gGAAgG;IAChG,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mFAAmF;IACnF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kHAAkH;IAClH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sJAAsJ;IACtJ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uKAAuK;IACvK,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0HAA0H;IAC1H,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oJAAoJ;IACpJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oJAAoJ;IACpJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8RAA8R;IAC9R,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8NAA8N;IAC9N,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uTAAuT;IACvT,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0CAA0C;IAC1C,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,UAAU,CAAC;IAChB,4FAA4F;IAC5F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAWD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,eAAe,GAAG,IAAI,CAiB/F"}
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { type Archetype } from "./component.js";
|
|
25
25
|
import { type DriverComponent, type DriverRunResult } from "./driver.js";
|
|
26
26
|
import { type ComponentPipelineOptions } from "../lexicon.js";
|
|
27
|
+
import type { RunProgressEvent } from "./run-progress.js";
|
|
27
28
|
import type { CapabilityRegistry } from "./capability.js";
|
|
28
29
|
import { type ChantConfig } from "../config.js";
|
|
29
30
|
/** One component in `chant list --components` output. */
|
|
@@ -147,6 +148,18 @@ export interface RunComponentsOptions {
|
|
|
147
148
|
* ran elsewhere. Merged with, and overridden by, outputs this run produces.
|
|
148
149
|
*/
|
|
149
150
|
componentOutputs?: Record<string, Record<string, unknown>>;
|
|
151
|
+
/**
|
|
152
|
+
* Opt-in structured progress observer (`chant run --components <name|all>
|
|
153
|
+
* --progress-json`, see ./run-progress.ts). Threaded straight through to
|
|
154
|
+
* `runInterpretDriver` for `selector === "all"`; for a single-component
|
|
155
|
+
* selector (which bypasses `runInterpretDriver` — see the docstring above),
|
|
156
|
+
* this function emits the same `run-start`/`wave-start`/`component-start`/
|
|
157
|
+
* …/`run-done` envelope itself, treating the one component as a run with a
|
|
158
|
+
* single wave, so `--progress-json` produces a well-formed event stream
|
|
159
|
+
* regardless of selector. Left `undefined` by every caller that didn't pass
|
|
160
|
+
* `--progress-json`, in which case nothing changes.
|
|
161
|
+
*/
|
|
162
|
+
onProgress?: (event: RunProgressEvent) => void;
|
|
150
163
|
}
|
|
151
164
|
/** Result of `chant run --components <name|all>`. */
|
|
152
165
|
export interface RunComponentsResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-support.d.ts","sourceRoot":"","sources":["../../src/components/cli-support.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAQL,KAAK,eAAe,EAEpB,KAAK,eAAe,EACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAuC,KAAK,wBAAwB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-support.d.ts","sourceRoot":"","sources":["../../src/components/cli-support.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
* `CapabilityRegistry` the caller supplies.
|
|
42
42
|
*/
|
|
43
43
|
import type { CapabilityRegistry, DeployContext } from "./capability.js";
|
|
44
|
+
import type { RunProgressEvent } from "./run-progress.js";
|
|
45
|
+
export type { RunProgressEvent } from "./run-progress.js";
|
|
44
46
|
/** A wiring reference or literal value, as it appears in a step's fields (schema `WiringValue`). */
|
|
45
47
|
export type WiringValue = string | {
|
|
46
48
|
stackOutput: {
|
|
@@ -181,8 +183,17 @@ export declare function resolveStepInput(input: Record<string, unknown>, phaseOu
|
|
|
181
183
|
* handling. Cross-component artifact outputs this component published (if
|
|
182
184
|
* any) are recorded into `componentOutputs` under its own name so downstream
|
|
183
185
|
* components can reference `@<name>.publish.*`.
|
|
186
|
+
*
|
|
187
|
+
* `onProgress`, when supplied, is forwarded to every `runPhase` call (both the
|
|
188
|
+
* forward `deploy` phases and, on failure, the component's own authored
|
|
189
|
+
* `rollback` phases) so a `--progress-json` consumer sees `phase-start`/
|
|
190
|
+
* `step`/`phase-done` events for whichever phases actually ran. The saga
|
|
191
|
+
* unwind step-by-step compensation (`rollbackExecuted` below) is not part of
|
|
192
|
+
* the `RunProgressEvent` contract and stays silent — it isn't a `deploy`
|
|
193
|
+
* phase, and its record statuses (`rolled-back`/`rollback-opted-out`) don't
|
|
194
|
+
* map onto the `step` event's `running`/`ok`/`failed` shape.
|
|
184
195
|
*/
|
|
185
|
-
export declare function runComponentDeploy(component: DriverComponent, ctx: DeployContext, registry: CapabilityRegistry, componentOutputs: Record<string, Record<string, unknown
|
|
196
|
+
export declare function runComponentDeploy(component: DriverComponent, ctx: DeployContext, registry: CapabilityRegistry, componentOutputs: Record<string, Record<string, unknown>>, onProgress?: (event: RunProgressEvent) => void): Promise<DriverComponentResult>;
|
|
186
197
|
export interface InterpretRunOptions {
|
|
187
198
|
/** Target environment name, threaded into every capability's `DeployContext`. */
|
|
188
199
|
env: string;
|
|
@@ -190,6 +201,16 @@ export interface InterpretRunOptions {
|
|
|
190
201
|
vars?: Record<string, unknown>;
|
|
191
202
|
/** Pre-seeded cross-component/cross-stack outputs (e.g. from a prior run, or a caller resolving `stackOutput` externally). Merged with outputs this run produces. */
|
|
192
203
|
componentOutputs?: Record<string, Record<string, unknown>>;
|
|
204
|
+
/**
|
|
205
|
+
* Opt-in structured progress observer (`chant run --components all
|
|
206
|
+
* --progress-json`, see ./run-progress.ts). Called with `run-start`/
|
|
207
|
+
* `wave-start`/`component-start`/…/`run-done` events as the run executes;
|
|
208
|
+
* never consulted for control flow, so leaving it `undefined` (the default
|
|
209
|
+
* for every caller that didn't pass `--progress-json`) makes every
|
|
210
|
+
* `onProgress?.(...)` call below a no-op and this function's behavior is
|
|
211
|
+
* byte-for-byte the same as before this option existed.
|
|
212
|
+
*/
|
|
213
|
+
onProgress?: (event: RunProgressEvent) => void;
|
|
193
214
|
}
|
|
194
215
|
/**
|
|
195
216
|
* Run a set of components to completion on the local in-process executor:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/components/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/components/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured progress events for `chant run --components <sel> --progress-json`
|
|
3
|
+
* (behold roadmap M3: a consumer that renders live wave/phase/step progress
|
|
4
|
+
* instead of tailing raw logs).
|
|
5
|
+
*
|
|
6
|
+
* This is purely additive observation over the interpret driver's existing
|
|
7
|
+
* wave -> component -> phase -> step execution loop (./driver.ts): an
|
|
8
|
+
* optional `onProgress` callback, threaded through
|
|
9
|
+
* `runInterpretDriver`/`runComponentDeploy`/`runPhase` (and the CLI's
|
|
10
|
+
* single-component path, ./cli-support.ts's `runComponents`), that never
|
|
11
|
+
* changes run ordering, gating, `onFailure`, rollback, or exit codes — it
|
|
12
|
+
* only reports what already happened, as it happens. See ./driver.ts's
|
|
13
|
+
* module doc for what actually executes; streaming progress on the *durable*
|
|
14
|
+
* (Temporal) path is a separate, later concern (Temporal already exposes
|
|
15
|
+
* durable run state via `chant run status`/`log`).
|
|
16
|
+
*
|
|
17
|
+
* `RunProgressEvent` is a discriminated union on `type`, one JSON object per
|
|
18
|
+
* NDJSON line (see `ndjsonProgressSink` below and
|
|
19
|
+
* ../cli/handlers/run.ts's `--progress-json` wiring).
|
|
20
|
+
*/
|
|
21
|
+
/** Terminal status for a wave/component/phase/run — mirrors DriverStepRecord's ok/fail split, collapsed to the two outcomes a consumer renders progress against. */
|
|
22
|
+
export type RunProgressStatus = "ok" | "failed";
|
|
23
|
+
/** The run is about to start. `waves` are the parallel-safe waves the run will attempt, in order (see resolveComponentGraph) — 1-based wave numbers in every other event index into this array. */
|
|
24
|
+
export interface RunStartEvent {
|
|
25
|
+
type: "run-start";
|
|
26
|
+
waves: string[][];
|
|
27
|
+
}
|
|
28
|
+
/** A wave is about to start; its components may run concurrently (independent components share a wave). */
|
|
29
|
+
export interface WaveStartEvent {
|
|
30
|
+
type: "wave-start";
|
|
31
|
+
/** 1-based wave number. */
|
|
32
|
+
wave: number;
|
|
33
|
+
components: string[];
|
|
34
|
+
}
|
|
35
|
+
/** A component within a wave is about to start its `deploy` composition. */
|
|
36
|
+
export interface ComponentStartEvent {
|
|
37
|
+
type: "component-start";
|
|
38
|
+
wave: number;
|
|
39
|
+
component: string;
|
|
40
|
+
}
|
|
41
|
+
/** A named phase of a component's composition is about to run its steps. Emitted for nested (fan-out) phases too, keyed by the nested phase's own name. */
|
|
42
|
+
export interface PhaseStartEvent {
|
|
43
|
+
type: "phase-start";
|
|
44
|
+
component: string;
|
|
45
|
+
phase: string;
|
|
46
|
+
}
|
|
47
|
+
/** A single capability step within a phase — one event when it starts, one when it settles. */
|
|
48
|
+
export interface StepEvent {
|
|
49
|
+
type: "step";
|
|
50
|
+
component: string;
|
|
51
|
+
phase: string;
|
|
52
|
+
step: string;
|
|
53
|
+
status: "running" | "ok" | "failed";
|
|
54
|
+
/** Present only alongside `status: "failed"`, when the capability threw. */
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
/** A phase finished — `ok` if every step in it succeeded, `failed` if any step failed (the phase's remaining steps were skipped, per the driver's fail-fast-within-a-phase semantics). */
|
|
58
|
+
export interface PhaseDoneEvent {
|
|
59
|
+
type: "phase-done";
|
|
60
|
+
component: string;
|
|
61
|
+
phase: string;
|
|
62
|
+
status: RunProgressStatus;
|
|
63
|
+
}
|
|
64
|
+
/** A component's `deploy` composition finished (after any saga rollback + component-level `rollback` phases the driver ran on failure). */
|
|
65
|
+
export interface ComponentDoneEvent {
|
|
66
|
+
type: "component-done";
|
|
67
|
+
wave: number;
|
|
68
|
+
component: string;
|
|
69
|
+
status: RunProgressStatus;
|
|
70
|
+
}
|
|
71
|
+
/** A wave finished — `failed` if any component in it failed, which also stops the run before any later wave starts. */
|
|
72
|
+
export interface WaveDoneEvent {
|
|
73
|
+
type: "wave-done";
|
|
74
|
+
wave: number;
|
|
75
|
+
status: RunProgressStatus;
|
|
76
|
+
}
|
|
77
|
+
/** The run finished. Mirrors the driver's own terminal `DriverRunResult.ok` / exit code. */
|
|
78
|
+
export interface RunDoneEvent {
|
|
79
|
+
type: "run-done";
|
|
80
|
+
status: RunProgressStatus;
|
|
81
|
+
}
|
|
82
|
+
export type RunProgressEvent = RunStartEvent | WaveStartEvent | ComponentStartEvent | PhaseStartEvent | StepEvent | PhaseDoneEvent | ComponentDoneEvent | WaveDoneEvent | RunDoneEvent;
|
|
83
|
+
/** A sink that receives progress events as they occur. The driver only ever calls this — it never writes to a stream directly, so it stays testable without stdout. */
|
|
84
|
+
export type RunProgressSink = (event: RunProgressEvent) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Build a sink that writes `JSON.stringify(event) + "\n"` to `write` (default:
|
|
87
|
+
* `process.stdout.write`), one line per event, as they happen — the
|
|
88
|
+
* `--progress-json` CLI wiring's sink (../cli/handlers/run.ts). Kept separate
|
|
89
|
+
* from `driver-output.ts`'s end-of-run renderers: this emits *during* the
|
|
90
|
+
* run, one line at a time; `renderDriverJson`/`renderDriverHuman` render the
|
|
91
|
+
* completed `DriverRunResult` once, after the run finishes.
|
|
92
|
+
*/
|
|
93
|
+
export declare function ndjsonProgressSink(write?: (chunk: string) => void): RunProgressSink;
|
|
94
|
+
//# sourceMappingURL=run-progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-progress.d.ts","sourceRoot":"","sources":["../../src/components/run-progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,oKAAoK;AACpK,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,QAAQ,CAAC;AAEhD,mMAAmM;AACnM,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;CACnB;AAED,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2JAA2J;AAC3J,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+FAA+F;AAC/F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,CAAC;IACpC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0LAA0L;AAC1L,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,2IAA2I;AAC3I,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,uHAAuH;AACvH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,cAAc,GACd,mBAAmB,GACnB,eAAe,GACf,SAAS,GACT,cAAc,GACd,kBAAkB,GAClB,aAAa,GACb,YAAY,CAAC;AAEjB,uKAAuK;AACvK,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAA0C,GAAG,eAAe,CAExH"}
|
|
@@ -24,8 +24,21 @@ export interface ObserveResult {
|
|
|
24
24
|
* marker channel logs and returns everything (its own contract). Plugins that
|
|
25
25
|
* throw are collected into `errors` and skipped — one failing lexicon never
|
|
26
26
|
* sinks the whole graph.
|
|
27
|
+
*
|
|
28
|
+
* `stacks` (#57) is for a multi-stack, per-component project (e.g. loomster)
|
|
29
|
+
* where there is no single stack named after the environment — AWS's
|
|
30
|
+
* single-stack convention (`lexicons/aws/src/plugin.ts`'s `describeResources`,
|
|
31
|
+
* absent an explicit `stack`) queries a stack that simply doesn't exist there,
|
|
32
|
+
* so the single-call path always observes zero nodes. When `stacks` is
|
|
33
|
+
* present and non-empty, each observing plugin's `describeResources` is
|
|
34
|
+
* called once per stack (same `environment`/`entities`/`entityNames`, only
|
|
35
|
+
* `stack` varies) and the returned resource maps are unioned — a resource
|
|
36
|
+
* appears under whichever stack contains its logical id. When `stacks` is
|
|
37
|
+
* absent or empty, behavior is exactly the single call of before (no `stack`
|
|
38
|
+
* key at all), so a single-stack project is unaffected.
|
|
27
39
|
*/
|
|
28
40
|
export declare function observeResources(environment: string, plugins: ObservationLexicon[], buildResult: BuildResult, opts?: {
|
|
29
41
|
owned?: boolean;
|
|
42
|
+
stacks?: string[];
|
|
30
43
|
}): Promise<ObserveResult>;
|
|
31
44
|
//# sourceMappingURL=observe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/lifecycle/observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,YAAY,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/lifecycle/observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,YAAY,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,kBAAkB,EAAE,EAC7B,WAAW,EAAE,WAAW,EACxB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5C,OAAO,CAAC,aAAa,CAAC,CAgExB"}
|
package/package.json
CHANGED
|
@@ -194,8 +194,14 @@ interface StatusJsonRow {
|
|
|
194
194
|
*/
|
|
195
195
|
/** Every distinct `cfn-deploy` stack name a component's deploy phases target. A
|
|
196
196
|
* step may itself be a nested `Phase`, so walk recursively; a resolved component
|
|
197
|
-
* carries the stack as a concrete string.
|
|
198
|
-
|
|
197
|
+
* carries the stack as a concrete string.
|
|
198
|
+
*
|
|
199
|
+
* Exported for `chant graph --live` (../handlers/graph.ts's `runGraphLive`,
|
|
200
|
+
* #57): the same per-component stack resolution this file uses for `chant
|
|
201
|
+
* components status --live` is also how the live graph learns which stacks to
|
|
202
|
+
* observe on a multi-stack, per-component project (`describeResources`'s
|
|
203
|
+
* single-stack-named-after-the-environment convention never matches one). */
|
|
204
|
+
export function cfnDeployStacks(deploy: Phase[]): string[] {
|
|
199
205
|
const stacks = new Set<string>();
|
|
200
206
|
const walkSteps = (steps: Phase["steps"]): void => {
|
|
201
207
|
for (const step of steps) {
|
|
@@ -44,6 +44,14 @@ const observeMock = vi.fn();
|
|
|
44
44
|
vi.mock("../../lifecycle/observe", () => ({
|
|
45
45
|
observeResources: (...a: unknown[]) => observeMock(...a),
|
|
46
46
|
}));
|
|
47
|
+
// `runGraphLive` resolves each component's `cfn-deploy` stack(s) (#57) so a
|
|
48
|
+
// multi-stack, per-component project observes the right stacks; default to
|
|
49
|
+
// "no components" (empty map, no errors) so the existing single-stack --live
|
|
50
|
+
// test is unaffected unless a test opts into a component layout below.
|
|
51
|
+
const discoverComponentsMock = vi.fn();
|
|
52
|
+
vi.mock("../../components/discover", () => ({
|
|
53
|
+
discoverComponents: (...a: unknown[]) => discoverComponentsMock(...a),
|
|
54
|
+
}));
|
|
47
55
|
vi.mock("../../config", () => ({
|
|
48
56
|
loadChantConfig: () => Promise.resolve({ config: {} }),
|
|
49
57
|
}));
|
|
@@ -93,6 +101,12 @@ describe("runGraph", () => {
|
|
|
93
101
|
lintMock.mockReset();
|
|
94
102
|
layoutMock.mockReset();
|
|
95
103
|
componentGraphMock.mockReset();
|
|
104
|
+
discoverComponentsMock.mockReset();
|
|
105
|
+
// Default: no components — the single-stack --live path most tests exercise.
|
|
106
|
+
discoverComponentsMock.mockResolvedValue({ components: new Map(), sourceFiles: [], errors: [] });
|
|
107
|
+
observeMock.mockReset();
|
|
108
|
+
loadPluginsMock.mockReset();
|
|
109
|
+
resolveLexMock.mockReset();
|
|
96
110
|
});
|
|
97
111
|
|
|
98
112
|
describe("Op graph (default)", () => {
|
|
@@ -326,5 +340,83 @@ describe("runGraph", () => {
|
|
|
326
340
|
expect(out).not.toContain("No lexicons implement describeResources");
|
|
327
341
|
expect(out).toContain("web-vpc");
|
|
328
342
|
});
|
|
343
|
+
|
|
344
|
+
// Regression for #57: a single-stack project (no `*.component.ts` files —
|
|
345
|
+
// discoverComponents returns an empty map) must observe exactly as before,
|
|
346
|
+
// no `stacks` collected.
|
|
347
|
+
test("single-stack project (no components): observeResources gets an empty stacks list", async () => {
|
|
348
|
+
resolveLexMock.mockResolvedValue(["aws"]);
|
|
349
|
+
loadPluginsMock.mockResolvedValue([
|
|
350
|
+
{ name: "aws", serializer: {}, describeResources: () => Promise.resolve({}) },
|
|
351
|
+
]);
|
|
352
|
+
observeMock.mockResolvedValue({ observations: [], errors: [] });
|
|
353
|
+
const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, env: "prod" }), plugins: [], serializers: [] });
|
|
354
|
+
expect(exit).toBe(0);
|
|
355
|
+
expect(observeMock).toHaveBeenCalledWith("prod", expect.anything(), expect.anything(), {
|
|
356
|
+
owned: true,
|
|
357
|
+
stacks: [],
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// The bug this branch fixes (#57): a multi-stack, per-component project
|
|
362
|
+
// (loomster/Floci) has no stack literally named after the environment, so
|
|
363
|
+
// the live graph must resolve each component's own `cfn-deploy` stack(s)
|
|
364
|
+
// and pass them through to `observeResources` for the per-stack union.
|
|
365
|
+
test("multi-stack component project: resolves each component's cfn-deploy stack(s) and passes them to observeResources", async () => {
|
|
366
|
+
resolveLexMock.mockResolvedValue(["aws"]);
|
|
367
|
+
loadPluginsMock.mockResolvedValue([
|
|
368
|
+
{ name: "aws", serializer: {}, describeResources: () => Promise.resolve({}) },
|
|
369
|
+
]);
|
|
370
|
+
discoverComponentsMock.mockResolvedValue({
|
|
371
|
+
errors: [],
|
|
372
|
+
sourceFiles: [],
|
|
373
|
+
components: new Map([
|
|
374
|
+
["loom-db", { component: { name: "loom-db", dependsOn: [], deploy: [
|
|
375
|
+
{ phase: "deploy", steps: [{ kind: "cfn-deploy", stack: "loom-local-a-loom-db" }] },
|
|
376
|
+
] }, exportName: "loomDb", filePath: "components/loom-db.component.ts" }],
|
|
377
|
+
// Multi-stack component: two cfn-deploy steps, nested under a sub-phase.
|
|
378
|
+
["loom-backend", { component: { name: "loom-backend", dependsOn: ["loom-db"], deploy: [
|
|
379
|
+
{ phase: "deploy", steps: [
|
|
380
|
+
{ phase: "nested", steps: [{ kind: "cfn-deploy", stack: "loom-local-a-loom-backend" }] },
|
|
381
|
+
{ kind: "cfn-deploy", stack: "loom-local-a-loom-backend-jobs" },
|
|
382
|
+
] },
|
|
383
|
+
] }, exportName: "loomBackend", filePath: "components/loom-backend.component.ts" }],
|
|
384
|
+
// Non-aws / no cfn-deploy component: contributes no stacks.
|
|
385
|
+
["loom-frontend", { component: { name: "loom-frontend", dependsOn: [], deploy: [
|
|
386
|
+
{ phase: "deploy", steps: [{ kind: "s3-sync" }] },
|
|
387
|
+
] }, exportName: "loomFrontend", filePath: "components/loom-frontend.component.ts" }],
|
|
388
|
+
]),
|
|
389
|
+
});
|
|
390
|
+
observeMock.mockResolvedValue({
|
|
391
|
+
observations: [{ lexicon: "aws", resources: { "loom-db": { type: "AWS::RDS::DBInstance", status: "OK" } } }],
|
|
392
|
+
errors: [],
|
|
393
|
+
});
|
|
394
|
+
const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, env: "local" }), plugins: [], serializers: [] });
|
|
395
|
+
expect(exit).toBe(0);
|
|
396
|
+
expect(observeMock).toHaveBeenCalledTimes(1);
|
|
397
|
+
const [, , , opts] = observeMock.mock.calls[0];
|
|
398
|
+
expect((opts as { stacks: string[] }).stacks.sort()).toEqual([
|
|
399
|
+
"loom-local-a-loom-backend",
|
|
400
|
+
"loom-local-a-loom-backend-jobs",
|
|
401
|
+
"loom-local-a-loom-db",
|
|
402
|
+
]);
|
|
403
|
+
expect((opts as { owned: boolean }).owned).toBe(true);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
test("component discovery errors: falls back to the single-stack path with a warning", async () => {
|
|
407
|
+
resolveLexMock.mockResolvedValue(["aws"]);
|
|
408
|
+
loadPluginsMock.mockResolvedValue([
|
|
409
|
+
{ name: "aws", serializer: {}, describeResources: () => Promise.resolve({}) },
|
|
410
|
+
]);
|
|
411
|
+
discoverComponentsMock.mockResolvedValue({ errors: [{ message: "bad component" }], sourceFiles: [], components: new Map() });
|
|
412
|
+
observeMock.mockResolvedValue({ observations: [], errors: [] });
|
|
413
|
+
const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, env: "prod" }), plugins: [], serializers: [] });
|
|
414
|
+
expect(exit).toBe(0);
|
|
415
|
+
expect(observeMock).toHaveBeenCalledWith("prod", expect.anything(), expect.anything(), {
|
|
416
|
+
owned: true,
|
|
417
|
+
stacks: [],
|
|
418
|
+
});
|
|
419
|
+
expect(stderrBuf.join("\n")).toMatch(/component discovery failed/i);
|
|
420
|
+
});
|
|
329
421
|
});
|
|
330
422
|
});
|
|
@@ -17,6 +17,8 @@ import { readFileSync } from "node:fs";
|
|
|
17
17
|
import { formatError, formatWarning, formatBold } from "../format";
|
|
18
18
|
import type { CommandContext } from "../registry";
|
|
19
19
|
import { computeComponentGraph } from "../../components/cli-support";
|
|
20
|
+
import { discoverComponents } from "../../components/discover";
|
|
21
|
+
import { cfnDeployStacks } from "./components";
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* `chant graph` — the Op dependency graph by default; `--stacks` renders the
|
|
@@ -96,7 +98,31 @@ async function runGraphLive(
|
|
|
96
98
|
return 1;
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
// Multi-stack, per-component projects (loomster/Floci, #57): AWS's
|
|
102
|
+
// single-stack convention (`describeResources` defaults to a stack named
|
|
103
|
+
// after the environment, lexicons/aws/src/plugin.ts) never matches a
|
|
104
|
+
// per-component layout (e.g. `loom-local-a-<component>`), so the plain
|
|
105
|
+
// single call always observes zero nodes. Resolve every discovered
|
|
106
|
+
// component's `cfn-deploy` stack(s) — the same walk `chant components
|
|
107
|
+
// status --live` uses (`cfnDeployStacks`, ./components.ts) — and hand them
|
|
108
|
+
// to `observeResources`, which queries `describeResources` once per stack
|
|
109
|
+
// and unions the results. A project with no components (or whose discovery
|
|
110
|
+
// errors) yields no stacks, so `observeResources` falls back to its
|
|
111
|
+
// original single-stack call — unchanged.
|
|
112
|
+
const componentsDiscovery = await discoverComponents(resolve(args.src ?? config.sourceDir ?? "."));
|
|
113
|
+
const stacks = new Set<string>();
|
|
114
|
+
if (componentsDiscovery.errors.length === 0) {
|
|
115
|
+
for (const { component } of componentsDiscovery.components.values()) {
|
|
116
|
+
for (const stack of cfnDeployStacks(component.deploy)) stacks.add(stack);
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
console.error(formatWarning({ message: "component discovery failed — observing the single-stack convention instead" }));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const { observations, errors } = await observeResources(environment, observing, buildResult, {
|
|
123
|
+
owned: true,
|
|
124
|
+
stacks: [...stacks],
|
|
125
|
+
});
|
|
100
126
|
for (const e of errors) console.error(formatWarning({ message: e }));
|
|
101
127
|
|
|
102
128
|
let ir: GraphIR = buildLiveGraphIr(observations);
|
|
@@ -945,6 +945,60 @@ describe("runOpComponents", () => {
|
|
|
945
945
|
vi.restoreAllMocks();
|
|
946
946
|
});
|
|
947
947
|
|
|
948
|
+
// ── --progress-json (M3, behold roadmap) ──────────────────────────────────
|
|
949
|
+
|
|
950
|
+
test("--progress-json streams NDJSON progress events to stdout as runComponents emits them", async () => {
|
|
951
|
+
runComponentsMock.mockImplementation(
|
|
952
|
+
async (_path: string, _selector: string, options: { onProgress?: (e: unknown) => void }) => {
|
|
953
|
+
options.onProgress?.({ type: "run-start", waves: [["svc"]] });
|
|
954
|
+
options.onProgress?.({ type: "run-done", status: "ok" });
|
|
955
|
+
return {
|
|
956
|
+
success: true,
|
|
957
|
+
selected: ["svc"],
|
|
958
|
+
run: { order: ["svc"], waves: [["svc"]], results: [{ component: "svc", ok: true, records: [] }], ok: true },
|
|
959
|
+
};
|
|
960
|
+
},
|
|
961
|
+
);
|
|
962
|
+
const stdoutWrite = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
963
|
+
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
964
|
+
|
|
965
|
+
const exit = await runOpComponents({
|
|
966
|
+
args: makeArgs({ path: "svc", progressJson: true, temporal: false }),
|
|
967
|
+
plugins: [],
|
|
968
|
+
serializers: [],
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
expect(exit).toBe(0);
|
|
972
|
+
const lines = stdoutWrite.mock.calls.map((c) => String(c[0])).filter((s) => s.trim().length > 0);
|
|
973
|
+
expect(lines.map((l) => JSON.parse(l))).toEqual([
|
|
974
|
+
{ type: "run-start", waves: [["svc"]] },
|
|
975
|
+
{ type: "run-done", status: "ok" },
|
|
976
|
+
]);
|
|
977
|
+
// Every line is a single, complete JSON object — real NDJSON, not one big blob.
|
|
978
|
+
for (const line of lines) expect(() => JSON.parse(line)).not.toThrow();
|
|
979
|
+
vi.restoreAllMocks();
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
test("without --progress-json, runComponents receives onProgress: undefined and nothing streams", async () => {
|
|
983
|
+
runComponentsMock.mockResolvedValue({
|
|
984
|
+
success: true,
|
|
985
|
+
selected: ["svc"],
|
|
986
|
+
run: { order: ["svc"], waves: [["svc"]], results: [{ component: "svc", ok: true, records: [] }], ok: true },
|
|
987
|
+
});
|
|
988
|
+
const stdoutWrite = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
989
|
+
vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
990
|
+
|
|
991
|
+
await runOpComponents({ args: makeArgs({ path: "svc", temporal: false }), plugins: [], serializers: [] });
|
|
992
|
+
|
|
993
|
+
expect(runComponentsMock).toHaveBeenCalledWith(expect.any(String), "svc", {
|
|
994
|
+
env: undefined,
|
|
995
|
+
componentOutputs: {},
|
|
996
|
+
onProgress: undefined,
|
|
997
|
+
});
|
|
998
|
+
expect(stdoutWrite).not.toHaveBeenCalled();
|
|
999
|
+
vi.restoreAllMocks();
|
|
1000
|
+
});
|
|
1001
|
+
|
|
948
1002
|
test("all: dispatches the 'all' selector and renders every component", async () => {
|
|
949
1003
|
runComponentsMock.mockResolvedValue({
|
|
950
1004
|
success: true,
|
package/src/cli/handlers/run.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { generateReport, writeReport } from "./run-report";
|
|
22
22
|
import { runComponents, resolveComponentTargets, findComponentGate, listComponents } from "../../components/cli-support";
|
|
23
23
|
import { renderDriverHuman, renderDriverJson } from "../../components/driver-output";
|
|
24
|
+
import { ndjsonProgressSink } from "../../components/run-progress";
|
|
24
25
|
import { loadComponentTemporalCodegen } from "../../components/temporal-codegen-loader";
|
|
25
26
|
import { applyConfigDefaults } from "../../components/config-defaults";
|
|
26
27
|
import { maybeRecordAutoRelease, extractRunDigestFromPhaseOutputs } from "../../components/auto-release";
|
|
@@ -686,7 +687,14 @@ export async function runOpComponents(ctx: CommandContext): Promise<number> {
|
|
|
686
687
|
return 1;
|
|
687
688
|
}
|
|
688
689
|
}
|
|
689
|
-
|
|
690
|
+
// `--progress-json` (#M3, behold roadmap): stream one NDJSON RunProgressEvent
|
|
691
|
+
// per line to stdout while the run executes, so a consumer (e.g. behold) can
|
|
692
|
+
// render live wave/component/phase/step progress instead of tailing raw
|
|
693
|
+
// logs. Purely additive: when the flag is absent, `onProgress` stays
|
|
694
|
+
// `undefined` and every `onProgress?.(...)` call in the driver is a no-op —
|
|
695
|
+
// behavior is byte-for-byte unchanged from before this flag existed.
|
|
696
|
+
const onProgress = ctx.args.progressJson ? ndjsonProgressSink() : undefined;
|
|
697
|
+
const result = await runComponents(resolve("."), selector, { env: ctx.args.env, componentOutputs: seededOutputs, onProgress });
|
|
690
698
|
|
|
691
699
|
// Dump the accumulated outputs for a downstream job to seed from. Written
|
|
692
700
|
// even on failure (partial outputs) so a resumed run still has what completed.
|
package/src/cli/main.test.ts
CHANGED
|
@@ -234,6 +234,20 @@ describe("parseArgs", () => {
|
|
|
234
234
|
const result = parseArgs(["run", "--components", "search-service"]);
|
|
235
235
|
expect(result.noReleaseRecord).toBeUndefined();
|
|
236
236
|
});
|
|
237
|
+
|
|
238
|
+
// ── --progress-json (M3, behold roadmap) ─────────────────────────────────
|
|
239
|
+
|
|
240
|
+
test("parses --progress-json for run --components", () => {
|
|
241
|
+
const result = parseArgs(["run", "--components", "search-service", "--env", "staging", "--progress-json"]);
|
|
242
|
+
expect(result.components).toBe(true);
|
|
243
|
+
expect(result.env).toBe("staging");
|
|
244
|
+
expect(result.progressJson).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("--progress-json is undefined (not false) when omitted", () => {
|
|
248
|
+
const result = parseArgs(["run", "--components", "search-service"]);
|
|
249
|
+
expect(result.progressJson).toBeUndefined();
|
|
250
|
+
});
|
|
237
251
|
});
|
|
238
252
|
|
|
239
253
|
// ── resolveCommand tests ──────────────────────────────────────────
|