@intentius/chant 0.42.1 → 0.44.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/build.d.ts +15 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts +10 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +8 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +1 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/governance.d.ts +1 -1
- package/dist/graph-detail.d.ts +31 -13
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/lexicon.d.ts +44 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +7 -0
- package/dist/lifecycle/change-set.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/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lint/component-checks.d.ts +2 -1
- package/dist/lint/component-checks.d.ts.map +1 -1
- package/dist/observation.d.ts +33 -3
- package/dist/observation.d.ts.map +1 -1
- package/dist/reconcile.d.ts +5 -5
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/terraform/aws-resources.d.ts.map +1 -1
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +4 -3
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/audit/rules-doc.ts +1 -1
- package/src/build.test.ts +95 -0
- package/src/build.ts +46 -1
- package/src/cli/commands/build.ts +9 -1
- package/src/cli/commands/lint.ts +14 -3
- package/src/cli/handlers/components.ts +1 -1
- package/src/cli/handlers/graph.ts +32 -7
- package/src/cli/handlers/lifecycle.ts +15 -4
- package/src/cli/plugins.ts +17 -0
- package/src/codegen/publish-order.test.ts +1 -1
- package/src/codegen/release-wiring.test.ts +3 -4
- package/src/components/cli-support.test.ts +52 -0
- package/src/components/cli-support.ts +13 -2
- package/src/components/deploy-units.test.ts +13 -0
- package/src/components/deploy-units.ts +5 -0
- package/src/governance.test.ts +1 -1
- package/src/governance.ts +1 -1
- package/src/graph-detail.test.ts +117 -6
- package/src/graph-detail.ts +76 -18
- package/src/lexicon.ts +47 -0
- package/src/lifecycle/change-set.test.ts +26 -0
- package/src/lifecycle/change-set.ts +13 -0
- package/src/lifecycle/live-diff.test.ts +35 -0
- package/src/lifecycle/live-diff.ts +21 -0
- package/src/lifecycle/observe.ts +2 -1
- package/src/lint/component-checks.ts +8 -1
- package/src/observation.test.ts +54 -7
- package/src/observation.ts +53 -13
- package/src/reconcile.ts +7 -7
- package/src/terraform/aws-resources.test.ts +52 -2
- package/src/terraform/aws-resources.ts +95 -4
- package/src/terraform/graph.test.ts +17 -0
- package/src/terraform/graph.ts +12 -2
- package/src/terraform/tier-map.ts +60 -8
package/dist/reconcile.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* the plan renderer, and the guardrail framework (rename resolution + a removal
|
|
8
8
|
* cap + a pluggable check runner).
|
|
9
9
|
*
|
|
10
|
-
* A
|
|
10
|
+
* A consumer application (e.g. github-warden) builds its provider-specific resource diffing,
|
|
11
11
|
* live-state types, and domain guardrails on top of this, and drives them with
|
|
12
12
|
* the generic `runReconcile` loop + `Cycle` interface (below). It complements
|
|
13
13
|
* chant's `ownership.ts` marker contract: ownership markers make a `delete`
|
|
@@ -33,7 +33,7 @@ export interface ChangeSetEntry {
|
|
|
33
33
|
/** High-level resource category (e.g. "team", "member", "branch-protection"). */
|
|
34
34
|
resourceType: string;
|
|
35
35
|
/**
|
|
36
|
-
* Cross-provider governance category
|
|
36
|
+
* Cross-provider governance category. `resourceType` stays the
|
|
37
37
|
* provider-specific display string; the verb is the shared grammar SCM and
|
|
38
38
|
* cloud plans group by. Stamped by `runReconcile` from the cycle's `verb`.
|
|
39
39
|
*/
|
|
@@ -180,8 +180,8 @@ export interface Cycle<TClient, TConfig, TLive, TScope = unknown> {
|
|
|
180
180
|
/** Human-readable name, e.g. "branch-protection". */
|
|
181
181
|
name: string;
|
|
182
182
|
/**
|
|
183
|
-
* Cross-provider governance category this cycle reconciles
|
|
184
|
-
* SCM
|
|
183
|
+
* Cross-provider governance category this cycle reconciles. Every
|
|
184
|
+
* SCM reconciler cycles stamp one; cloud cycles must. Optional
|
|
185
185
|
* only so provider-external Cycle implementations don't break.
|
|
186
186
|
*/
|
|
187
187
|
verb?: GovernanceVerb;
|
|
@@ -192,7 +192,7 @@ export interface Cycle<TClient, TConfig, TLive, TScope = unknown> {
|
|
|
192
192
|
/** Per-cycle outcome recorded in the run result. */
|
|
193
193
|
export interface CycleResult {
|
|
194
194
|
name: string;
|
|
195
|
-
/** The cycle's governance verb
|
|
195
|
+
/** The cycle's governance verb, when it stamps one. */
|
|
196
196
|
verb?: GovernanceVerb;
|
|
197
197
|
/** Scope id this result is for (e.g. an org login). */
|
|
198
198
|
org: string;
|
package/dist/reconcile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../src/reconcile.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../src/reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-resources.d.ts","sourceRoot":"","sources":["../../src/terraform/aws-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,+DAA+D;AAC/D,KAAK,SAAS,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAA;CAAE,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,kEAAkE;IAClE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,iCAAiC,CAAC;AAajE,eAAO,MAAM,eAAe,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"aws-resources.d.ts","sourceRoot":"","sources":["../../src/terraform/aws-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,+DAA+D;AAC/D,KAAK,SAAS,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAA;CAAE,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,kEAAkE;IAClE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,iCAAiC,CAAC;AAajE,eAAO,MAAM,eAAe,EAAE,YAAY,EAqNzC,CAAC;AAIF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAErE;AASD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAoB1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/terraform/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAU,MAAM,SAAS,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AAKpE,UAAU,MAAM;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe/D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAc/D;
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/terraform/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAU,MAAM,SAAS,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AAKpE,UAAU,MAAM;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4BD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe/D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAc/D;AA4DD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAwEhF;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtE;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvE"}
|
|
@@ -29,9 +29,10 @@ export declare const TIER_MAP: Record<string, TierInfo>;
|
|
|
29
29
|
*/
|
|
30
30
|
export declare const FOLDS_INTO: Record<string, string>;
|
|
31
31
|
/**
|
|
32
|
-
* The HCL attribute carrying a resource's physical name, per type —
|
|
33
|
-
* from the
|
|
34
|
-
*
|
|
32
|
+
* The HCL attribute carrying a resource's physical name, per type — AWS entries
|
|
33
|
+
* derived from the carve-out table, non-AWS listed directly. A dotted entry is
|
|
34
|
+
* a path into nested blocks (`manifest.metadata.name`). Used for the graph's
|
|
35
|
+
* identity and the live-import hint. Absent → fall back to the TF logical name.
|
|
35
36
|
*/
|
|
36
37
|
export declare const IDENTITY_ATTR: Record<string, string>;
|
|
37
38
|
export declare function resolveTier(tfType: string): TierInfo | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tier-map.d.ts","sourceRoot":"","sources":["../../src/terraform/tier-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"tier-map.d.ts","sourceRoot":"","sources":["../../src/terraform/tier-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AA0CD,sEAAsE;AACtE,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAK7C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiB7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGhD,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE3D"}
|
package/package.json
CHANGED
package/src/audit/rules-doc.ts
CHANGED
|
@@ -14,7 +14,7 @@ const GROUPS: Array<{ heading: string; prefixes: string[]; blurb: string }> = [
|
|
|
14
14
|
{ heading: "GitHub Actions (GHA)", prefixes: ["GHA"], blurb: "Also applied to Forgejo workflows, which are GitHub-dialect." },
|
|
15
15
|
{ heading: "GitLab CI (WGL)", prefixes: ["WGL"], blurb: "" },
|
|
16
16
|
{ heading: "Forgejo (WFJ)", prefixes: ["WFJ"], blurb: "" },
|
|
17
|
-
{ heading: "Kubernetes (WK8 / ARGO)", prefixes: ["WK8", "ARGO"], blurb: "Run against Kubernetes manifests." },
|
|
17
|
+
{ heading: "Kubernetes (WK8 / ARGO / FLUX)", prefixes: ["WK8", "ARGO", "FLUX"], blurb: "Run against Kubernetes manifests." },
|
|
18
18
|
{ heading: "Docker (DKRD)", prefixes: ["DKRD"], blurb: "Run against Dockerfiles and Compose files." },
|
|
19
19
|
{ heading: "AWS CloudFormation (WAW / COR / EXT)", prefixes: ["WAW", "COR", "EXT"], blurb: "Run against CloudFormation templates (JSON or YAML)." },
|
|
20
20
|
{ heading: "Azure ARM (AZR)", prefixes: ["AZR"], blurb: "Run against ARM deployment templates (JSON)." },
|
package/src/build.test.ts
CHANGED
|
@@ -257,6 +257,101 @@ export const testEntity = {
|
|
|
257
257
|
});
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
+
describe("build-root contributors (#1548 piece 3)", () => {
|
|
261
|
+
let testDir: string;
|
|
262
|
+
|
|
263
|
+
beforeEach(async () => {
|
|
264
|
+
testDir = join(tmpdir(), `chant-buildroots-test-${Date.now()}-${Math.random()}`);
|
|
265
|
+
await mkdir(testDir, { recursive: true });
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
afterEach(async () => {
|
|
269
|
+
await rm(testDir, { recursive: true, force: true });
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const entity = (entityType: string): Declarable =>
|
|
273
|
+
({
|
|
274
|
+
lexicon: "test",
|
|
275
|
+
entityType,
|
|
276
|
+
kind: "resource",
|
|
277
|
+
props: {},
|
|
278
|
+
[DECLARABLE_MARKER]: true,
|
|
279
|
+
}) as unknown as Declarable;
|
|
280
|
+
|
|
281
|
+
const recordingSerializer = (seen: string[][]): Serializer => ({
|
|
282
|
+
name: "test",
|
|
283
|
+
rulePrefix: "TEST",
|
|
284
|
+
serialize: (entities) => {
|
|
285
|
+
seen.push([...entities.keys()]);
|
|
286
|
+
return "out";
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("contributed entities join the entity set and reach the serializer", async () => {
|
|
291
|
+
const seen: string[][] = [];
|
|
292
|
+
const result = await build(testDir, [recordingSerializer(seen)], undefined, {
|
|
293
|
+
buildRoots: [
|
|
294
|
+
async () => ({
|
|
295
|
+
entities: new Map([["overlays/prod/deploymentApp", entity("TestEntity")]]),
|
|
296
|
+
warnings: ["rendered a stray doc"],
|
|
297
|
+
}),
|
|
298
|
+
],
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(result.errors).toEqual([]);
|
|
302
|
+
expect(result.entities.has("overlays/prod/deploymentApp")).toBe(true);
|
|
303
|
+
expect(seen).toEqual([["overlays/prod/deploymentApp"]]);
|
|
304
|
+
expect(result.warnings).toContain("rendered a stray doc");
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("a contributor that throws becomes a build error carrying its message, not a thrown stack", async () => {
|
|
308
|
+
const result = await build(testDir, [], undefined, {
|
|
309
|
+
buildRoots: [
|
|
310
|
+
async () => {
|
|
311
|
+
throw new Error("neither the `kustomize` binary nor `kubectl` was found on PATH");
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
expect(result.errors).toHaveLength(1);
|
|
317
|
+
expect(result.errors[0].message).toContain("neither the `kustomize` binary nor `kubectl`");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("a contributed name colliding with a discovered entity is a build error, never an overwrite", async () => {
|
|
321
|
+
await writeFile(
|
|
322
|
+
join(testDir, "app.infra.ts"),
|
|
323
|
+
`
|
|
324
|
+
export const discovered = {
|
|
325
|
+
lexicon: "test",
|
|
326
|
+
entityType: "Discovered",
|
|
327
|
+
props: {},
|
|
328
|
+
[Symbol.for("chant.declarable")]: true,
|
|
329
|
+
};
|
|
330
|
+
`,
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
const result = await build(testDir, [recordingSerializer([])], undefined, {
|
|
334
|
+
buildRoots: [async () => ({ entities: new Map([["discovered", entity("Contributed")]]) })],
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
expect(result.errors.some((e) => e.message.includes('"discovered" collides'))).toBe(true);
|
|
338
|
+
expect(result.entities.get("discovered")?.entityType).toBe("Discovered");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("contributors run exactly once per build", async () => {
|
|
342
|
+
let calls = 0;
|
|
343
|
+
await build(testDir, [], undefined, {
|
|
344
|
+
buildRoots: [
|
|
345
|
+
async () => {
|
|
346
|
+
calls++;
|
|
347
|
+
return { entities: new Map() };
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
});
|
|
351
|
+
expect(calls).toBe(1);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
260
355
|
describe("partitionByLexicon", () => {
|
|
261
356
|
test("partitions entities by lexicon", () => {
|
|
262
357
|
const entities = new Map<string, Declarable>([
|
package/src/build.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Declarable } from "./declarable";
|
|
|
2
2
|
import type { Serializer, SerializerResult } from "./serializer";
|
|
3
3
|
import type { OwnershipMarker } from "./ownership";
|
|
4
4
|
import type { BuildError, DiscoveryErrorType } from "./errors";
|
|
5
|
-
import type { IntrinsicDef } from "./lexicon";
|
|
5
|
+
import type { IntrinsicDef, BuildRootContribution } from "./lexicon";
|
|
6
6
|
import type { BuildParamProvenance } from "./provenance";
|
|
7
7
|
import { DiscoveryError, BuildError as BuildErrorClass } from "./errors";
|
|
8
8
|
import { LexiconOutput, isLexiconOutput } from "./lexicon-output";
|
|
@@ -215,6 +215,21 @@ export interface BuildOptions {
|
|
|
215
215
|
* carries the already-resolved records for provenance.
|
|
216
216
|
*/
|
|
217
217
|
buildParams?: BuildParamProvenance[];
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* chant #1548 piece 3 — lexicon-contributed build roots: closures the CLI
|
|
221
|
+
* binds from each configured plugin's `buildRoots(ctx)` hook (see
|
|
222
|
+
* `collectBuildRootContributors` in ./cli/plugins.ts), each rendering a
|
|
223
|
+
* non-chant-source root (a kustomize overlay dir) into entities. Run once,
|
|
224
|
+
* at the TOP-LEVEL build only (never repeated for nested child projects),
|
|
225
|
+
* after discovery and before partitioning — so contributed entities are
|
|
226
|
+
* serialized, ownership-stamped, post-synth-checked and observed exactly
|
|
227
|
+
* like discovered ones. A contributor that throws becomes a build error
|
|
228
|
+
* carrying its message (the k8s hook's missing-binary refusal names the
|
|
229
|
+
* binaries); a contributed name colliding with a discovered entity is a
|
|
230
|
+
* build error, never a silent overwrite.
|
|
231
|
+
*/
|
|
232
|
+
buildRoots?: Array<() => Promise<BuildRootContribution>>;
|
|
218
233
|
}
|
|
219
234
|
|
|
220
235
|
export interface BuildResult {
|
|
@@ -657,6 +672,36 @@ async function buildFromDiscoveryResult(
|
|
|
657
672
|
}
|
|
658
673
|
}
|
|
659
674
|
|
|
675
|
+
// Step 4b (#1548 piece 3): lexicon-contributed build roots — rendered
|
|
676
|
+
// non-source roots (kustomize dirs) joining the entity set before
|
|
677
|
+
// partitioning, so everything downstream (serialization with ownership
|
|
678
|
+
// stamping, post-synth checks, observation) treats them as declared.
|
|
679
|
+
// Top-level build only: nested child builds receive the same options
|
|
680
|
+
// object, and re-running the contributors there would duplicate every
|
|
681
|
+
// contributed entity once per child.
|
|
682
|
+
if (!parentBuildStack && options?.buildRoots) {
|
|
683
|
+
for (const contribute of options.buildRoots) {
|
|
684
|
+
try {
|
|
685
|
+
const contribution = await contribute();
|
|
686
|
+
for (const w of contribution.warnings ?? []) warnings.push(w);
|
|
687
|
+
for (const [name, entity] of contribution.entities) {
|
|
688
|
+
if (discoveryResult.entities.has(name)) {
|
|
689
|
+
errors.push(
|
|
690
|
+
new BuildErrorClass(
|
|
691
|
+
"",
|
|
692
|
+
`Build-root entity "${name}" collides with a discovered entity of the same name`,
|
|
693
|
+
),
|
|
694
|
+
);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
discoveryResult.entities.set(name, entity);
|
|
698
|
+
}
|
|
699
|
+
} catch (error) {
|
|
700
|
+
errors.push(new BuildErrorClass("", error instanceof Error ? error.message : String(error)));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
660
705
|
// Step 5: Partition entities by lexicon
|
|
661
706
|
const partitions = partitionByLexicon(discoveryResult.entities);
|
|
662
707
|
|
|
@@ -3,7 +3,7 @@ import { loadChantConfigUpward, resolveOwnershipMarker, resolveFoldEnabled, reso
|
|
|
3
3
|
import { resolveCliBuildParams } from "../build-params-cli";
|
|
4
4
|
import type { Serializer, SerializerResult } from "../../serializer";
|
|
5
5
|
import type { LexiconPlugin } from "../../lexicon";
|
|
6
|
-
import { resolveLexiconVersions } from "../plugins";
|
|
6
|
+
import { resolveLexiconVersions, collectBuildRootContributors } from "../plugins";
|
|
7
7
|
import { runPostSynthChecks } from "../../lint/post-synth";
|
|
8
8
|
import { applyConfiguredSeverity } from "../../lint/config";
|
|
9
9
|
import { loadPolicyChecks } from "../../lint/policy";
|
|
@@ -261,6 +261,14 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
|
|
|
261
261
|
lexicons,
|
|
262
262
|
lexiconVersions,
|
|
263
263
|
buildParams: paramsResolution.provenance,
|
|
264
|
+
// #1548 piece 3 — config-declared build roots (kustomize dirs), rendered
|
|
265
|
+
// into entities by the owning lexicon's hook. Rooted at the config dir,
|
|
266
|
+
// not the (possibly sourceDir-scoped) infra path.
|
|
267
|
+
buildRoots: collectBuildRootContributors(
|
|
268
|
+
options.plugins,
|
|
269
|
+
config as unknown as Record<string, unknown>,
|
|
270
|
+
configDir,
|
|
271
|
+
),
|
|
264
272
|
});
|
|
265
273
|
|
|
266
274
|
// #1022 — report per-file fold vs run so it's visible what still runs.
|
package/src/cli/commands/lint.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve, join, relative } from "path";
|
|
2
|
+
import type { BuildParamProvenance } from "../../provenance";
|
|
2
3
|
import { readFileSync, writeFileSync, readdirSync, statSync } from "fs";
|
|
3
4
|
import { execFileSync } from "child_process";
|
|
4
5
|
import { runLint, parseDisableComments } from "../../lint/engine";
|
|
@@ -152,6 +153,15 @@ async function loadAllPluginRules(
|
|
|
152
153
|
export interface LintOptions {
|
|
153
154
|
/** Path to lint */
|
|
154
155
|
path: string;
|
|
156
|
+
/**
|
|
157
|
+
* This invocation's resolved build parameters (#1490).
|
|
158
|
+
*
|
|
159
|
+
* The COMP* checks import `*.component.ts`, and an ES module evaluates once
|
|
160
|
+
* per path — so the values in effect during the lint gate are the values
|
|
161
|
+
* every later reader observes. A caller that lints before it graphs must
|
|
162
|
+
* pass the same parameters to both or the later resolution has no effect.
|
|
163
|
+
*/
|
|
164
|
+
buildParams?: BuildParamProvenance[];
|
|
155
165
|
/** Apply auto-fixes */
|
|
156
166
|
fix?: boolean;
|
|
157
167
|
/** Output format */
|
|
@@ -334,6 +344,7 @@ async function resolveRegistryContext(
|
|
|
334
344
|
async function runComponentCheckDiagnostics(
|
|
335
345
|
infraPath: string,
|
|
336
346
|
sandbox?: boolean,
|
|
347
|
+
buildParams?: BuildParamProvenance[],
|
|
337
348
|
): Promise<{ diagnostics: LintDiagnostic[]; suppressed: Array<LintDiagnostic & { reason?: string }> }> {
|
|
338
349
|
// Discovery stays scoped to the lint arg; COMP* severity overrides come from
|
|
339
350
|
// the project-root config, same as the AST-rule pass.
|
|
@@ -342,7 +353,7 @@ async function runComponentCheckDiagnostics(
|
|
|
342
353
|
const allCheckIds = new Set(checks.map((c) => c.id));
|
|
343
354
|
|
|
344
355
|
const registryContext = await resolveRegistryContext(infraPath);
|
|
345
|
-
const raw = await runComponentChecks(infraPath, checks, registryContext, sandbox);
|
|
356
|
+
const raw = await runComponentChecks(infraPath, checks, registryContext, sandbox, buildParams);
|
|
346
357
|
|
|
347
358
|
const fileDirectivesCache = new Map<string, ReturnType<typeof parseDisableComments>>();
|
|
348
359
|
const fileLevelDisable = (
|
|
@@ -483,7 +494,7 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
|
|
|
483
494
|
// structurally distinct check family (whole-project, post-discovery,
|
|
484
495
|
// see ../../lint/component-checks.ts) but the same `chant lint` output and
|
|
485
496
|
// the same error-severity gating as every COR/EVL diagnostic.
|
|
486
|
-
const componentResult = await runComponentCheckDiagnostics(infraPath, options.sandbox);
|
|
497
|
+
const componentResult = await runComponentCheckDiagnostics(infraPath, options.sandbox, options.buildParams);
|
|
487
498
|
diagnostics.push(...componentResult.diagnostics);
|
|
488
499
|
suppressed.push(...componentResult.suppressed);
|
|
489
500
|
|
|
@@ -531,7 +542,7 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
|
|
|
531
542
|
// `*.component.ts` file on their behalf), but a fix applied to another
|
|
532
543
|
// rule could still be in the same file a component was discovered from —
|
|
533
544
|
// re-run for consistency with the AST re-lint above.
|
|
534
|
-
const postComponentResult = await runComponentCheckDiagnostics(infraPath, options.sandbox);
|
|
545
|
+
const postComponentResult = await runComponentCheckDiagnostics(infraPath, options.sandbox, options.buildParams);
|
|
535
546
|
diagnostics.push(...postComponentResult.diagnostics);
|
|
536
547
|
suppressed.push(...postComponentResult.suppressed);
|
|
537
548
|
}
|
|
@@ -430,7 +430,7 @@ export async function runComponentsStatus(ctx: CommandContext): Promise<number>
|
|
|
430
430
|
// rather than "stale" (recorded, and nothing live).
|
|
431
431
|
const message = err instanceof Error ? err.message : String(err);
|
|
432
432
|
console.error(formatWarning({ message: `${plugin.name}: describeResources failed — ${message} (components in this lexicon report unknown, not stale)` }));
|
|
433
|
-
observed = { resources: {}, unobserved: unobservedAll(declared, "read-failed", message, entities) };
|
|
433
|
+
observed = { resources: {}, unobserved: unobservedAll(declared, "read-failed", message, entities), queried: {} };
|
|
434
434
|
}
|
|
435
435
|
const cs = buildChangeSet(environment, {
|
|
436
436
|
declared,
|
|
@@ -378,7 +378,11 @@ async function runGraphLive(
|
|
|
378
378
|
*/
|
|
379
379
|
async function runComponentGraph(ctx: CommandContext): Promise<number> {
|
|
380
380
|
const projectPath = resolve(ctx.args.path === "." ? "." : ctx.args.path);
|
|
381
|
-
|
|
381
|
+
// #1490 — as in runComponentGraphView: the text/--json mode reads the same
|
|
382
|
+
// source and must not disagree with the --format modes about it.
|
|
383
|
+
const componentParams = await graphBuildParams(ctx, projectPath);
|
|
384
|
+
if (!componentParams) return 1;
|
|
385
|
+
const graph = await computeComponentGraph(projectPath, ctx.args.sandbox, componentParams);
|
|
382
386
|
|
|
383
387
|
if (!graph.success) {
|
|
384
388
|
console.error(formatError({ message: graph.error ?? "Failed to compute component graph" }));
|
|
@@ -434,7 +438,20 @@ async function runComponentGraphView(
|
|
|
434
438
|
): Promise<number> {
|
|
435
439
|
const projectPath = resolve(ctx.args.path === "." ? "." : ctx.args.path);
|
|
436
440
|
|
|
437
|
-
|
|
441
|
+
// #1490 — resolved BEFORE the lint gate, not after. The COMP* checks import
|
|
442
|
+
// every `*.component.ts`, an ES module evaluates once per path, and the
|
|
443
|
+
// values in effect at that first import are the ones the graph below will
|
|
444
|
+
// read no matter what it resolves for itself. Ordering is the fix; passing
|
|
445
|
+
// them to `computeComponentGraph` alone did nothing.
|
|
446
|
+
const componentParams = await graphBuildParams(ctx, projectPath);
|
|
447
|
+
if (!componentParams) return 1;
|
|
448
|
+
|
|
449
|
+
const lint = await lintCommand({
|
|
450
|
+
path: ctx.args.path,
|
|
451
|
+
format: "stylish",
|
|
452
|
+
sandbox: ctx.args.sandbox,
|
|
453
|
+
buildParams: componentParams,
|
|
454
|
+
});
|
|
438
455
|
if (!lint.success) {
|
|
439
456
|
console.error(
|
|
440
457
|
formatError({
|
|
@@ -444,7 +461,7 @@ async function runComponentGraphView(
|
|
|
444
461
|
return 1;
|
|
445
462
|
}
|
|
446
463
|
|
|
447
|
-
const graph = await computeComponentGraph(projectPath, ctx.args.sandbox);
|
|
464
|
+
const graph = await computeComponentGraph(projectPath, ctx.args.sandbox, componentParams);
|
|
448
465
|
if (!graph.success) {
|
|
449
466
|
console.error(formatError({ message: graph.error ?? "Failed to compute component graph" }));
|
|
450
467
|
return 1;
|
|
@@ -538,8 +555,19 @@ async function runGraphView(
|
|
|
538
555
|
return 1;
|
|
539
556
|
}
|
|
540
557
|
|
|
558
|
+
// Resolved before the gate for the reason in runComponentGraphView: the
|
|
559
|
+
// lint pass imports project source, and the first import of a module is the
|
|
560
|
+
// one that binds its parameter-derived values (#1490).
|
|
561
|
+
const buildParams = await graphBuildParams(ctx, projectPath);
|
|
562
|
+
if (!buildParams) return 1;
|
|
563
|
+
|
|
541
564
|
// Gate: only emit for lint-clean source.
|
|
542
|
-
const lint = await lintCommand({
|
|
565
|
+
const lint = await lintCommand({
|
|
566
|
+
path: ctx.args.path,
|
|
567
|
+
format: "stylish",
|
|
568
|
+
sandbox: ctx.args.sandbox,
|
|
569
|
+
buildParams,
|
|
570
|
+
});
|
|
543
571
|
if (!lint.success) {
|
|
544
572
|
console.error(
|
|
545
573
|
formatError({
|
|
@@ -550,9 +578,6 @@ async function runGraphView(
|
|
|
550
578
|
return 1;
|
|
551
579
|
}
|
|
552
580
|
|
|
553
|
-
const buildParams = await graphBuildParams(ctx, projectPath);
|
|
554
|
-
if (!buildParams) return 1;
|
|
555
|
-
|
|
556
581
|
const result = await discover(projectPath, { buildParams });
|
|
557
582
|
if (result.errors.length > 0) {
|
|
558
583
|
for (const e of result.errors) console.error(formatError({ message: e.message }));
|
|
@@ -31,6 +31,7 @@ import { cfnDeployStacks } from "./components";
|
|
|
31
31
|
import { affectedStacks } from "../../lifecycle/affected";
|
|
32
32
|
import { rollbackToRevision } from "../../lifecycle/rollback";
|
|
33
33
|
import { loadChantConfig, environmentNames } from "../../config";
|
|
34
|
+
import { collectBuildRootContributors } from "../plugins";
|
|
34
35
|
import { applyLiveEndpoint } from "../../live-endpoint";
|
|
35
36
|
import { isResourceDeclarable } from "../../declarable";
|
|
36
37
|
import { formatError, formatWarning, formatSuccess, formatBold } from "../format";
|
|
@@ -150,9 +151,10 @@ export async function runLifecycleSnapshot(ctx: CommandContext): Promise<number>
|
|
|
150
151
|
// estate; a region whose stack declares no security group still has a default
|
|
151
152
|
// one, and scoping the bound per stack silently drops it.
|
|
152
153
|
const built: Array<{ target: (typeof targets)[number]; buildResult: Awaited<ReturnType<typeof build>> }> = [];
|
|
154
|
+
const buildRoots = collectBuildRootContributors(targetPlugins, config as unknown as Record<string, unknown>, projectPath);
|
|
153
155
|
for (const target of targets) {
|
|
154
156
|
const label = target.stack ? `stack "${target.stack}"` : "project";
|
|
155
|
-
const buildResult = await build(target.root, targetSerializers, undefined, { buildParams: declaredParams });
|
|
157
|
+
const buildResult = await build(target.root, targetSerializers, undefined, { buildParams: declaredParams, buildRoots });
|
|
156
158
|
if (buildResult.errors.length > 0) {
|
|
157
159
|
console.error(formatError({ message: `Build failed for ${label} — fix errors before taking a snapshot` }));
|
|
158
160
|
anyHardError = true;
|
|
@@ -363,9 +365,11 @@ export async function runLifecycleDiff(ctx: CommandContext): Promise<number> {
|
|
|
363
365
|
const endpointResult = applyLiveEndpoint(config.environments, environment, liveLexicons);
|
|
364
366
|
if (endpointResult.notice) console.error(formatWarning({ message: endpointResult.notice }));
|
|
365
367
|
|
|
368
|
+
const diffBuildRoots = collectBuildRootContributors(plugins, config as unknown as Record<string, unknown>, resolve("."));
|
|
369
|
+
|
|
366
370
|
try {
|
|
367
371
|
for (const target of targets) {
|
|
368
|
-
const buildResult = await build(target.root, targetSerializers, undefined, { buildParams: declaredParams });
|
|
372
|
+
const buildResult = await build(target.root, targetSerializers, undefined, { buildParams: declaredParams, buildRoots: diffBuildRoots });
|
|
369
373
|
if (buildResult.errors.length > 0) {
|
|
370
374
|
const label = target.stack ? `stack "${target.stack}"` : "project";
|
|
371
375
|
console.error(formatError({ message: `Build failed for ${label} — fix errors before diffing` }));
|
|
@@ -733,6 +737,7 @@ async function observeLexicon(
|
|
|
733
737
|
return {
|
|
734
738
|
resources: {},
|
|
735
739
|
unobserved: unobservedAll(entityNames, "read-failed", message, opts.entities),
|
|
740
|
+
queried: {},
|
|
736
741
|
};
|
|
737
742
|
}
|
|
738
743
|
}
|
|
@@ -802,7 +807,7 @@ async function runLifecycleDiffLive(args: LiveDiffArgs): Promise<LiveDiffOutcome
|
|
|
802
807
|
});
|
|
803
808
|
const observedNow = observed.resources;
|
|
804
809
|
const observedThen = prevSnapshot?.resources;
|
|
805
|
-
const diff = diffLive({ declared, observedNow, observedThen, unobserved: observed.unobserved });
|
|
810
|
+
const diff = diffLive({ declared, observedNow, observedThen, unobserved: observed.unobserved, queried: observed.queried });
|
|
806
811
|
// Unobserved entities are deliberately NOT drift: a hole in the read is
|
|
807
812
|
// not a change in the cloud. They are reported separately (#1089) so a
|
|
808
813
|
// "no drift detected" line can never be built on top of a failed read.
|
|
@@ -958,7 +963,12 @@ function renderLiveDiff(lexiconName: string, environment: string, diff: LiveDiff
|
|
|
958
963
|
}
|
|
959
964
|
if (diff.missing.length > 0) {
|
|
960
965
|
console.log(formatBold("\nMISSING (declared, provider reports not in cloud):"));
|
|
961
|
-
for (const name of diff.missing)
|
|
966
|
+
for (const name of diff.missing) {
|
|
967
|
+
// The address the read actually went to (#1620) — the line between "not
|
|
968
|
+
// there" and "looked in the wrong place" (a defaulted namespace, say).
|
|
969
|
+
const queried = diff.queried?.[name];
|
|
970
|
+
console.log(` - ${name}${queried ? ` [queried ${queried}]` : ""}`);
|
|
971
|
+
}
|
|
962
972
|
}
|
|
963
973
|
if (diff.orphan.length > 0) {
|
|
964
974
|
console.log(formatBold("\nORPHAN (in cloud, not declared):"));
|
|
@@ -1063,6 +1073,7 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1063
1073
|
if (!declaredParams) return 1;
|
|
1064
1074
|
const buildResult = await build(resolveBuildRoot(args, config), targetSerializers, undefined, {
|
|
1065
1075
|
buildParams: declaredParams,
|
|
1076
|
+
buildRoots: collectBuildRootContributors(plugins, config as unknown as Record<string, unknown>, resolve(".")),
|
|
1066
1077
|
});
|
|
1067
1078
|
if (buildResult.errors.length > 0) {
|
|
1068
1079
|
console.error(formatError({ message: "Build failed — fix errors before planning" }));
|
package/src/cli/plugins.ts
CHANGED
|
@@ -95,6 +95,23 @@ export function resolveLexiconVersions(lexiconNames: readonly string[]): Record<
|
|
|
95
95
|
return versions;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Bind each loaded plugin's `buildRoots` hook (#1548 piece 3) to this
|
|
100
|
+
* invocation's config and project root, producing the closures
|
|
101
|
+
* `BuildOptions.buildRoots` takes — the same extract-then-thread shape the
|
|
102
|
+
* CLI uses for `intrinsics`. Plugins without the hook contribute nothing;
|
|
103
|
+
* an empty array is the common case and `build()` treats it as absent.
|
|
104
|
+
*/
|
|
105
|
+
export function collectBuildRootContributors(
|
|
106
|
+
plugins: readonly LexiconPlugin[] | undefined,
|
|
107
|
+
config: Record<string, unknown>,
|
|
108
|
+
projectRoot: string,
|
|
109
|
+
): Array<() => Promise<import("../lexicon").BuildRootContribution>> {
|
|
110
|
+
return (plugins ?? [])
|
|
111
|
+
.filter((plugin) => typeof plugin.buildRoots === "function")
|
|
112
|
+
.map((plugin) => () => plugin.buildRoots!({ projectRoot, config }));
|
|
113
|
+
}
|
|
114
|
+
|
|
98
115
|
/**
|
|
99
116
|
* Load plugins for all detected lexicon names.
|
|
100
117
|
* Calls `init()` on each plugin if present.
|
|
@@ -48,7 +48,7 @@ describe("publish order", () => {
|
|
|
48
48
|
// same stranding by a different route.
|
|
49
49
|
const all = execFileSync(
|
|
50
50
|
"bash",
|
|
51
|
-
["-c", 'for d in packages/*/ lexicons
|
|
51
|
+
["-c", 'for d in packages/*/ lexicons/*/; do [ -f "$d/package.json" ] && echo "${d%/}"; done'],
|
|
52
52
|
{ cwd: REPO, encoding: "utf8" },
|
|
53
53
|
)
|
|
54
54
|
.split("\n")
|
|
@@ -118,10 +118,9 @@ function recipeBody(name: string): string {
|
|
|
118
118
|
*/
|
|
119
119
|
describe("release wiring: peer ranges stay in lockstep (#1255)", () => {
|
|
120
120
|
it("the whole-repo release rewrites every @intentius peer range", () => {
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// rewrite goes stale the same way the hand-listed publish steps did.
|
|
121
|
+
// The rewrite is generic (`with_entries` over every `@intentius/*`
|
|
122
|
+
// peer) rather than named keys — a hand-listed rewrite goes stale the
|
|
123
|
+
// same way the hand-listed publish steps did.
|
|
125
124
|
const body = recipeBody("release");
|
|
126
125
|
expect(body).toMatch(/\.peerDependencies\s*\|=\s*with_entries/);
|
|
127
126
|
expect(body).toMatch(/startswith\("@intentius\/"\)/);
|
|
@@ -229,6 +229,58 @@ describe("computeComponentGraph", () => {
|
|
|
229
229
|
expect(result.edges).toEqual([]);
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
+
// #1490 — `discoverComponents` has honoured buildParams since #1108, but
|
|
233
|
+
// every caller stopped short of passing them, so the component graph was
|
|
234
|
+
// always the default-parameter graph. A component conditioned on a parameter
|
|
235
|
+
// survived `--param` that removed the resources it describes, and `chant
|
|
236
|
+
// build` and `chant graph --components` disagreed about the same source.
|
|
237
|
+
//
|
|
238
|
+
// The fixture imports the params module by absolute path rather than by the
|
|
239
|
+
// `@intentius/chant/params` specifier: it is written to a temp dir with no
|
|
240
|
+
// node_modules, so the bare specifier would resolve elsewhere (or nowhere)
|
|
241
|
+
// and the fixture would read a DIFFERENT params object than the one
|
|
242
|
+
// discovery mutates — passing the test for the wrong reason.
|
|
243
|
+
const paramsModule = new URL("../params.ts", import.meta.url).pathname;
|
|
244
|
+
const conditionalComponent = `import { params } from ${JSON.stringify(paramsModule)};
|
|
245
|
+
export const backup =
|
|
246
|
+
params.backups === "omit"
|
|
247
|
+
? undefined
|
|
248
|
+
: { name: "backup", dependsOn: [], deploy: [{ phase: "Apply", steps: [{ kind: "shell", reason: "t" }] }] };`;
|
|
249
|
+
|
|
250
|
+
// A fresh directory per call: the ESM loader caches a module by path, so
|
|
251
|
+
// re-importing the same fixture would replay the FIRST call's parameter
|
|
252
|
+
// binding and the assertion would pass or fail for the wrong reason.
|
|
253
|
+
async function graphWith(
|
|
254
|
+
dir: string,
|
|
255
|
+
provenance?: Array<{ name: string; value: string; source: "cli" }>,
|
|
256
|
+
) {
|
|
257
|
+
await mkdir(dir, { recursive: true });
|
|
258
|
+
await writeFile(join(dir, "backup.component.ts"), conditionalComponent);
|
|
259
|
+
return computeComponentGraph(dir, undefined, provenance);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
test("a component conditioned on a build parameter follows the parameter", async () => {
|
|
263
|
+
const omitted = await graphWith(join(testDir, "omit"), [
|
|
264
|
+
{ name: "backups", value: "omit", source: "cli" },
|
|
265
|
+
]);
|
|
266
|
+
expect(omitted.success).toBe(true);
|
|
267
|
+
expect(omitted.order).toEqual([]);
|
|
268
|
+
|
|
269
|
+
const kept = await graphWith(join(testDir, "keep"), [
|
|
270
|
+
{ name: "backups", value: "pg-dump", source: "cli" },
|
|
271
|
+
]);
|
|
272
|
+
expect(kept.success).toBe(true);
|
|
273
|
+
expect(kept.order).toEqual(["backup"]);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Supplying none must not inherit whatever a previous call set — the same
|
|
277
|
+
// leak `discoverComponents`'s unconditional setBuildParams guards against.
|
|
278
|
+
test("passing no parameters does not inherit the previous call's", async () => {
|
|
279
|
+
await graphWith(join(testDir, "first"), [{ name: "backups", value: "omit", source: "cli" }]);
|
|
280
|
+
const fresh = await graphWith(join(testDir, "second"));
|
|
281
|
+
expect(fresh.order).toEqual(["backup"]);
|
|
282
|
+
});
|
|
283
|
+
|
|
232
284
|
test("orders a consumer after its producer, with a consumer → producer edge", async () => {
|
|
233
285
|
await writeFile(
|
|
234
286
|
join(testDir, "alb.component.ts"),
|