@intentius/chant 0.69.1 → 0.70.0
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/lifecycle.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAE9E;AAmCD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAyH/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C3E;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAmL3E;AAmrBD;;;;;;;;;GASG;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":"AA6CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAE9E;AAmCD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAyH/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C3E;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B/E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAmL3E;AAmrBD;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqR3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA2L/E;AAsBD;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1E;AAgBD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAmE7E;AAiCD;;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":";AAMA,OAAO,EAAkB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAwF9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6VpD;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAMA,OAAO,EAAkB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAwF9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6VpD;AAqbD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,UAAU,EAkGvC,CAAC;AAgIF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5E"}
|
package/package.json
CHANGED
|
@@ -916,6 +916,71 @@ describe("runLifecyclePlan", () => {
|
|
|
916
916
|
// #2162 — a held property is not an action, so the plan carries it beside
|
|
917
917
|
// `entries` rather than inside one, attributed to its lexicon the same way
|
|
918
918
|
// an entry is.
|
|
919
|
+
test("without --deep the pass does not run, and the entries are unchanged (#2405)", async () => {
|
|
920
|
+
// The property that makes `--deep` safe to default off: a held property is
|
|
921
|
+
// never a proposal, so the change set is identical either way and the only
|
|
922
|
+
// thing the flag buys is the HELD section. If that stops being true, this
|
|
923
|
+
// is where it shows.
|
|
924
|
+
const makeBuild = () => {
|
|
925
|
+
const b = makeBuildResult({ k8s: ["web"] });
|
|
926
|
+
b.entities.set("web", {
|
|
927
|
+
lexicon: "k8s",
|
|
928
|
+
entityType: "K8s::Apps::Deployment",
|
|
929
|
+
props: { spec: { replicas: heldElsewhere<number>({ by: "hpa", reason: "the autoscaler owns replicas after the first apply" }) } },
|
|
930
|
+
} as never);
|
|
931
|
+
return b;
|
|
932
|
+
};
|
|
933
|
+
let deepCalls = 0;
|
|
934
|
+
const makePlugins = (): LexiconPlugin[] => {
|
|
935
|
+
const inner = staticDeepObservation({
|
|
936
|
+
web: { type: "K8s::Apps::Deployment", properties: { spec: { replicas: 5 } } },
|
|
937
|
+
});
|
|
938
|
+
return [
|
|
939
|
+
createMockPlugin({
|
|
940
|
+
name: "k8s",
|
|
941
|
+
describeResources: staticObservation({ web: meta({ type: "K8s::Apps::Deployment" }) }),
|
|
942
|
+
// Counting wrapper: the helper's return type is the plugin member's,
|
|
943
|
+
// which is optional, so it is narrowed once here rather than at the
|
|
944
|
+
// call.
|
|
945
|
+
observeResourcesDeep: ((opts: never) => {
|
|
946
|
+
deepCalls += 1;
|
|
947
|
+
return inner!(opts);
|
|
948
|
+
}) as never,
|
|
949
|
+
}),
|
|
950
|
+
];
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
const run = async (deep: boolean) => {
|
|
954
|
+
stdoutBuf.length = 0;
|
|
955
|
+
buildMock.mockResolvedValue(makeBuild());
|
|
956
|
+
const plugins = makePlugins();
|
|
957
|
+
const exit = await runLifecyclePlan({
|
|
958
|
+
args: makeArgs({ path: "plan", extraPositional: "prod", json: true, ...(deep ? { deep: true } : {}) }),
|
|
959
|
+
plugins,
|
|
960
|
+
serializers: plugins.map((p) => p.serializer),
|
|
961
|
+
} as never);
|
|
962
|
+
expect(exit).toBe(0);
|
|
963
|
+
return JSON.parse(stdoutBuf.join("\n"));
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
deepCalls = 0;
|
|
967
|
+
const shallow = await run(false);
|
|
968
|
+
const callsWithoutDeep = deepCalls;
|
|
969
|
+
|
|
970
|
+
deepCalls = 0;
|
|
971
|
+
const deep = await run(true);
|
|
972
|
+
|
|
973
|
+
// The cost: the pass is not run at all without the flag.
|
|
974
|
+
expect(callsWithoutDeep).toBe(0);
|
|
975
|
+
expect(deepCalls).toBeGreaterThan(0);
|
|
976
|
+
|
|
977
|
+
// The correctness: the same proposals either way, and the held section
|
|
978
|
+
// only when it was asked for.
|
|
979
|
+
expect(shallow.entries).toEqual(deep.entries);
|
|
980
|
+
expect(shallow.held).toBeUndefined();
|
|
981
|
+
expect(deep.held).toBeDefined();
|
|
982
|
+
});
|
|
983
|
+
|
|
919
984
|
test("--json carries the held set beside entries, attributed to its lexicon", async () => {
|
|
920
985
|
const build = makeBuildResult({ k8s: ["web"] });
|
|
921
986
|
build.entities.set("web", {
|
|
@@ -934,7 +999,7 @@ describe("runLifecyclePlan", () => {
|
|
|
934
999
|
}),
|
|
935
1000
|
];
|
|
936
1001
|
const exit = await runLifecyclePlan({
|
|
937
|
-
args: makeArgs({ path: "plan", extraPositional: "prod", json: true }),
|
|
1002
|
+
args: makeArgs({ path: "plan", extraPositional: "prod", json: true, deep: true }),
|
|
938
1003
|
plugins,
|
|
939
1004
|
serializers: plugins.map((p) => p.serializer),
|
|
940
1005
|
});
|
|
@@ -971,7 +1036,7 @@ describe("runLifecyclePlan", () => {
|
|
|
971
1036
|
}),
|
|
972
1037
|
];
|
|
973
1038
|
const exit = await runLifecyclePlan({
|
|
974
|
-
args: makeArgs({ path: "plan", extraPositional: "prod" }),
|
|
1039
|
+
args: makeArgs({ path: "plan", extraPositional: "prod", deep: true }),
|
|
975
1040
|
plugins,
|
|
976
1041
|
serializers: plugins.map((p) => p.serializer),
|
|
977
1042
|
});
|
|
@@ -1319,11 +1319,24 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1319
1319
|
|
|
1320
1320
|
Object.assign(allObservedResources, observed.resources);
|
|
1321
1321
|
|
|
1322
|
-
// Held properties (#2162)
|
|
1323
|
-
//
|
|
1324
|
-
//
|
|
1325
|
-
// carried on the plan beside `entries
|
|
1326
|
-
|
|
1322
|
+
// Held properties (#2162), behind `--deep` since #2405.
|
|
1323
|
+
//
|
|
1324
|
+
// A held property is never a proposal: it is computed against this same
|
|
1325
|
+
// observation and carried on the plan beside `entries`, never folded
|
|
1326
|
+
// into one. So the entries a plan proposes are identical whether this
|
|
1327
|
+
// ran or not, and the only thing `--deep` buys is the HELD section.
|
|
1328
|
+
//
|
|
1329
|
+
// It used to run whenever the lexicon could, which made the read's cost
|
|
1330
|
+
// a function of how many resources an estate holds rather than how it is
|
|
1331
|
+
// organised. Measured on 528 resources across 8 stacks: 24 stack-shaped
|
|
1332
|
+
// calls, and 496 from this pass. At ten thousand resources that is
|
|
1333
|
+
// roughly twenty thousand calls against eighty, for a section the caller
|
|
1334
|
+
// did not ask for.
|
|
1335
|
+
//
|
|
1336
|
+
// `--deep` is the flag `lifecycle snapshot` already uses for the same
|
|
1337
|
+
// choice, and `lifecycle diff` still runs the pass unconditionally
|
|
1338
|
+
// because property drift is the question it exists to answer.
|
|
1339
|
+
if (args.deep && plugin.observeResourcesDeep) {
|
|
1327
1340
|
const deep = await deepDiffForLexicon(plugin, {
|
|
1328
1341
|
environment,
|
|
1329
1342
|
buildOutput,
|
package/src/cli/main.ts
CHANGED
|
@@ -593,6 +593,11 @@ Lifecycle (alias: lc):
|
|
|
593
593
|
property-level drift; --update-baseline records
|
|
594
594
|
what it reports as accepted so it stops alerting)
|
|
595
595
|
lifecycle plan <env> Typed change set (create/update/delete/adopt) vs live
|
|
596
|
+
--deep: also report properties declared
|
|
597
|
+
heldElsewhere(). Never changes what the plan
|
|
598
|
+
proposes; costs a provider call pair per readable
|
|
599
|
+
resource, so the read's cost becomes a function of
|
|
600
|
+
estate size rather than stack count (#2405)
|
|
596
601
|
lifecycle affected Stacks a change affects (--base <ref> [--include-dependents])
|
|
597
602
|
--json: emit the ChangeSet as JSON
|
|
598
603
|
lifecycle whoami <env> Who chant would act as in each configured lexicon,
|