@intentius/chant 0.18.0 → 0.18.2
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/graph.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +4 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +9 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/live-diff.d.ts +18 -0
- package/dist/lifecycle/live-diff.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/handlers/graph.test.ts +44 -0
- package/src/cli/handlers/graph.ts +6 -1
- package/src/cli/handlers/lifecycle.ts +79 -2
- package/src/cli/main.ts +4 -0
- package/src/cli/registry.ts +4 -0
- package/src/lifecycle/git.test.ts +16 -0
- package/src/lifecycle/git.ts +21 -0
- package/src/lifecycle/live-diff.test.ts +28 -1
- package/src/lifecycle/live-diff.ts +40 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/graph.ts"],"names":[],"mappings":"
|
|
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;AAGlD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAcnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/lifecycle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAoBlD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAwE/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC3E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/lifecycle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAoBlD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAwE/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC3E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C3E;AA2SD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA6G3E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1E;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9E;AAkBD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C/E"}
|
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":";AAKA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB9E;;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":";AAKA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA2LpD"}
|
package/dist/cli/registry.d.ts
CHANGED
|
@@ -60,6 +60,10 @@ export interface ParsedArgs {
|
|
|
60
60
|
/** `chant graph --live --overlay` — classify the provisioned graph against
|
|
61
61
|
* declared source: managed / foreign / pending (#780). */
|
|
62
62
|
overlay?: boolean;
|
|
63
|
+
/** `chant lifecycle diff <env> --between <refA> <refB>` (#822) — diff two saved
|
|
64
|
+
* snapshots (orphan-branch commits from `lifecycle log`) against each other. */
|
|
65
|
+
betweenA?: string;
|
|
66
|
+
betweenB?: string;
|
|
63
67
|
/** `chant graph --live --overlay --overlay-anchor <source|live>` (#821) — which
|
|
64
68
|
* graph is the canvas. `source` (default) keeps the declared edges (the
|
|
65
69
|
* cross-substrate topology) and joins live status per node; `live` keeps the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/lifecycle/git.d.ts
CHANGED
|
@@ -46,6 +46,15 @@ export declare function writeSnapshot(environment: string, lexicon: string, json
|
|
|
46
46
|
export declare function readSnapshot(environment: string, lexicon: string, opts?: {
|
|
47
47
|
cwd?: string;
|
|
48
48
|
}): Promise<string | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Read a snapshot at a specific orphan-branch commit (#822). `readSnapshot` reads
|
|
51
|
+
* the branch tip; this reads `<ref>:<env>/<lexicon>.json` for any commit `ref`
|
|
52
|
+
* (as listed by {@link listSnapshots}), so two historical snapshots can be diffed.
|
|
53
|
+
* Returns null if that env/lexicon wasn't captured at `ref`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function readSnapshotAt(environment: string, lexicon: string, ref: string, opts?: {
|
|
56
|
+
cwd?: string;
|
|
57
|
+
}): Promise<string | null>;
|
|
49
58
|
/**
|
|
50
59
|
* Append one immutable release record line to `<environment>/releases.jsonl`
|
|
51
60
|
* on the orphan branch (#568, epic #551 "Build & deploy observability"). Same
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lifecycle/git.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lifecycle/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,24 @@ export interface DiffLiveInput {
|
|
|
46
46
|
/** Resources captured by the previous snapshot, if any. */
|
|
47
47
|
observedThen: Record<string, ResourceMetadata> | undefined;
|
|
48
48
|
}
|
|
49
|
+
/** The delta between two saved snapshots (#822): a two-way observed diff. */
|
|
50
|
+
export interface SnapshotDiffResult {
|
|
51
|
+
/** In `next`, not in `prev`. */
|
|
52
|
+
added: string[];
|
|
53
|
+
/** In `prev`, not in `next`. */
|
|
54
|
+
removed: string[];
|
|
55
|
+
/** In both; metadata differs (with the attribute-level changes). */
|
|
56
|
+
changed: ResourceDrift[];
|
|
57
|
+
/** In both; metadata identical. */
|
|
58
|
+
unchanged: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Diff two **observed** snapshots (#822) — `prev` vs `next`, each a resources map
|
|
62
|
+
* read from the orphan branch. A two-way diff (no "declared" axis), so it answers
|
|
63
|
+
* "what changed in the cloud between two points" independent of source. Pure and
|
|
64
|
+
* deterministic (results sorted). Feeds the deployment-lanes frame-pair diff.
|
|
65
|
+
*/
|
|
66
|
+
export declare function diffSnapshots(prev: Record<string, ResourceMetadata>, next: Record<string, ResourceMetadata>): SnapshotDiffResult;
|
|
49
67
|
export declare function diffLive(input: DiffLiveInput): LiveDiffResult;
|
|
50
68
|
export interface LiveArtifactDiffResult {
|
|
51
69
|
/** Observed now, not in previous snapshot. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-diff.d.ts","sourceRoot":"","sources":["../../src/lifecycle/live-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mDAAmD;IACnD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mEAAmE;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAyCD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAiE7D;AAID,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iCAAiC;IACjC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,mCAAmC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB,CAmCvF"}
|
|
1
|
+
{"version":3,"file":"live-diff.d.ts","sourceRoot":"","sources":["../../src/lifecycle/live-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mDAAmD;IACnD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mEAAmE;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAyCD,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gCAAgC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,mCAAmC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACrC,kBAAkB,CAiBpB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAiE7D;AAID,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iCAAiC;IACjC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,mCAAmC;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB,CAmCvF"}
|
package/package.json
CHANGED
|
@@ -26,6 +26,28 @@ vi.mock("../../graph-layout", () => ({
|
|
|
26
26
|
getLayoutEngine: (name?: string) => ({ name: name ?? "dagre", layout: (input: unknown) => layoutMock(input) }),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
|
+
// --live path deps. `graph` isn't `requiresPlugins`, so the live handler loads
|
|
30
|
+
// plugins itself; mock that plus observation/build/config (existing tests only
|
|
31
|
+
// hit the Op-graph and source-view modes, so these mocks don't touch them).
|
|
32
|
+
const loadPluginsMock = vi.fn();
|
|
33
|
+
const resolveLexMock = vi.fn();
|
|
34
|
+
vi.mock("../plugins", () => ({
|
|
35
|
+
loadPlugins: (...a: unknown[]) => loadPluginsMock(...a),
|
|
36
|
+
resolveProjectLexicons: (...a: unknown[]) => resolveLexMock(...a),
|
|
37
|
+
}));
|
|
38
|
+
const observeMock = vi.fn();
|
|
39
|
+
vi.mock("../../lifecycle/observe", () => ({
|
|
40
|
+
observeResources: (...a: unknown[]) => observeMock(...a),
|
|
41
|
+
}));
|
|
42
|
+
vi.mock("../../config", () => ({
|
|
43
|
+
loadChantConfig: () => Promise.resolve({ config: {} }),
|
|
44
|
+
}));
|
|
45
|
+
vi.mock("../../build", () => ({
|
|
46
|
+
build: () => Promise.resolve({ errors: [] }),
|
|
47
|
+
partitionByLexicon: () => ({}),
|
|
48
|
+
computeStackGraph: () => ({}),
|
|
49
|
+
}));
|
|
50
|
+
|
|
29
51
|
const { runGraph } = await import("./graph");
|
|
30
52
|
|
|
31
53
|
function makeArgs(overrides: Partial<ParsedArgs> = {}): ParsedArgs {
|
|
@@ -204,4 +226,26 @@ describe("runGraph", () => {
|
|
|
204
226
|
expect(stderrBuf.join("\n")).toContain("boom");
|
|
205
227
|
});
|
|
206
228
|
});
|
|
229
|
+
|
|
230
|
+
describe("live graph (--live)", () => {
|
|
231
|
+
// Regression: `graph` is not `requiresPlugins`, so `ctx.plugins` is empty. The
|
|
232
|
+
// live path must load the project's plugins itself — otherwise it wrongly
|
|
233
|
+
// reports "No lexicons implement describeResources" and observes nothing.
|
|
234
|
+
test("loads plugins for --live when ctx.plugins is empty", async () => {
|
|
235
|
+
resolveLexMock.mockResolvedValue(["aws"]);
|
|
236
|
+
loadPluginsMock.mockResolvedValue([
|
|
237
|
+
{ name: "aws", serializer: {}, describeResources: () => Promise.resolve({}) },
|
|
238
|
+
]);
|
|
239
|
+
observeMock.mockResolvedValue({
|
|
240
|
+
observations: [{ lexicon: "aws", resources: { "web-vpc": { type: "AWS::EC2::VPC", status: "OK" } } }],
|
|
241
|
+
errors: [],
|
|
242
|
+
});
|
|
243
|
+
const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, env: "prod" }), plugins: [], serializers: [] });
|
|
244
|
+
expect(exit).toBe(0);
|
|
245
|
+
expect(loadPluginsMock).toHaveBeenCalled();
|
|
246
|
+
const out = stdoutBuf.join("\n");
|
|
247
|
+
expect(out).not.toContain("No lexicons implement describeResources");
|
|
248
|
+
expect(out).toContain("web-vpc");
|
|
249
|
+
});
|
|
250
|
+
});
|
|
207
251
|
});
|
|
@@ -12,6 +12,7 @@ import { toMermaid } from "../../graph-mermaid";
|
|
|
12
12
|
import { toDot } from "../../graph-dot";
|
|
13
13
|
import { getLayoutEngine, toLayoutInput, type NodeSize } from "../../graph-layout";
|
|
14
14
|
import { lintCommand } from "../commands/lint";
|
|
15
|
+
import { loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
15
16
|
import { readFileSync } from "node:fs";
|
|
16
17
|
import { formatError, formatWarning, formatBold } from "../format";
|
|
17
18
|
import type { CommandContext } from "../registry";
|
|
@@ -53,7 +54,7 @@ async function runGraphLive(
|
|
|
53
54
|
ctx: CommandContext,
|
|
54
55
|
format: "ir" | "mermaid" | "dot" | "layout",
|
|
55
56
|
): Promise<number> {
|
|
56
|
-
const { args
|
|
57
|
+
const { args } = ctx;
|
|
57
58
|
const environment = args.env;
|
|
58
59
|
if (!environment) {
|
|
59
60
|
console.error(formatError({ message: "chant graph --live needs an environment: --live --env <name>" }));
|
|
@@ -62,6 +63,10 @@ async function runGraphLive(
|
|
|
62
63
|
|
|
63
64
|
const projectPath = resolve(".");
|
|
64
65
|
const { config } = await loadChantConfig(projectPath);
|
|
66
|
+
// `graph` is not `requiresPlugins` (Op/source-graph modes must work without a
|
|
67
|
+
// lexicon), so `ctx.plugins` is empty. The live path needs the project's
|
|
68
|
+
// observation plugins — load them here, mirroring the lifecycle handlers.
|
|
69
|
+
const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(await resolveProjectLexicons(projectPath));
|
|
65
70
|
if (config.environments && !config.environments.includes(environment)) {
|
|
66
71
|
console.error(formatError({
|
|
67
72
|
message: `Unknown environment "${environment}"`,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { build } from "../../build";
|
|
3
3
|
import { takeSnapshot } from "../../lifecycle/snapshot";
|
|
4
|
-
import { readSnapshot, readEnvironmentSnapshots, listSnapshots, fetchLifecycle, StaleLifecycleBranchError } from "../../lifecycle/git";
|
|
4
|
+
import { readSnapshot, readSnapshotAt, readEnvironmentSnapshots, listSnapshots, fetchLifecycle, StaleLifecycleBranchError } from "../../lifecycle/git";
|
|
5
5
|
import { computeBuildDigest, diffDigests } from "../../lifecycle/digest";
|
|
6
|
-
import { diffLive, diffLiveArtifacts, type LiveDiffResult, type LiveArtifactDiffResult } from "../../lifecycle/live-diff";
|
|
6
|
+
import { diffLive, diffLiveArtifacts, diffSnapshots, type LiveDiffResult, type LiveArtifactDiffResult, type SnapshotDiffResult } from "../../lifecycle/live-diff";
|
|
7
7
|
import { buildChangeSet, renderChangeSet, gitlabMrReport, type ChangeSet } from "../../lifecycle/change-set";
|
|
8
8
|
import { affectedStacks } from "../../lifecycle/affected";
|
|
9
9
|
import { loadChantConfig } from "../../config";
|
|
@@ -159,6 +159,18 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
159
159
|
return 1;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
// `--between <refA> <refB>` (#822): diff two saved snapshots against each other.
|
|
163
|
+
// Purely historical — no build, no cloud query; reads the orphan branch.
|
|
164
|
+
if (args.betweenA && args.betweenB) {
|
|
165
|
+
return runLifecycleDiffBetween({
|
|
166
|
+
environment,
|
|
167
|
+
lexiconFilter,
|
|
168
|
+
refA: args.betweenA,
|
|
169
|
+
refB: args.betweenB,
|
|
170
|
+
json: !!args.json,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
162
174
|
// Filter serializers to target lexicon before building
|
|
163
175
|
const targetSerializers = lexiconFilter
|
|
164
176
|
? plugins.filter((p) => p.name === lexiconFilter).map((p) => p.serializer)
|
|
@@ -186,6 +198,71 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
186
198
|
return runLifecycleDiffDigest({ environment, lexicons, buildResult });
|
|
187
199
|
}
|
|
188
200
|
|
|
201
|
+
interface BetweenDiffArgs {
|
|
202
|
+
environment: string;
|
|
203
|
+
lexiconFilter?: string;
|
|
204
|
+
refA: string;
|
|
205
|
+
refB: string;
|
|
206
|
+
json: boolean;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* `chant lifecycle diff <env> --between <refA> <refB>` (#822). Diffs two saved
|
|
211
|
+
* snapshots against each other — read-only, no build, no cloud query. Reads
|
|
212
|
+
* `<ref>:<env>/<lexicon>.json` from the orphan branch at each ref and reports the
|
|
213
|
+
* two-way delta per lexicon.
|
|
214
|
+
*/
|
|
215
|
+
async function runLifecycleDiffBetween(args: BetweenDiffArgs): Promise<number> {
|
|
216
|
+
await fetchLifecycle();
|
|
217
|
+
const { config } = await loadChantConfig(resolve("."));
|
|
218
|
+
const lexicons = args.lexiconFilter ? [args.lexiconFilter] : config.lexicons ?? [];
|
|
219
|
+
if (lexicons.length === 0) {
|
|
220
|
+
console.error(formatError({ message: "No lexicons to diff — pass a lexicon or declare `lexicons` in chant.config." }));
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const parseResources = (content: string | null): Record<string, ResourceMetadata> | null => {
|
|
225
|
+
if (content === null) return null;
|
|
226
|
+
try {
|
|
227
|
+
return (JSON.parse(content) as LifecycleSnapshot).resources ?? {};
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const byLexicon: Record<string, SnapshotDiffResult> = {};
|
|
234
|
+
for (const lexicon of lexicons) {
|
|
235
|
+
const prev = parseResources(await readSnapshotAt(args.environment, lexicon, args.refA));
|
|
236
|
+
const next = parseResources(await readSnapshotAt(args.environment, lexicon, args.refB));
|
|
237
|
+
if (prev === null && next === null) {
|
|
238
|
+
if (!args.json) console.error(formatWarning({ message: `${lexicon}: not captured at either ref — skipping` }));
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
byLexicon[lexicon] = diffSnapshots(prev ?? {}, next ?? {});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (args.json) {
|
|
245
|
+
console.log(JSON.stringify({ environment: args.environment, refA: args.refA, refB: args.refB, lexicons: byLexicon }, null, 2));
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (Object.keys(byLexicon).length === 0) {
|
|
250
|
+
console.log(`No snapshots for ${args.environment} at ${args.refA} / ${args.refB}.`);
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(formatBold(`Snapshot diff — ${args.environment}: ${args.refA} → ${args.refB}`));
|
|
255
|
+
for (const [lexicon, d] of Object.entries(byLexicon)) {
|
|
256
|
+
console.log(
|
|
257
|
+
`\n${formatBold(lexicon)} — ${d.added.length} added, ${d.removed.length} removed, ${d.changed.length} changed, ${d.unchanged.length} unchanged`,
|
|
258
|
+
);
|
|
259
|
+
for (const name of d.added) console.log(` + ${name}`);
|
|
260
|
+
for (const name of d.removed) console.log(` - ${name}`);
|
|
261
|
+
for (const drift of d.changed) console.log(` ~ ${drift.name} (${drift.changes.map((c) => c.path).join(", ")})`);
|
|
262
|
+
}
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
189
266
|
interface DigestDiffArgs {
|
|
190
267
|
environment: string;
|
|
191
268
|
lexicons: string[];
|
package/src/cli/main.ts
CHANGED
|
@@ -94,6 +94,10 @@ export function parseArgs(args: string[]): ParsedArgs {
|
|
|
94
94
|
result.live = true;
|
|
95
95
|
} else if (arg === "--overlay") {
|
|
96
96
|
result.overlay = true;
|
|
97
|
+
} else if (arg === "--between") {
|
|
98
|
+
result.betweenA = args[++i];
|
|
99
|
+
result.betweenB = args[++i];
|
|
100
|
+
if (!result.betweenA || !result.betweenB) throw new Error("--between needs two snapshot refs: --between <refA> <refB>");
|
|
97
101
|
} else if (arg === "--overlay-anchor") {
|
|
98
102
|
const v = args[++i];
|
|
99
103
|
if (v !== "source" && v !== "live") throw new Error(`--overlay-anchor must be 'source' or 'live', got '${v}'`);
|
package/src/cli/registry.ts
CHANGED
|
@@ -61,6 +61,10 @@ export interface ParsedArgs {
|
|
|
61
61
|
/** `chant graph --live --overlay` — classify the provisioned graph against
|
|
62
62
|
* declared source: managed / foreign / pending (#780). */
|
|
63
63
|
overlay?: boolean;
|
|
64
|
+
/** `chant lifecycle diff <env> --between <refA> <refB>` (#822) — diff two saved
|
|
65
|
+
* snapshots (orphan-branch commits from `lifecycle log`) against each other. */
|
|
66
|
+
betweenA?: string;
|
|
67
|
+
betweenB?: string;
|
|
64
68
|
/** `chant graph --live --overlay --overlay-anchor <source|live>` (#821) — which
|
|
65
69
|
* graph is the canvas. `source` (default) keeps the declared edges (the
|
|
66
70
|
* cross-substrate topology) and joins live status per node; `live` keeps the
|
|
@@ -6,6 +6,7 @@ import { join } from "node:path";
|
|
|
6
6
|
import {
|
|
7
7
|
writeSnapshot,
|
|
8
8
|
readSnapshot,
|
|
9
|
+
readSnapshotAt,
|
|
9
10
|
readEnvironmentSnapshots,
|
|
10
11
|
listSnapshots,
|
|
11
12
|
getHeadCommit,
|
|
@@ -56,6 +57,21 @@ describe("lifecycle/git", () => {
|
|
|
56
57
|
});
|
|
57
58
|
});
|
|
58
59
|
|
|
60
|
+
test("readSnapshotAt reads a snapshot at a historical orphan-branch commit (#822)", async () => {
|
|
61
|
+
await withTestDir(async (dir) => {
|
|
62
|
+
await initRepo(dir);
|
|
63
|
+
await writeSnapshot("prod", "aws", JSON.stringify({ resources: { vpc: { type: "T", status: "OK" } } }), { cwd: dir });
|
|
64
|
+
await writeSnapshot("prod", "aws", JSON.stringify({ resources: { vpc: { type: "T", status: "OK" }, subnet: { type: "S", status: "OK" } } }), { cwd: dir });
|
|
65
|
+
const snaps = await listSnapshots({ cwd: dir }); // newest-first
|
|
66
|
+
expect(snaps.length).toBeGreaterThanOrEqual(2);
|
|
67
|
+
const older = await readSnapshotAt("prod", "aws", snaps[1].commit, { cwd: dir });
|
|
68
|
+
const newer = await readSnapshotAt("prod", "aws", snaps[0].commit, { cwd: dir });
|
|
69
|
+
expect(Object.keys(JSON.parse(older!).resources)).toEqual(["vpc"]);
|
|
70
|
+
expect(Object.keys(JSON.parse(newer!).resources).sort()).toEqual(["subnet", "vpc"]);
|
|
71
|
+
expect(await readSnapshotAt("prod", "gcp", snaps[0].commit, { cwd: dir })).toBeNull();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
59
75
|
test("subsequent writes preserve other env+lexicon entries", async () => {
|
|
60
76
|
await withTestDir(async (dir) => {
|
|
61
77
|
await initRepo(dir);
|
package/src/lifecycle/git.ts
CHANGED
|
@@ -166,6 +166,27 @@ export async function readSnapshot(
|
|
|
166
166
|
return readBlobFromPath(environment, `${lexicon}.json`, opts);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Read a snapshot at a specific orphan-branch commit (#822). `readSnapshot` reads
|
|
171
|
+
* the branch tip; this reads `<ref>:<env>/<lexicon>.json` for any commit `ref`
|
|
172
|
+
* (as listed by {@link listSnapshots}), so two historical snapshots can be diffed.
|
|
173
|
+
* Returns null if that env/lexicon wasn't captured at `ref`.
|
|
174
|
+
*/
|
|
175
|
+
export async function readSnapshotAt(
|
|
176
|
+
environment: string,
|
|
177
|
+
lexicon: string,
|
|
178
|
+
ref: string,
|
|
179
|
+
opts?: { cwd?: string },
|
|
180
|
+
): Promise<string | null> {
|
|
181
|
+
const rt = getRuntime();
|
|
182
|
+
const result = await rt.spawn(
|
|
183
|
+
["git", "show", `${ref}:${environment}/${lexicon}.json`],
|
|
184
|
+
{ cwd: opts?.cwd },
|
|
185
|
+
);
|
|
186
|
+
if (result.exitCode !== 0) return null;
|
|
187
|
+
return result.stdout;
|
|
188
|
+
}
|
|
189
|
+
|
|
169
190
|
/**
|
|
170
191
|
* Append one immutable release record line to `<environment>/releases.jsonl`
|
|
171
192
|
* on the orphan branch (#568, epic #551 "Build & deploy observability"). Same
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from "vitest";
|
|
2
|
-
import { diffLive, diffLiveArtifacts } from "./live-diff";
|
|
2
|
+
import { diffLive, diffLiveArtifacts, diffSnapshots } from "./live-diff";
|
|
3
3
|
import type { ResourceMetadata, ArtifactMetadata } from "../lexicon";
|
|
4
4
|
|
|
5
5
|
const meta = (overrides: Partial<ResourceMetadata> = {}): ResourceMetadata => ({
|
|
@@ -182,3 +182,30 @@ describe("diffLiveArtifacts", () => {
|
|
|
182
182
|
expect(result.unchanged).toEqual(["release/default/b"]);
|
|
183
183
|
});
|
|
184
184
|
});
|
|
185
|
+
|
|
186
|
+
describe("diffSnapshots (#822)", () => {
|
|
187
|
+
test("classifies added / removed / changed / unchanged between two snapshots", () => {
|
|
188
|
+
const prev = {
|
|
189
|
+
vpc: meta({ physicalId: "vpc-1" }),
|
|
190
|
+
subnet: meta({ physicalId: "subnet-1", status: "CREATE_COMPLETE" }),
|
|
191
|
+
gone: meta({ physicalId: "old" }),
|
|
192
|
+
};
|
|
193
|
+
const next = {
|
|
194
|
+
vpc: meta({ physicalId: "vpc-1" }), // unchanged
|
|
195
|
+
subnet: meta({ physicalId: "subnet-1", status: "UPDATE_COMPLETE" }), // changed (status)
|
|
196
|
+
fresh: meta({ physicalId: "new" }), // added
|
|
197
|
+
};
|
|
198
|
+
const d = diffSnapshots(prev, next);
|
|
199
|
+
expect(d.added).toEqual(["fresh"]);
|
|
200
|
+
expect(d.removed).toEqual(["gone"]);
|
|
201
|
+
expect(d.unchanged).toEqual(["vpc"]);
|
|
202
|
+
expect(d.changed.map((c) => c.name)).toEqual(["subnet"]);
|
|
203
|
+
expect(d.changed[0].changes.map((c) => c.path)).toContain("status");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("empty vs empty is all-unchanged-empty; results are sorted", () => {
|
|
207
|
+
expect(diffSnapshots({}, {})).toEqual({ added: [], removed: [], changed: [], unchanged: [] });
|
|
208
|
+
const d = diffSnapshots({}, { b: meta(), a: meta() });
|
|
209
|
+
expect(d.added).toEqual(["a", "b"]);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -90,6 +90,46 @@ function shallowEqual(a: unknown, b: unknown): boolean {
|
|
|
90
90
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** The delta between two saved snapshots (#822): a two-way observed diff. */
|
|
94
|
+
export interface SnapshotDiffResult {
|
|
95
|
+
/** In `next`, not in `prev`. */
|
|
96
|
+
added: string[];
|
|
97
|
+
/** In `prev`, not in `next`. */
|
|
98
|
+
removed: string[];
|
|
99
|
+
/** In both; metadata differs (with the attribute-level changes). */
|
|
100
|
+
changed: ResourceDrift[];
|
|
101
|
+
/** In both; metadata identical. */
|
|
102
|
+
unchanged: string[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Diff two **observed** snapshots (#822) — `prev` vs `next`, each a resources map
|
|
107
|
+
* read from the orphan branch. A two-way diff (no "declared" axis), so it answers
|
|
108
|
+
* "what changed in the cloud between two points" independent of source. Pure and
|
|
109
|
+
* deterministic (results sorted). Feeds the deployment-lanes frame-pair diff.
|
|
110
|
+
*/
|
|
111
|
+
export function diffSnapshots(
|
|
112
|
+
prev: Record<string, ResourceMetadata>,
|
|
113
|
+
next: Record<string, ResourceMetadata>,
|
|
114
|
+
): SnapshotDiffResult {
|
|
115
|
+
const added: string[] = [];
|
|
116
|
+
const removed: string[] = [];
|
|
117
|
+
const changed: ResourceDrift[] = [];
|
|
118
|
+
const unchanged: string[] = [];
|
|
119
|
+
for (const name of [...new Set([...Object.keys(prev), ...Object.keys(next)])].sort()) {
|
|
120
|
+
const a = prev[name];
|
|
121
|
+
const b = next[name];
|
|
122
|
+
if (!a && b) added.push(name);
|
|
123
|
+
else if (a && !b) removed.push(name);
|
|
124
|
+
else if (a && b) {
|
|
125
|
+
const changes = compareMetadata(a, b);
|
|
126
|
+
if (changes.length > 0) changed.push({ name, type: b.type ?? a.type, changes });
|
|
127
|
+
else unchanged.push(name);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return { added, removed, changed, unchanged };
|
|
131
|
+
}
|
|
132
|
+
|
|
93
133
|
export function diffLive(input: DiffLiveInput): LiveDiffResult {
|
|
94
134
|
const { declared, observedNow, observedThen } = input;
|
|
95
135
|
const observedThenMap = observedThen ?? {};
|