@intentius/chant 0.17.0 → 0.18.1
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/commands/lint.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +5 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/rolling-upgrade.d.ts +1 -1
- package/dist/codegen/rolling-upgrade.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +10 -1
- package/dist/discovery/files.d.ts.map +1 -1
- package/dist/graph-ir.d.ts +18 -0
- package/dist/graph-ir.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/lint.ts +6 -0
- package/src/cli/handlers/graph.test.ts +44 -0
- package/src/cli/handlers/graph.ts +17 -5
- package/src/cli/main.ts +4 -0
- package/src/cli/registry.ts +5 -0
- package/src/codegen/rolling-upgrade.test.ts +59 -0
- package/src/codegen/rolling-upgrade.ts +3 -1
- package/src/discovery/files.test.ts +17 -0
- package/src/discovery/files.ts +29 -4
- package/src/graph-ir-live.test.ts +56 -1
- package/src/graph-ir.ts +51 -0
- package/src/op/activity-registry.test.ts +21 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAW,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAW,MAAM,iBAAiB,CAAC;AAkBzE;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAW5D;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAmBhC;AAgDD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,qCAAqC;IACrC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAsND;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAyI3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GACtC,MAAM,IAAI,CAiCZ"}
|
|
@@ -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"}
|
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,CAuLpD"}
|
package/dist/cli/registry.d.ts
CHANGED
|
@@ -60,6 +60,11 @@ 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 graph --live --overlay --overlay-anchor <source|live>` (#821) — which
|
|
64
|
+
* graph is the canvas. `source` (default) keeps the declared edges (the
|
|
65
|
+
* cross-substrate topology) and joins live status per node; `live` keeps the
|
|
66
|
+
* provisioned graph's reconstructed edges (the pre-#821 behaviour). */
|
|
67
|
+
overlayAnchor?: "source" | "live";
|
|
63
68
|
/** `chant list --components` / `chant graph --components` — surface discovered
|
|
64
69
|
* `Component` declarations (#560) instead of/alongside lexicon resources. */
|
|
65
70
|
components?: boolean;
|
|
@@ -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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"}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { type SurfaceDelta, type ChangeSeverity, type SurfaceSnapshot } from "./surface-snapshot.js";
|
|
23
23
|
import { type RegenOptions, type RegenResult } from "./lexicon-regen.js";
|
|
24
|
-
export type RollingLexicon = "aws" | "azure" | "github";
|
|
24
|
+
export type RollingLexicon = "aws" | "azure" | "github" | "fly";
|
|
25
25
|
/**
|
|
26
26
|
* An API-version change for one Azure ARM provider.
|
|
27
27
|
* Only populated for the azure lexicon.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rolling-upgrade.d.ts","sourceRoot":"","sources":["../../src/codegen/rolling-upgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAmC,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAIvG,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"rolling-upgrade.d.ts","sourceRoot":"","sources":["../../src/codegen/rolling-upgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAmC,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAIvG,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wFAAwF;IACxF,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,OAAO,EAAE,cAAc,CAAC;IACxB,mEAAmE;IACnE,UAAU,EAAE,OAAO,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,EAAE,cAAc,CAAC;IACzB,gCAAgC;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;IACtB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAClC,0EAA0E;IAC1E,eAAe,EAAE,qBAAqB,EAAE,CAAC;IACzC,wEAAwE;IACxE,aAAa,EAAE,eAAe,GAAG,IAAI,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACzD;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAoC/B;AA+BD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,eAAe,GACrB,qBAAqB,EAAE,CA6BzB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,qBAAqB,EAAE,CAmBzB;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,eAAe,GACrB,YAAY,CAEd;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG;IAClD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAIA"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker chant writes at the top of files it generates (worker/workflow/activities
|
|
3
|
+
* bootstrap for Temporal Ops, etc.). Discovery must not treat these as authored
|
|
4
|
+
* infra source: they hold no Declarables, they self-execute on import (the worker
|
|
5
|
+
* bootstrap calls `run()`), and they use runtime patterns the authored-source lint
|
|
6
|
+
* rules forbid (dynamic `process.env[...]` access, spreads). Skipping them keeps
|
|
7
|
+
* `chant lint`/`build` from importing or linting the tool's own output.
|
|
8
|
+
*/
|
|
9
|
+
export declare const GENERATED_MARKER = "Generated by chant \u2014 do not edit directly";
|
|
1
10
|
/**
|
|
2
11
|
* Recursively find all TypeScript infrastructure files in a directory
|
|
3
12
|
* @param path - The directory path to search
|
|
4
|
-
* @returns Array of file paths to .ts files (excluding test files)
|
|
13
|
+
* @returns Array of file paths to .ts files (excluding test files and chant-generated files)
|
|
5
14
|
*/
|
|
6
15
|
export declare function findInfraFiles(path: string): Promise<string[]>;
|
|
7
16
|
//# sourceMappingURL=files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/discovery/files.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/discovery/files.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,mDAA8C,CAAC;AAgB5E;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoDpE"}
|
package/dist/graph-ir.d.ts
CHANGED
|
@@ -137,4 +137,22 @@ export declare function buildLiveGraphIr(observations: LiveObservation[]): Graph
|
|
|
137
137
|
* no live edges). Sorted; the live groups pass through unchanged.
|
|
138
138
|
*/
|
|
139
139
|
export declare function overlayGraphs(live: GraphIR, declared: GraphIR): GraphIR;
|
|
140
|
+
/**
|
|
141
|
+
* Source-anchored overlay (#821) — the inverse of {@link overlayGraphs}. The
|
|
142
|
+
* **declared** graph is the canvas, so its edges are kept: cross-substrate edges
|
|
143
|
+
* (an ECS service wired to a k8s workload) are a source-graph property, since live
|
|
144
|
+
* reconstruction is per-substrate (identifier value-match) and never crosses
|
|
145
|
+
* providers. Use this when the overlay must keep the mixed topology; use
|
|
146
|
+
* `overlayGraphs` when the provisioned graph itself is the subject.
|
|
147
|
+
*
|
|
148
|
+
* Each declared node is classified against live observation and tagged `_status`:
|
|
149
|
+
* - **managed** (declared + provisioned) → `good`, carrying the observed
|
|
150
|
+
* `physicalId` / `ownership` onto the declared node
|
|
151
|
+
* - **pending** (declared, not provisioned) → `accent`
|
|
152
|
+
* **Foreign** resources (provisioned, not declared) are appended and tagged
|
|
153
|
+
* `warn`, together with any live-reconstructed edges that touch them — a declared
|
|
154
|
+
* edge cannot describe an undeclared resource. Declared groups/exports pass
|
|
155
|
+
* through unchanged; nodes and edges are sorted for deterministic output.
|
|
156
|
+
*/
|
|
157
|
+
export declare function sourceOverlayGraphs(declared: GraphIR, live: GraphIR): GraphIR;
|
|
140
158
|
//# sourceMappingURL=graph-ir.d.ts.map
|
package/dist/graph-ir.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-ir.d.ts","sourceRoot":"","sources":["../src/graph-ir.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-ir.d.ts","sourceRoot":"","sources":["../src/graph-ir.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli/commands/lint.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { RollbackPolicy } from "../../components/capability";
|
|
|
13
13
|
import { rule } from "../../lint/declarative";
|
|
14
14
|
import { watchDirectory, formatTimestamp, formatChangedFiles } from "../watch";
|
|
15
15
|
import { formatError, formatInfo } from "../format";
|
|
16
|
+
import { GENERATED_MARKER } from "../../discovery/files";
|
|
16
17
|
|
|
17
18
|
// Import config loader
|
|
18
19
|
import { loadConfig, resolveRulesForFile, parseRuleConfig } from "../../lint/config";
|
|
@@ -156,6 +157,11 @@ function getTypeScriptFiles(dir: string): string[] {
|
|
|
156
157
|
scan(fullPath);
|
|
157
158
|
}
|
|
158
159
|
} else if (entry.endsWith(".ts") && !entry.endsWith(".test.ts") && !entry.endsWith(".spec.ts")) {
|
|
160
|
+
// Skip chant-generated files (worker/workflow/activities bootstrap): they
|
|
161
|
+
// hold no authored source and use runtime patterns the EVL* rules forbid.
|
|
162
|
+
if (readFileSync(fullPath, "utf-8").slice(0, 256).includes(GENERATED_MARKER)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
159
165
|
files.push(fullPath);
|
|
160
166
|
}
|
|
161
167
|
}
|
|
@@ -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
|
});
|
|
@@ -2,7 +2,7 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import { discoverOps } from "../../op/discover";
|
|
3
3
|
import { discover } from "../../discovery/index";
|
|
4
4
|
import { partitionByLexicon, computeStackGraph, build } from "../../build";
|
|
5
|
-
import { buildGraphIr, buildLiveGraphIr, overlayGraphs, type GraphIR } from "../../graph-ir";
|
|
5
|
+
import { buildGraphIr, buildLiveGraphIr, overlayGraphs, sourceOverlayGraphs, type GraphIR } from "../../graph-ir";
|
|
6
6
|
import { reconstructEdges, mergeCatalogs, containmentGroups, type ReferenceCatalog, type ContainmentPair } from "../../graph-refs";
|
|
7
7
|
import { observeResources } from "../../lifecycle/observe";
|
|
8
8
|
import { loadChantConfig } from "../../config";
|
|
@@ -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}"`,
|
|
@@ -117,12 +122,19 @@ async function runGraphLive(
|
|
|
117
122
|
containment = reconstructed.containment;
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
// Drift overlay
|
|
121
|
-
//
|
|
125
|
+
// Drift overlay: classify each resource against declared source (managed /
|
|
126
|
+
// foreign / pending) so a renderer colours the drift. Two anchorings:
|
|
127
|
+
// - source (default, #821): declared graph is the canvas — keeps its edges,
|
|
128
|
+
// so cross-substrate topology survives; live status joined per node.
|
|
129
|
+
// - live (#780): provisioned graph is the canvas — reconstructed live edges.
|
|
122
130
|
if (args.overlay) {
|
|
123
131
|
const declared = await discover(resolve(args.src ?? config.sourceDir ?? "."));
|
|
124
132
|
if (declared.errors.length === 0) {
|
|
125
|
-
|
|
133
|
+
const declaredIr = buildGraphIr(declared.entities, projectPath);
|
|
134
|
+
ir =
|
|
135
|
+
args.overlayAnchor === "live"
|
|
136
|
+
? overlayGraphs(ir, declaredIr)
|
|
137
|
+
: sourceOverlayGraphs(declaredIr, ir);
|
|
126
138
|
} else {
|
|
127
139
|
console.error(formatWarning({ message: "overlay: source has discovery errors — showing the provisioned graph without the declared overlay" }));
|
|
128
140
|
}
|
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 === "--overlay-anchor") {
|
|
98
|
+
const v = args[++i];
|
|
99
|
+
if (v !== "source" && v !== "live") throw new Error(`--overlay-anchor must be 'source' or 'live', got '${v}'`);
|
|
100
|
+
result.overlayAnchor = v;
|
|
97
101
|
} else if (arg === "--from") {
|
|
98
102
|
// Shared by `migrate --from <lexicon>` and `import --from <env>`; the
|
|
99
103
|
// two commands never run together, so one field carries both.
|
package/src/cli/registry.ts
CHANGED
|
@@ -61,6 +61,11 @@ 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 graph --live --overlay --overlay-anchor <source|live>` (#821) — which
|
|
65
|
+
* graph is the canvas. `source` (default) keeps the declared edges (the
|
|
66
|
+
* cross-substrate topology) and joins live status per node; `live` keeps the
|
|
67
|
+
* provisioned graph's reconstructed edges (the pre-#821 behaviour). */
|
|
68
|
+
overlayAnchor?: "source" | "live";
|
|
64
69
|
/** `chant list --components` / `chant graph --components` — surface discovered
|
|
65
70
|
* `Component` declarations (#560) instead of/alongside lexicon resources. */
|
|
66
71
|
components?: boolean;
|
|
@@ -211,6 +211,65 @@ describe("checkRollingUpgrade — surface changed vs unchanged", () => {
|
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
213
|
|
|
214
|
+
// ── fly lexicon detection (rolls off the live Fly Machines OpenAPI) ────
|
|
215
|
+
|
|
216
|
+
function baselineFly(): SurfaceSnapshot {
|
|
217
|
+
return {
|
|
218
|
+
schemaVersion: 1,
|
|
219
|
+
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
220
|
+
entries: {
|
|
221
|
+
Machine: {
|
|
222
|
+
kind: "resource",
|
|
223
|
+
resourceType: "Fly::Machines::Machine",
|
|
224
|
+
props: ["name:false", "region:false", "config:false"],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Adds a new resource → additive upgrade. */
|
|
231
|
+
function freshFlyAdditive(): SurfaceSnapshot {
|
|
232
|
+
const s = baselineFly();
|
|
233
|
+
s.entries.Volume = {
|
|
234
|
+
kind: "resource",
|
|
235
|
+
resourceType: "Fly::Machines::Volume",
|
|
236
|
+
props: ["name:false", "size_gb:false"],
|
|
237
|
+
};
|
|
238
|
+
return s;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
describe("checkRollingUpgrade — fly", () => {
|
|
242
|
+
test("detects fly lexicon by package name", async () => {
|
|
243
|
+
const dir = makeLexiconDir("fly", baselineFly());
|
|
244
|
+
try {
|
|
245
|
+
const res = await checkRollingUpgrade({
|
|
246
|
+
lexiconDir: dir,
|
|
247
|
+
_regenFn: makeRegen(baselineFly(), baselineFly()),
|
|
248
|
+
});
|
|
249
|
+
expect(res.lexicon).toBe("fly");
|
|
250
|
+
expect(res.hasUpgrade).toBe(false);
|
|
251
|
+
expect(res.apiVersionDelta).toEqual([]); // fly has no ARM-style version delta
|
|
252
|
+
} finally {
|
|
253
|
+
rmSync(dir, { recursive: true, force: true });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test("a new resource in the Machines surface is an additive upgrade", async () => {
|
|
258
|
+
const dir = makeLexiconDir("fly", baselineFly());
|
|
259
|
+
try {
|
|
260
|
+
const res = await checkRollingUpgrade({
|
|
261
|
+
lexiconDir: dir,
|
|
262
|
+
_regenFn: makeRegen(freshFlyAdditive(), baselineFly()),
|
|
263
|
+
});
|
|
264
|
+
expect(res.lexicon).toBe("fly");
|
|
265
|
+
expect(res.hasUpgrade).toBe(true);
|
|
266
|
+
expect(res.severity).toBe("additive");
|
|
267
|
+
} finally {
|
|
268
|
+
rmSync(dir, { recursive: true, force: true });
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
214
273
|
// ── azure lexicon detection + apiVersionDelta ─────────────────────────
|
|
215
274
|
|
|
216
275
|
describe("checkRollingUpgrade — azure", () => {
|
|
@@ -34,7 +34,7 @@ import { regenLexicon, SNAPSHOT_FILENAME, type RegenOptions, type RegenResult }
|
|
|
34
34
|
|
|
35
35
|
// ── Public types ──────────────────────────────────────────────────────
|
|
36
36
|
|
|
37
|
-
export type RollingLexicon = "aws" | "azure" | "github";
|
|
37
|
+
export type RollingLexicon = "aws" | "azure" | "github" | "fly";
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* An API-version change for one Azure ARM provider.
|
|
@@ -157,6 +157,7 @@ function detectLexicon(lexiconDir: string): RollingLexicon {
|
|
|
157
157
|
const name = pkg.name ?? "";
|
|
158
158
|
if (name.includes("azure")) return "azure";
|
|
159
159
|
if (name.includes("github")) return "github";
|
|
160
|
+
if (name.includes("fly")) return "fly";
|
|
160
161
|
}
|
|
161
162
|
} catch {
|
|
162
163
|
// Fall through to directory-based detection
|
|
@@ -165,6 +166,7 @@ function detectLexicon(lexiconDir: string): RollingLexicon {
|
|
|
165
166
|
const normalized = lexiconDir.replace(/\\/g, "/");
|
|
166
167
|
if (/\/azure(\/|$)/.test(normalized)) return "azure";
|
|
167
168
|
if (/\/github(\/|$)/.test(normalized)) return "github";
|
|
169
|
+
if (/\/fly(\/|$)/.test(normalized)) return "fly";
|
|
168
170
|
return "aws";
|
|
169
171
|
}
|
|
170
172
|
|
|
@@ -151,4 +151,21 @@ describe("findInfraFiles", () => {
|
|
|
151
151
|
expect(files).toEqual([]);
|
|
152
152
|
});
|
|
153
153
|
});
|
|
154
|
+
|
|
155
|
+
test("skips chant-generated files (marker header)", async () => {
|
|
156
|
+
await withTestDir(async (testDir) => {
|
|
157
|
+
await writeFile(join(testDir, "app.ts"), "export const app = {};");
|
|
158
|
+
// A generated worker bootstrap: self-executes on import and uses runtime
|
|
159
|
+
// patterns the EVL* rules forbid — discovery must not pick it up.
|
|
160
|
+
await writeFile(
|
|
161
|
+
join(testDir, "worker.ts"),
|
|
162
|
+
"// Generated by chant — do not edit directly.\nrun();",
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const files = await findInfraFiles(testDir);
|
|
166
|
+
expect(files).toHaveLength(1);
|
|
167
|
+
expect(files[0]).toMatch(/app\.ts$/);
|
|
168
|
+
expect(files.some((f) => f.endsWith("worker.ts"))).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
154
171
|
});
|
package/src/discovery/files.ts
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
|
-
import { readdir, stat } from "node:fs/promises";
|
|
1
|
+
import { readdir, stat, open } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join, relative } from "node:path";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Marker chant writes at the top of files it generates (worker/workflow/activities
|
|
7
|
+
* bootstrap for Temporal Ops, etc.). Discovery must not treat these as authored
|
|
8
|
+
* infra source: they hold no Declarables, they self-execute on import (the worker
|
|
9
|
+
* bootstrap calls `run()`), and they use runtime patterns the authored-source lint
|
|
10
|
+
* rules forbid (dynamic `process.env[...]` access, spreads). Skipping them keeps
|
|
11
|
+
* `chant lint`/`build` from importing or linting the tool's own output.
|
|
12
|
+
*/
|
|
13
|
+
export const GENERATED_MARKER = "Generated by chant — do not edit directly";
|
|
14
|
+
|
|
15
|
+
/** True when a file's header carries the {@link GENERATED_MARKER}. Reads only the head. */
|
|
16
|
+
async function isGeneratedFile(file: string): Promise<boolean> {
|
|
17
|
+
let fh;
|
|
18
|
+
try {
|
|
19
|
+
fh = await open(file, "r");
|
|
20
|
+
const { buffer, bytesRead } = await fh.read({ buffer: Buffer.alloc(256), position: 0 });
|
|
21
|
+
return buffer.toString("utf8", 0, bytesRead).includes(GENERATED_MARKER);
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
} finally {
|
|
25
|
+
await fh?.close();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
5
29
|
/**
|
|
6
30
|
* Recursively find all TypeScript infrastructure files in a directory
|
|
7
31
|
* @param path - The directory path to search
|
|
8
|
-
* @returns Array of file paths to .ts files (excluding test files)
|
|
32
|
+
* @returns Array of file paths to .ts files (excluding test files and chant-generated files)
|
|
9
33
|
*/
|
|
10
34
|
export async function findInfraFiles(path: string): Promise<string[]> {
|
|
11
35
|
const files: string[] = [];
|
|
@@ -44,11 +68,12 @@ export async function findInfraFiles(path: string): Promise<string[]> {
|
|
|
44
68
|
}
|
|
45
69
|
await scanDirectory(fullPath);
|
|
46
70
|
} else if (entry.isFile()) {
|
|
47
|
-
// Include only .ts files, exclude test files
|
|
71
|
+
// Include only .ts files, exclude test files and chant-generated files
|
|
48
72
|
if (
|
|
49
73
|
entry.name.endsWith(".ts") &&
|
|
50
74
|
!entry.name.endsWith(".test.ts") &&
|
|
51
|
-
!entry.name.endsWith(".spec.ts")
|
|
75
|
+
!entry.name.endsWith(".spec.ts") &&
|
|
76
|
+
!(await isGeneratedFile(fullPath))
|
|
52
77
|
) {
|
|
53
78
|
files.push(fullPath);
|
|
54
79
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { buildLiveGraphIr, overlayGraphs, type LiveObservation, type GraphIR } from "./graph-ir";
|
|
2
|
+
import { buildLiveGraphIr, overlayGraphs, sourceOverlayGraphs, type LiveObservation, type GraphIR } from "./graph-ir";
|
|
3
3
|
|
|
4
4
|
// A fixture "snapshot" — what a lexicon's describeResources() returns for a live
|
|
5
5
|
// environment (managed-only). Two AWS resources; the subnet references the VPC by
|
|
@@ -86,3 +86,58 @@ describe("overlayGraphs (#780 drift overlay)", () => {
|
|
|
86
86
|
expect(ir.edges).toHaveLength(1);
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
|
+
|
|
90
|
+
describe("sourceOverlayGraphs (#821 source-anchored overlay)", () => {
|
|
91
|
+
const n = (id: string, lexicon = "aws") => ({ id, kind: "K", lexicon, attrs: {} });
|
|
92
|
+
// Declared graph carries a *cross-substrate* edge (a k8s ingress → an aws vpc)
|
|
93
|
+
// that live reconstruction — per-substrate identifier matching — can never make.
|
|
94
|
+
const declared: GraphIR = {
|
|
95
|
+
nodes: [n("web-vpc", "aws"), n("app-ingress", "k8s"), n("planned-db", "aws")],
|
|
96
|
+
edges: [{ from: "app-ingress", to: "web-vpc", kind: "ref", viaAttr: "vpcId" }],
|
|
97
|
+
groups: { byLexicon: { aws: ["planned-db", "web-vpc"], k8s: ["app-ingress"] } },
|
|
98
|
+
};
|
|
99
|
+
const live: GraphIR = {
|
|
100
|
+
nodes: [
|
|
101
|
+
{ id: "web-vpc", kind: "AWS::EC2::VPC", lexicon: "aws", attrs: {}, physicalId: "vpc-0a1b", ownership: "owned" },
|
|
102
|
+
n("app-ingress", "k8s"),
|
|
103
|
+
n("rogue-sg", "aws"),
|
|
104
|
+
],
|
|
105
|
+
edges: [{ from: "rogue-sg", to: "web-vpc", kind: "ref", viaAttr: "sg" }],
|
|
106
|
+
groups: {},
|
|
107
|
+
};
|
|
108
|
+
const statusOf = (ir: GraphIR, id: string) =>
|
|
109
|
+
(ir.nodes.find((x) => x.id === id)!.attrs as { _status?: string })._status;
|
|
110
|
+
|
|
111
|
+
it("classifies managed / pending / foreign via _status", () => {
|
|
112
|
+
const ir = sourceOverlayGraphs(declared, live);
|
|
113
|
+
expect(statusOf(ir, "web-vpc")).toBe("good"); // declared + provisioned
|
|
114
|
+
expect(statusOf(ir, "app-ingress")).toBe("good"); // declared + provisioned
|
|
115
|
+
expect(statusOf(ir, "planned-db")).toBe("accent"); // declared, not provisioned
|
|
116
|
+
expect(statusOf(ir, "rogue-sg")).toBe("warn"); // provisioned, not declared → foreign
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("keeps the declared cross-substrate edge (the whole point of source-anchoring)", () => {
|
|
120
|
+
const ir = sourceOverlayGraphs(declared, live);
|
|
121
|
+
expect(ir.edges).toContainEqual({ from: "app-ingress", to: "web-vpc", kind: "ref", viaAttr: "vpcId" });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("carries the observed physicalId/ownership onto a managed declared node", () => {
|
|
125
|
+
const ir = sourceOverlayGraphs(declared, live);
|
|
126
|
+
const vpc = ir.nodes.find((x) => x.id === "web-vpc")!;
|
|
127
|
+
expect(vpc.physicalId).toBe("vpc-0a1b");
|
|
128
|
+
expect(vpc.ownership).toBe("owned");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("appends foreign nodes with their live edges, and keeps declared groups", () => {
|
|
132
|
+
const ir = sourceOverlayGraphs(declared, live);
|
|
133
|
+
expect(ir.nodes.map((x) => x.id)).toContain("rogue-sg");
|
|
134
|
+
expect(ir.edges).toContainEqual({ from: "rogue-sg", to: "web-vpc", kind: "ref", viaAttr: "sg" }); // foreign-touching
|
|
135
|
+
expect(ir.groups.byLexicon).toEqual({ aws: ["planned-db", "web-vpc"], k8s: ["app-ingress"] });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("drops a live edge between two managed nodes — declared edges already cover it", () => {
|
|
139
|
+
const liveDup: GraphIR = { ...live, edges: [{ from: "app-ingress", to: "web-vpc", kind: "ref", viaAttr: "live-label" }] };
|
|
140
|
+
const ir = sourceOverlayGraphs(declared, liveDup);
|
|
141
|
+
expect(ir.edges.filter((e) => e.from === "app-ingress" && e.to === "web-vpc")).toHaveLength(1);
|
|
142
|
+
});
|
|
143
|
+
});
|
package/src/graph-ir.ts
CHANGED
|
@@ -421,3 +421,54 @@ export function overlayGraphs(live: GraphIR, declared: GraphIR): GraphIR {
|
|
|
421
421
|
|
|
422
422
|
return { ...live, nodes };
|
|
423
423
|
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Source-anchored overlay (#821) — the inverse of {@link overlayGraphs}. The
|
|
427
|
+
* **declared** graph is the canvas, so its edges are kept: cross-substrate edges
|
|
428
|
+
* (an ECS service wired to a k8s workload) are a source-graph property, since live
|
|
429
|
+
* reconstruction is per-substrate (identifier value-match) and never crosses
|
|
430
|
+
* providers. Use this when the overlay must keep the mixed topology; use
|
|
431
|
+
* `overlayGraphs` when the provisioned graph itself is the subject.
|
|
432
|
+
*
|
|
433
|
+
* Each declared node is classified against live observation and tagged `_status`:
|
|
434
|
+
* - **managed** (declared + provisioned) → `good`, carrying the observed
|
|
435
|
+
* `physicalId` / `ownership` onto the declared node
|
|
436
|
+
* - **pending** (declared, not provisioned) → `accent`
|
|
437
|
+
* **Foreign** resources (provisioned, not declared) are appended and tagged
|
|
438
|
+
* `warn`, together with any live-reconstructed edges that touch them — a declared
|
|
439
|
+
* edge cannot describe an undeclared resource. Declared groups/exports pass
|
|
440
|
+
* through unchanged; nodes and edges are sorted for deterministic output.
|
|
441
|
+
*/
|
|
442
|
+
export function sourceOverlayGraphs(declared: GraphIR, live: GraphIR): GraphIR {
|
|
443
|
+
const liveById = new Map(live.nodes.map((n) => [n.id, n]));
|
|
444
|
+
const declaredIds = new Set(declared.nodes.map((n) => n.id));
|
|
445
|
+
const foreignIds = new Set(live.nodes.filter((n) => !declaredIds.has(n.id)).map((n) => n.id));
|
|
446
|
+
const tagged = (n: IRNode, status: "good" | "warn" | "accent"): IRNode => ({ ...n, attrs: { ...n.attrs, _status: status } });
|
|
447
|
+
|
|
448
|
+
const nodes: IRNode[] = declared.nodes.map((n) => {
|
|
449
|
+
const obs = liveById.get(n.id);
|
|
450
|
+
if (!obs) return tagged(n, "accent"); // pending — declared, not provisioned
|
|
451
|
+
const merged: IRNode = { ...n }; // managed — carry the observed identity
|
|
452
|
+
if (obs.physicalId) merged.physicalId = obs.physicalId;
|
|
453
|
+
if (obs.ownership) merged.ownership = obs.ownership;
|
|
454
|
+
return tagged(merged, "good");
|
|
455
|
+
});
|
|
456
|
+
for (const n of live.nodes) if (foreignIds.has(n.id)) nodes.push(tagged(n, "warn")); // foreign
|
|
457
|
+
nodes.sort((a, b) => a.id.localeCompare(b.id));
|
|
458
|
+
|
|
459
|
+
// Declared edges are the canvas (the cross-substrate topology). Add only the
|
|
460
|
+
// live edges that touch a foreign node — declared edges already cover every
|
|
461
|
+
// declared relationship, so keeping all live edges would double managed ones.
|
|
462
|
+
const seen = new Set(declared.edges.map(edgeKey));
|
|
463
|
+
const edges = [...declared.edges];
|
|
464
|
+
for (const e of live.edges) {
|
|
465
|
+
if (!(foreignIds.has(e.from) || foreignIds.has(e.to))) continue;
|
|
466
|
+
const k = edgeKey(e);
|
|
467
|
+
if (seen.has(k)) continue;
|
|
468
|
+
seen.add(k);
|
|
469
|
+
edges.push(e);
|
|
470
|
+
}
|
|
471
|
+
edges.sort((a, b) => edgeKey(a).localeCompare(edgeKey(b)));
|
|
472
|
+
|
|
473
|
+
return { ...declared, nodes, edges };
|
|
474
|
+
}
|
|
@@ -12,7 +12,7 @@ describe("loadActivities", () => {
|
|
|
12
12
|
// Real export names from lexicons/temporal/src/op/activities.
|
|
13
13
|
expect(activities.has("shellCmd")).toBe(true);
|
|
14
14
|
expect(activities.has("chantBuild")).toBe(true);
|
|
15
|
-
expect(activities.has("
|
|
15
|
+
expect(activities.has("waitForStack")).toBe(true);
|
|
16
16
|
expect(activities.has("lifecycleDiff")).toBe(true);
|
|
17
17
|
expect(typeof activities.get("shellCmd")).toBe("function");
|
|
18
18
|
});
|
|
@@ -49,12 +49,12 @@ describe("resolveActivity", () => {
|
|
|
49
49
|
|
|
50
50
|
describe("loadActivities — heartbeat-shim safety", () => {
|
|
51
51
|
test("the activity library loads without @temporalio/activity installed", async () => {
|
|
52
|
-
// kubectlApply/helmInstall/
|
|
53
|
-
// lazy shim; if the shim statically required the SDK, this
|
|
54
|
-
// throw (the SDK is not installed in this environment).
|
|
52
|
+
// waitForStack (and the relocated kubectlApply/helmInstall/gitlabPipeline)
|
|
53
|
+
// heartbeat via the lazy shim; if the shim statically required the SDK, this
|
|
54
|
+
// import would throw (the SDK is not installed in this environment).
|
|
55
55
|
const activities = await loadActivities();
|
|
56
|
-
expect(activities.has("kubectlApply")).toBe(true);
|
|
57
56
|
expect(activities.has("waitForStack")).toBe(true);
|
|
57
|
+
expect(activities.has("chantBuild")).toBe(true);
|
|
58
58
|
});
|
|
59
59
|
});
|
|
60
60
|
|
|
@@ -62,10 +62,12 @@ describe("loadActivities — heartbeat-shim safety", () => {
|
|
|
62
62
|
// lexicons (#706); the loader pulls them in per the project's configured
|
|
63
63
|
// `lexicons`. Proves the relocation resolves end-to-end.
|
|
64
64
|
describe("loadActivities — multi-lexicon (#706)", () => {
|
|
65
|
-
test("base (no lexicons): temporal activities present,
|
|
65
|
+
test("base (no lexicons): temporal activities present, product activities absent", async () => {
|
|
66
66
|
const a = await loadActivities();
|
|
67
|
-
expect(a.has("
|
|
68
|
-
expect(a.has("
|
|
67
|
+
expect(a.has("waitForStack")).toBe(true); // temporal base
|
|
68
|
+
expect(a.has("shellCmd")).toBe(true); // temporal base
|
|
69
|
+
expect(a.has("kubectlApply")).toBe(false); // relocated to k8s (#809)
|
|
70
|
+
expect(a.has("k3dUp")).toBe(false); // relocated to k8s (#809)
|
|
69
71
|
expect(a.has("gcpApply")).toBe(false); // relocated to gcp
|
|
70
72
|
expect(a.has("flociUp")).toBe(false); // relocated to aws
|
|
71
73
|
expect(a.has("azGroupEnsure")).toBe(false); // relocated to azure
|
|
@@ -74,7 +76,16 @@ describe("loadActivities — multi-lexicon (#706)", () => {
|
|
|
74
76
|
test("gcp lexicon contributes the GCP applier", async () => {
|
|
75
77
|
const a = await loadActivities(["gcp"]);
|
|
76
78
|
expect(a.has("gcpApply")).toBe(true);
|
|
77
|
-
expect(a.has("
|
|
79
|
+
expect(a.has("waitForStack")).toBe(true); // base still loaded alongside
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("k8s lexicon contributes kubectl / k3d / argo activities (#809)", async () => {
|
|
83
|
+
const a = await loadActivities(["k8s"]);
|
|
84
|
+
expect(a.has("kubectlApply")).toBe(true);
|
|
85
|
+
expect(a.has("k3dUp")).toBe(true);
|
|
86
|
+
expect(a.has("k3dDown")).toBe(true);
|
|
87
|
+
expect(a.has("waitForArgoSync")).toBe(true);
|
|
88
|
+
expect(a.has("waitForStack")).toBe(true); // base still loaded alongside
|
|
78
89
|
});
|
|
79
90
|
|
|
80
91
|
test("aws lexicon contributes the Floci lifecycle", async () => {
|
|
@@ -92,6 +103,6 @@ describe("loadActivities — multi-lexicon (#706)", () => {
|
|
|
92
103
|
|
|
93
104
|
test("unknown lexicon is skipped without throwing", async () => {
|
|
94
105
|
const a = await loadActivities(["definitely-not-a-lexicon"]);
|
|
95
|
-
expect(a.has("
|
|
106
|
+
expect(a.has("waitForStack")).toBe(true); // temporal base still loads
|
|
96
107
|
});
|
|
97
108
|
});
|