@intentius/chant-lexicon-terraform 0.124.52 → 0.124.54
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/README.md +7 -6
- package/dist/__fixtures__/pr-loop/estate.component.d.ts +7 -0
- package/dist/__fixtures__/pr-loop/estate.component.d.ts.map +1 -0
- package/dist/__fixtures__/pr-loop/estate.component.js +7 -0
- package/dist/__fixtures__/report/generate.d.ts +26 -0
- package/dist/__fixtures__/report/generate.d.ts.map +1 -0
- package/dist/__fixtures__/report/generate.js +58 -0
- package/dist/applied-state.d.ts +27 -0
- package/dist/applied-state.d.ts.map +1 -0
- package/dist/applied-state.js +44 -0
- package/dist/backend-config.d.ts +53 -0
- package/dist/backend-config.d.ts.map +1 -0
- package/dist/backend-config.js +136 -0
- package/dist/behaviour/kinds.d.ts.map +1 -1
- package/dist/behaviour/kinds.js +4 -0
- package/dist/behaviour/predict.d.ts.map +1 -1
- package/dist/behaviour/predict.js +6 -2
- package/dist/behaviour/reference-catalog.d.ts +16 -5
- package/dist/behaviour/reference-catalog.d.ts.map +1 -1
- package/dist/behaviour/reference-catalog.js +16 -5
- package/dist/behaviour/request.d.ts.map +1 -1
- package/dist/behaviour/request.js +3 -2
- package/dist/changed-roots.d.ts +6 -4
- package/dist/changed-roots.d.ts.map +1 -1
- package/dist/changed-roots.js +14 -18
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/components/capability-plugin.d.ts +65 -3
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +197 -13
- package/dist/components/compose-group.d.ts +145 -0
- package/dist/components/compose-group.d.ts.map +1 -0
- package/dist/components/compose-group.js +407 -0
- package/dist/components/placeholder-preview.d.ts +78 -0
- package/dist/components/placeholder-preview.d.ts.map +1 -0
- package/dist/components/placeholder-preview.js +254 -0
- package/dist/compose/apply-events.d.ts +46 -0
- package/dist/compose/apply-events.d.ts.map +1 -0
- package/dist/compose/apply-events.js +77 -0
- package/dist/compose/estate.d.ts +194 -0
- package/dist/compose/estate.d.ts.map +1 -0
- package/dist/compose/estate.js +363 -0
- package/dist/compose/hcl.d.ts +99 -0
- package/dist/compose/hcl.d.ts.map +1 -0
- package/dist/compose/hcl.js +302 -0
- package/dist/compose/module-address.d.ts +24 -0
- package/dist/compose/module-address.d.ts.map +1 -0
- package/dist/compose/module-address.js +43 -0
- package/dist/compose/root.d.ts +127 -0
- package/dist/compose/root.d.ts.map +1 -0
- package/dist/compose/root.js +586 -0
- package/dist/compose/run.d.ts +183 -0
- package/dist/compose/run.d.ts.map +1 -0
- package/dist/compose/run.js +447 -0
- package/dist/compose/slice.d.ts +102 -0
- package/dist/compose/slice.d.ts.map +1 -0
- package/dist/compose/slice.js +249 -0
- package/dist/compose/state-address.d.ts +28 -0
- package/dist/compose/state-address.d.ts.map +1 -0
- package/dist/compose/state-address.js +154 -0
- package/dist/compose/state-merge.d.ts +52 -0
- package/dist/compose/state-merge.d.ts.map +1 -0
- package/dist/compose/state-merge.js +135 -0
- package/dist/compose.d.ts +179 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +482 -0
- package/dist/composites/terraform-apply-op.d.ts.map +1 -1
- package/dist/composites/terraform-apply-op.js +7 -3
- package/dist/config.d.ts +59 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -9
- package/dist/describe-resources.d.ts +74 -12
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +374 -66
- package/dist/drift-read.d.ts +33 -0
- package/dist/drift-read.d.ts.map +1 -0
- package/dist/drift-read.js +243 -0
- package/dist/drift-record.d.ts +147 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +383 -0
- package/dist/hcl/edges.d.ts.map +1 -1
- package/dist/hcl/edges.js +24 -1
- package/dist/hcl/files.d.ts +61 -0
- package/dist/hcl/files.d.ts.map +1 -0
- package/dist/hcl/files.js +221 -0
- package/dist/hcl/instances.d.ts +82 -0
- package/dist/hcl/instances.d.ts.map +1 -0
- package/dist/hcl/instances.js +390 -0
- package/dist/hcl/parse.d.ts +81 -9
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +114 -16
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/roots.js +5 -0
- package/dist/hcl/suppressions.d.ts.map +1 -1
- package/dist/hcl/suppressions.js +8 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -2
- package/dist/integrity.json +3 -3
- package/dist/live-plan-reasons.d.ts +21 -0
- package/dist/live-plan-reasons.d.ts.map +1 -0
- package/dist/live-plan-reasons.js +47 -0
- package/dist/lsp/option-keys.d.ts.map +1 -1
- package/dist/lsp/option-keys.js +2 -0
- package/dist/manifest.json +1 -1
- package/dist/op/activities/index.d.ts +6 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +5 -1
- package/dist/op/activities/live-detect.d.ts +4 -3
- package/dist/op/activities/live-detect.d.ts.map +1 -1
- package/dist/op/activities/live-detect.js +57 -32
- package/dist/op/activities/pin-rollout.d.ts +2 -0
- package/dist/op/activities/pin-rollout.d.ts.map +1 -1
- package/dist/op/activities/pin-rollout.js +1 -0
- package/dist/op/activities/terraform.d.ts +153 -5
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +205 -20
- package/dist/op/activity-contracts.d.ts +27 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +19 -1
- package/dist/op/builders.d.ts +7 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -0
- package/dist/pin/edit.d.ts.map +1 -1
- package/dist/pin/edit.js +35 -0
- package/dist/pin/rollout.d.ts +2 -0
- package/dist/pin/rollout.d.ts.map +1 -1
- package/dist/pin/rollout.js +14 -11
- package/dist/plan-shape.d.ts +30 -0
- package/dist/plan-shape.d.ts.map +1 -0
- package/dist/plan-shape.js +125 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +32 -18
- package/dist/report.d.ts +15 -6
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +28 -55
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/state/azure-blob.d.ts +68 -0
- package/dist/state/azure-blob.d.ts.map +1 -0
- package/dist/state/azure-blob.js +201 -0
- package/dist/state/backend.d.ts +158 -0
- package/dist/state/backend.d.ts.map +1 -0
- package/dist/state/backend.js +406 -0
- package/dist/state/exec.d.ts +39 -0
- package/dist/state/exec.d.ts.map +1 -0
- package/dist/state/exec.js +80 -0
- package/dist/state/gcs.d.ts +62 -0
- package/dist/state/gcs.d.ts.map +1 -0
- package/dist/state/gcs.js +224 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +14 -0
- package/dist/state/locks.d.ts +105 -0
- package/dist/state/locks.d.ts.map +1 -0
- package/dist/state/locks.js +130 -0
- package/dist/state/object-store.d.ts +37 -0
- package/dist/state/object-store.d.ts.map +1 -0
- package/dist/state/object-store.js +20 -0
- package/dist/state/root-states.d.ts +131 -0
- package/dist/state/root-states.d.ts.map +1 -0
- package/dist/state/root-states.js +241 -0
- package/dist/state/s3.d.ts +68 -0
- package/dist/state/s3.d.ts.map +1 -0
- package/dist/state/s3.js +170 -0
- package/dist/state/store.d.ts +51 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +185 -0
- package/dist/terragrunt/affected.d.ts.map +1 -1
- package/dist/terragrunt/affected.js +2 -1
- package/package.json +7 -3
- package/src/__fixtures__/ACCEPTANCE.md +69 -7
- package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
- package/src/__fixtures__/compose/state-app.json +66 -0
- package/src/__fixtures__/compose/state-edge.json +40 -0
- package/src/__fixtures__/compose/state-net.json +58 -0
- package/src/__fixtures__/compose/three-app.plan.json +184 -0
- package/src/__fixtures__/compose/three-composed.plan.json +509 -0
- package/src/__fixtures__/compose/three-edge.plan.json +144 -0
- package/src/__fixtures__/compose/three-net.plan.json +174 -0
- package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
- package/src/__fixtures__/compose/working-after-apply.json +145 -0
- package/src/__fixtures__/config-blocks/app/main.tf +61 -0
- package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
- package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
- package/src/__fixtures__/config-files/shadow/main.tf +3 -0
- package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
- package/src/__fixtures__/config-files/shadow/other.tf +3 -0
- package/src/__fixtures__/config-files/tf/main.tf +11 -0
- package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
- package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
- package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
- package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
- package/src/__fixtures__/drift-record/README.md +11 -0
- package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
- package/src/__fixtures__/instance-forms/app/main.tf +110 -0
- package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/main.tf +52 -0
- package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
- package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
- package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
- package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
- package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
- package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
- package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
- package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
- package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
- package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
- package/src/__fixtures__/pr-loop/README.md +50 -0
- package/src/__fixtures__/pr-loop/chant.config.json +13 -0
- package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
- package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
- package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
- package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
- package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
- package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
- package/src/__fixtures__/report/applied.show.json +51 -0
- package/src/__fixtures__/report/generate.ts +63 -0
- package/src/__fixtures__/report/plan.show.json +200 -0
- package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
- package/src/__fixtures__/report/tf-apply/report.json +338 -0
- package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
- package/src/__fixtures__/report/tf-plan/report.json +320 -0
- package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
- package/src/applied-state.ts +52 -0
- package/src/backend-config.test.ts +105 -0
- package/src/backend-config.ts +133 -0
- package/src/behaviour/kinds.ts +4 -0
- package/src/behaviour/predict.ts +5 -2
- package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
- package/src/behaviour/reference-catalog.ts +16 -5
- package/src/behaviour/request.ts +3 -2
- package/src/change-set-instances.test.ts +98 -0
- package/src/changed-roots.ts +14 -16
- package/src/commands.ts +4 -3
- package/src/components/capability-plugin.test.ts +172 -5
- package/src/components/capability-plugin.ts +212 -11
- package/src/components/change-set-graph.e2e.test.ts +11 -5
- package/src/components/compose-group.test.ts +486 -0
- package/src/components/compose-group.ts +489 -0
- package/src/components/demo-composed-roots.e2e.test.ts +440 -0
- package/src/components/member-outputs.test.ts +76 -0
- package/src/components/placeholder-preview.test.ts +147 -0
- package/src/components/placeholder-preview.ts +257 -0
- package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
- package/src/components/pr-loop.tofu.test.ts +112 -56
- package/src/compose/apply-events.test.ts +62 -0
- package/src/compose/apply-events.ts +100 -0
- package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
- package/src/compose/estate.test.ts +421 -0
- package/src/compose/estate.ts +443 -0
- package/src/compose/hcl.ts +311 -0
- package/src/compose/module-address.ts +49 -0
- package/src/compose/root.test.ts +416 -0
- package/src/compose/root.ts +592 -0
- package/src/compose/run.test.ts +440 -0
- package/src/compose/run.tofu.test.ts +176 -0
- package/src/compose/run.ts +527 -0
- package/src/compose/slice.test.ts +184 -0
- package/src/compose/slice.ts +290 -0
- package/src/compose/state-address.ts +157 -0
- package/src/compose/state-merge.test.ts +131 -0
- package/src/compose/state-merge.ts +148 -0
- package/src/compose.test.ts +248 -0
- package/src/compose.ts +627 -0
- package/src/composites/terraform-apply-op.test.ts +9 -0
- package/src/composites/terraform-apply-op.ts +7 -3
- package/src/config-file-listers.test.ts +265 -0
- package/src/config.ts +44 -9
- package/src/describe-resources.engine-facts.test.ts +412 -0
- package/src/describe-resources.live-module-keyed.test.ts +290 -0
- package/src/describe-resources.ts +416 -70
- package/src/drift-read.ts +284 -0
- package/src/drift-record.test.ts +223 -0
- package/src/drift-record.ts +455 -0
- package/src/hcl/config-blocks.test.ts +174 -0
- package/src/hcl/edges.ts +21 -1
- package/src/hcl/files.ts +234 -0
- package/src/hcl/instance-forms.test.ts +94 -0
- package/src/hcl/instances.test.ts +137 -0
- package/src/hcl/instances.ts +422 -0
- package/src/hcl/parse.test.ts +139 -1
- package/src/hcl/parse.ts +149 -16
- package/src/hcl/roots.ts +6 -0
- package/src/hcl/suppressions.ts +8 -2
- package/src/index.ts +76 -0
- package/src/live-plan-reasons.ts +54 -0
- package/src/lsp/completions.test.ts +1 -1
- package/src/lsp/option-keys.ts +2 -0
- package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/live-detect.ts +55 -26
- package/src/op/activities/pin-rollout.ts +3 -0
- package/src/op/activities/registry.test.ts +2 -1
- package/src/op/activities/terraform.test.ts +55 -0
- package/src/op/activities/terraform.ts +266 -22
- package/src/op/activity-contracts.test.ts +1 -0
- package/src/op/activity-contracts.ts +24 -1
- package/src/op/builders.ts +14 -0
- package/src/pin/bundle.test.ts +2 -0
- package/src/pin/edit.ts +30 -0
- package/src/pin/rollout.ts +16 -11
- package/src/plan-shape.test.ts +148 -0
- package/src/plan-shape.ts +128 -0
- package/src/plugin.ts +33 -19
- package/src/report.test.ts +82 -1
- package/src/report.ts +31 -54
- package/src/signal-only-root.test.ts +72 -0
- package/src/skills/chant-terraform.md +1 -1
- package/src/state/azure-blob.ts +223 -0
- package/src/state/backend-verdict.test.ts +187 -0
- package/src/state/backend.test.ts +127 -0
- package/src/state/backend.ts +488 -0
- package/src/state/exec.ts +111 -0
- package/src/state/gcs.ts +254 -0
- package/src/state/index.ts +15 -0
- package/src/state/locks.test.ts +84 -0
- package/src/state/locks.ts +201 -0
- package/src/state/object-store.ts +35 -0
- package/src/state/root-states-floci.e2e.test.ts +66 -0
- package/src/state/root-states.test.ts +462 -0
- package/src/state/root-states.ts +309 -0
- package/src/state/s3.ts +193 -0
- package/src/state/store.ts +225 -0
- package/src/terragrunt/affected.ts +2 -1
- package/src/workspace-kinds.test.ts +4 -17
- package/workspace-kinds.json +1 -24
- package/dist/workspace-member.d.ts +0 -30
- package/dist/workspace-member.d.ts.map +0 -1
- package/dist/workspace-member.js +0 -91
- package/schemas/pulumi.schema.json +0 -34
- package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
- package/src/testdata/pulumi-member/stack-export.json +0 -53
- package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
- package/src/workspace-member.test.ts +0 -89
- package/src/workspace-member.ts +0 -126
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine facts from `choudoufu live-graph -json -from-plan=<file>` on a live
|
|
3
|
+
* root (chant #4528, designed on #4520 section 4 and ruled there).
|
|
4
|
+
*
|
|
5
|
+
* Two documents are read here, neither produced by a run:
|
|
6
|
+
*
|
|
7
|
+
* - chant #4527's schema fixture,
|
|
8
|
+
* `packages/core/src/graph-schema/fixtures/choudoufu.engine-graph.json`,
|
|
9
|
+
* the shape choudoufu#2285's own tests decode against. It carries every
|
|
10
|
+
* fact field and two `grain: "block"` edges, one out of an instance under
|
|
11
|
+
* an expanded module call.
|
|
12
|
+
* - `__fixtures__/live-module-keyed/live-graph.json`, written by hand for the
|
|
13
|
+
* #4513 fixture root to what choudoufu#2285 prints for it from the
|
|
14
|
+
* `live-plan.json` beside it, read on choudoufu
|
|
15
|
+
* `origin/integration/consolidation-graph` (3b40fc5683),
|
|
16
|
+
* internal/live/livegraph/: one node per block with its `sourceLoc`
|
|
17
|
+
* (`collect`); instance nodes for the literal `count = 2` call and the
|
|
18
|
+
* block's own `count = 2`, and for the `for_each = toset(...)` call only
|
|
19
|
+
* through the plan's rows, since a function call is not a literal
|
|
20
|
+
* (`literalKeys`, `nodeForAddr`); facts by `planFacts` (`marker` binds
|
|
21
|
+
* carry `markers.EscapeAddress`, a `derived` bind is `ownedBy: "name"`,
|
|
22
|
+
* ABSENT is `pending`, an unowned row with `tofu_estate` is `foreign`);
|
|
23
|
+
* no `observedAt`, because the plan document has no `observed_at`; no
|
|
24
|
+
* engine version, as on a dev build; continuation keys
|
|
25
|
+
* `tofu-address-2..4`; and no edges, because no block in that root reads
|
|
26
|
+
* another.
|
|
27
|
+
*
|
|
28
|
+
* Nothing here runs choudoufu: the activities are injected.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
32
|
+
import { createRequire } from "node:module";
|
|
33
|
+
import { tmpdir } from "node:os";
|
|
34
|
+
import { dirname, join } from "node:path";
|
|
35
|
+
import { fileURLToPath } from "node:url";
|
|
36
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
37
|
+
import { normalizeObservation } from "@intentius/chant/observation";
|
|
38
|
+
import type { Declarable } from "@intentius/chant/declarable";
|
|
39
|
+
import { buildLiveGraphIr } from "@intentius/chant/graph-ir";
|
|
40
|
+
import { ENGINE_FACTS_FLOOR } from "@intentius/chant/engine-facts";
|
|
41
|
+
import { NEXT_RELEASE } from "@intentius/chant/release-floors";
|
|
42
|
+
import {
|
|
43
|
+
describeResources,
|
|
44
|
+
readEngineGraph,
|
|
45
|
+
TERRAFORM_LIVE_PLAN_DIR_ENV,
|
|
46
|
+
withEngineFacts,
|
|
47
|
+
type TerraformReadDeps,
|
|
48
|
+
} from "./describe-resources";
|
|
49
|
+
import { renderTerraformRoots } from "./hcl/roots";
|
|
50
|
+
import {
|
|
51
|
+
choudoufuLiveGraphCommand,
|
|
52
|
+
classifyLiveGraphFailure,
|
|
53
|
+
MIN_CHOUDOUFU_GRAPH_VERSION,
|
|
54
|
+
MIN_CHOUDOUFU_VERSION,
|
|
55
|
+
isOlderVersion,
|
|
56
|
+
} from "./op/activities/terraform";
|
|
57
|
+
|
|
58
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
59
|
+
const SCHEMA_DIR = join(here, "..", "..", "..", "packages", "core", "src", "graph-schema");
|
|
60
|
+
const SCHEMA = JSON.parse(readFileSync(join(SCHEMA_DIR, "graph.schema.json"), "utf-8")) as { $id: string };
|
|
61
|
+
const CORE_FIXTURE: unknown = JSON.parse(readFileSync(join(SCHEMA_DIR, "fixtures", "choudoufu.engine-graph.json"), "utf-8"));
|
|
62
|
+
const FIXTURE = join(here, "__fixtures__", "live-module-keyed");
|
|
63
|
+
const ROOT_DIR = join(FIXTURE, "root");
|
|
64
|
+
const LIVE_PLAN: unknown = JSON.parse(readFileSync(join(FIXTURE, "live-plan.json"), "utf-8"));
|
|
65
|
+
const LIVE_GRAPH: unknown = JSON.parse(readFileSync(join(FIXTURE, "live-graph.json"), "utf-8"));
|
|
66
|
+
const ESTATE = "module-keyed-estate";
|
|
67
|
+
|
|
68
|
+
// Core's own ajv (v8, draft 2020-12), which the schema test uses; the copy at
|
|
69
|
+
// the workspace root is another major. Loaded through core's package so the
|
|
70
|
+
// two tests validate with the same build.
|
|
71
|
+
interface Validate {
|
|
72
|
+
(doc: unknown): boolean;
|
|
73
|
+
errors?: unknown;
|
|
74
|
+
}
|
|
75
|
+
interface Ajv {
|
|
76
|
+
addSchema(schema: unknown): void;
|
|
77
|
+
getSchema(ref: string): Validate | undefined;
|
|
78
|
+
}
|
|
79
|
+
const Ajv2020 = (createRequire(join(SCHEMA_DIR, "..", "..", "package.json"))("ajv/dist/2020") as { default: new (opts: object) => Ajv }).default;
|
|
80
|
+
const ajv = new Ajv2020({ allErrors: true, strict: true });
|
|
81
|
+
ajv.addSchema(SCHEMA);
|
|
82
|
+
const validEngineGraph = ajv.getSchema(`${SCHEMA.$id}#/$defs/EngineGraphDocument`)!;
|
|
83
|
+
|
|
84
|
+
type Entities = Map<string, { entityType: string; props: Record<string, unknown> }>;
|
|
85
|
+
|
|
86
|
+
async function render(): Promise<Entities> {
|
|
87
|
+
const { entities: declarables } = await renderTerraformRoots({
|
|
88
|
+
projectRoot: FIXTURE,
|
|
89
|
+
roots: { estate: { dir: "./root" } },
|
|
90
|
+
binary: "choudoufu",
|
|
91
|
+
});
|
|
92
|
+
const entities: Entities = new Map();
|
|
93
|
+
for (const [key, entity] of declarables) {
|
|
94
|
+
entities.set(key, { entityType: entity.entityType, props: (entity as Declarable & { props: Record<string, unknown> }).props });
|
|
95
|
+
}
|
|
96
|
+
return entities;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function options(entities: Entities) {
|
|
100
|
+
return { environment: "prod", buildOutput: "", entityNames: [...entities.keys()].sort(), entities };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const never = ((args: { root: string }) => {
|
|
104
|
+
throw new Error(`unexpected activity for root "${args.root}"`);
|
|
105
|
+
}) as never;
|
|
106
|
+
|
|
107
|
+
type LiveGraph = NonNullable<TerraformReadDeps["liveGraph"]>;
|
|
108
|
+
type LiveGraphCall = Parameters<LiveGraph>[0] & { document: unknown };
|
|
109
|
+
|
|
110
|
+
/** `live-plan -json` answers from the fixture; `live-graph` answers with `graph`, recording what it was handed. */
|
|
111
|
+
function deps(graph?: (call: LiveGraphCall) => Awaited<ReturnType<LiveGraph>>, calls: LiveGraphCall[] = []): TerraformReadDeps {
|
|
112
|
+
return {
|
|
113
|
+
init: never,
|
|
114
|
+
show: never,
|
|
115
|
+
liveLs: never,
|
|
116
|
+
livePlan: (async () => ({ json: LIVE_PLAN, dir: ROOT_DIR, estate: ESTATE })) as unknown as TerraformReadDeps["livePlan"],
|
|
117
|
+
...(graph
|
|
118
|
+
? {
|
|
119
|
+
liveGraph: (async (args: Parameters<LiveGraph>[0]) => {
|
|
120
|
+
// The file is read while it exists: a scratch copy is removed after the call.
|
|
121
|
+
const call = { ...args, document: JSON.parse(readFileSync(args.fromPlan, "utf-8")) as unknown };
|
|
122
|
+
calls.push(call);
|
|
123
|
+
return graph(call);
|
|
124
|
+
}) as LiveGraph,
|
|
125
|
+
}
|
|
126
|
+
: {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const answers = (json: unknown) => () => ({ supported: true as const, json, dir: ROOT_DIR });
|
|
131
|
+
|
|
132
|
+
const saved = process.env[TERRAFORM_LIVE_PLAN_DIR_ENV];
|
|
133
|
+
afterEach(() => {
|
|
134
|
+
if (saved === undefined) delete process.env[TERRAFORM_LIVE_PLAN_DIR_ENV];
|
|
135
|
+
else process.env[TERRAFORM_LIVE_PLAN_DIR_ENV] = saved;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("the engine graph documents (#4528)", () => {
|
|
139
|
+
it("both validate against chant #4527's schema", () => {
|
|
140
|
+
expect(validEngineGraph(CORE_FIXTURE), JSON.stringify(validEngineGraph.errors)).toBe(true);
|
|
141
|
+
expect(validEngineGraph(LIVE_GRAPH), JSON.stringify(validEngineGraph.errors)).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("readEngineGraph over #4527's schema fixture", () => {
|
|
146
|
+
const read = readEngineGraph("web", CORE_FIXTURE);
|
|
147
|
+
|
|
148
|
+
it("puts each block node's facts on its entity key", () => {
|
|
149
|
+
expect([...read.blocks.keys()].sort()).toEqual(["web/aws_s3_bucket.logs", "web/aws_sns_topic.alerts", "web/aws_sqs_queue.jobs"]);
|
|
150
|
+
expect(read.blocks.get("web/aws_s3_bucket.logs")).toEqual({
|
|
151
|
+
ownership: "bound",
|
|
152
|
+
ownedBy: "record",
|
|
153
|
+
cloudIds: [
|
|
154
|
+
{ kind: "import-id", value: "web-logs" },
|
|
155
|
+
{ kind: "arn", value: "arn:aws:s3:::web-logs" },
|
|
156
|
+
],
|
|
157
|
+
recordVersions: {
|
|
158
|
+
kept: true,
|
|
159
|
+
versions: [
|
|
160
|
+
{ id: "3sL4kqtJlcpXroDTDmJ.rmSpXd3dIbrHY", writtenAt: "2026-10-26T11:58:02Z", current: true, deleted: false },
|
|
161
|
+
{ id: "2bE8x0l1BqzDmoPTmD7M7bGqFrsTFTQS", writtenAt: "2026-10-20T09:14:40Z", current: false, deleted: false },
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
observedAt: "2026-10-26T12:00:00Z",
|
|
165
|
+
});
|
|
166
|
+
expect(read.blocks.get("web/aws_sqs_queue.jobs")).toEqual({
|
|
167
|
+
ownership: "foreign",
|
|
168
|
+
markers: { owner: "billing", encoding: "escaped", source: "live" },
|
|
169
|
+
observedAt: "2026-10-26T12:00:00Z",
|
|
170
|
+
});
|
|
171
|
+
expect(read.blocks.get("web/aws_sns_topic.alerts")).toEqual({ ownership: "pending", observedAt: "2026-10-26T12:00:00Z" });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("puts an instance node's facts under its block's entity key, by instance address", () => {
|
|
175
|
+
expect([...read.instances.keys()]).toEqual(["web/module.app/aws_eip.pool"]);
|
|
176
|
+
expect(read.instances.get("web/module.app/aws_eip.pool")!.get("module.app[0].aws_eip.pool[1]")).toEqual({
|
|
177
|
+
ownership: "bound",
|
|
178
|
+
ownedBy: "marker",
|
|
179
|
+
markers: { owner: "web", address: "module.app:0.aws_eip.pool:1", encoding: "escaped", source: "live" },
|
|
180
|
+
cloudIds: [{ kind: "import-id", value: "eipalloc-0abc" }],
|
|
181
|
+
observedAt: "2026-10-26T12:00:00Z",
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("maps block edges to live graph ids and keeps their grain", () => {
|
|
186
|
+
expect(read.edges).toEqual([
|
|
187
|
+
{ from: "web/module.app[0]/aws_eip.pool[1]", to: "web/module.app/aws_instance.web", kind: "ref", viaAttr: "dependencies", grain: "block" },
|
|
188
|
+
{ from: "web/module.app/aws_instance.web", to: "web/aws_s3_bucket.logs", kind: "ref", viaAttr: "dependencies", grain: "block" },
|
|
189
|
+
]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("refuses a document that is not an engine graph", () => {
|
|
193
|
+
expect(() => readEngineGraph("web", { version: 1, nodes: [], edges: [] })).toThrow(/not an engine graph document/);
|
|
194
|
+
expect(() => readEngineGraph("web", "nope")).toThrow(/not an engine graph document/);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("carries the facts and edges onto the live graph", () => {
|
|
198
|
+
const resources = withEngineFacts(
|
|
199
|
+
{
|
|
200
|
+
"web/aws_s3_bucket.logs": { type: "Terraform::Resource", status: "bound", physicalId: "web-logs", ownership: "owned" },
|
|
201
|
+
"web/module.app/aws_instance.web": { type: "Terraform::Resource", status: "bound", ownership: "owned" },
|
|
202
|
+
"web/module.app/aws_eip.pool": {
|
|
203
|
+
type: "Terraform::Resource",
|
|
204
|
+
status: "bound",
|
|
205
|
+
ownership: "owned",
|
|
206
|
+
instances: [
|
|
207
|
+
{ key: "[1]", scope: "module.app[0]", address: "module.app[0].aws_eip.pool[1]", verdict: "present", ownership: "owned", physicalId: "eipalloc-0abc" },
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
read,
|
|
212
|
+
);
|
|
213
|
+
const ir = buildLiveGraphIr([{ lexicon: "terraform", resources, edges: read.edges }]);
|
|
214
|
+
const node = (id: string) => ir.nodes.find((n) => n.id === id);
|
|
215
|
+
expect(node("web/aws_s3_bucket.logs")!.facts!.ownedBy).toBe("record");
|
|
216
|
+
expect(node("web/module.app[0]/aws_eip.pool[1]")!.facts!.markers!.source).toBe("live");
|
|
217
|
+
// The block node of an expanded block has no facts of its own; its instance does.
|
|
218
|
+
expect(node("web/module.app/aws_eip.pool")!.facts).toBeUndefined();
|
|
219
|
+
// Both endpoints of each were observed, so buildLiveGraphIr keeps both (its sort is localeCompare's).
|
|
220
|
+
expect(ir.edges.map((e) => `${e.from} -> ${e.to} (${e.grain})`).sort()).toEqual([
|
|
221
|
+
"web/module.app/aws_instance.web -> web/aws_s3_bucket.logs (block)",
|
|
222
|
+
"web/module.app[0]/aws_eip.pool[1] -> web/module.app/aws_instance.web (block)",
|
|
223
|
+
]);
|
|
224
|
+
// ownership keeps its own meaning beside the facts.
|
|
225
|
+
expect(node("web/aws_s3_bucket.logs")!.ownership).toBe("owned");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("describeResources reads live-graph after live-plan on the module-keyed root (#4528, #4513)", () => {
|
|
230
|
+
it("hands live-graph the same live-plan document, in a scratch file when no directory was asked for", async () => {
|
|
231
|
+
delete process.env[TERRAFORM_LIVE_PLAN_DIR_ENV];
|
|
232
|
+
const calls: LiveGraphCall[] = [];
|
|
233
|
+
await describeResources(options(await render()), deps(answers(LIVE_GRAPH), calls));
|
|
234
|
+
expect(calls).toHaveLength(1);
|
|
235
|
+
expect(calls[0]).toMatchObject({ root: "estate", estate: ESTATE });
|
|
236
|
+
expect(calls[0]!.document).toEqual(LIVE_PLAN);
|
|
237
|
+
expect(calls[0]!.fromPlan.startsWith(tmpdir())).toBe(true);
|
|
238
|
+
expect(calls[0]!.fromPlan.endsWith("estate.live-plan.json")).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("hands it the <root>.live-plan.json under CHANT_TERRAFORM_LIVE_PLAN_DIR when that is set", async () => {
|
|
242
|
+
const out = mkdtempSync(join(tmpdir(), "chant-4528-plan-dir-"));
|
|
243
|
+
try {
|
|
244
|
+
process.env[TERRAFORM_LIVE_PLAN_DIR_ENV] = out;
|
|
245
|
+
const calls: LiveGraphCall[] = [];
|
|
246
|
+
await describeResources(options(await render()), deps(answers(LIVE_GRAPH), calls));
|
|
247
|
+
expect(calls.map((c) => c.fromPlan)).toEqual([join(out, "estate.live-plan.json")]);
|
|
248
|
+
expect(calls[0]!.document).toEqual(LIVE_PLAN);
|
|
249
|
+
} finally {
|
|
250
|
+
rmSync(out, { recursive: true, force: true });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("sets each module-keyed instance's facts, by marker, by name, pending, unowned and foreign", async () => {
|
|
255
|
+
const { resources } = normalizeObservation(await describeResources(options(await render()), deps(answers(LIVE_GRAPH))));
|
|
256
|
+
const pool = resources["estate/module.app/aws_eip.pool"]!;
|
|
257
|
+
expect(pool.facts).toBeUndefined();
|
|
258
|
+
expect(pool.instances!.map((i) => [i.address, i.facts?.ownership, i.facts?.ownedBy, i.facts?.markers?.address, i.facts?.cloudIds?.[0]?.value])).toEqual([
|
|
259
|
+
["module.app[0].aws_eip.pool[0]", "bound", "marker", "module.app:0.aws_eip.pool:0", "eipalloc-0a41c7d2e9b3f5061"],
|
|
260
|
+
["module.app[0].aws_eip.pool[1]", "bound", "marker", "module.app:0.aws_eip.pool:1", "eipalloc-0b52d8e3fac4061f2"],
|
|
261
|
+
["module.app[1].aws_eip.pool[0]", "bound", "marker", "module.app:1.aws_eip.pool:0", "eipalloc-0c63e9f40bd5172a3"],
|
|
262
|
+
["module.app[1].aws_eip.pool[1]", "bound", "marker", "module.app:1.aws_eip.pool:1", "eipalloc-0d74fa051ce6283b4"],
|
|
263
|
+
]);
|
|
264
|
+
expect(pool.instances![0]!.facts!.markers).toEqual({ owner: ESTATE, address: "module.app:0.aws_eip.pool:0", encoding: "escaped", source: "live" });
|
|
265
|
+
|
|
266
|
+
const logs = resources["estate/module.app/aws_cloudwatch_log_group.logs"]!;
|
|
267
|
+
expect(logs.instances!.map((i) => [i.address, i.verdict, i.facts])).toEqual([
|
|
268
|
+
["module.app[0].aws_cloudwatch_log_group.logs", "present", { ownership: "bound", ownedBy: "name", cloudIds: [{ kind: "import-id", value: `/${ESTATE}/app-0` }] }],
|
|
269
|
+
["module.app[1].aws_cloudwatch_log_group.logs", "absent", { ownership: "pending" }],
|
|
270
|
+
]);
|
|
271
|
+
|
|
272
|
+
const front = resources["estate/module.edge/aws_cloudwatch_log_group.front"]!;
|
|
273
|
+
expect(front.instances!.map((i) => i.facts)).toEqual([
|
|
274
|
+
{ ownership: "unowned", cloudIds: [{ kind: "import-id", value: `/${ESTATE}/edge-east` }] },
|
|
275
|
+
{ ownership: "foreign", markers: { owner: "other-estate", encoding: "escaped", source: "live" }, cloudIds: [{ kind: "import-id", value: `/${ESTATE}/edge-west` }] },
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
// The verdicts are the live-plan read's, unchanged.
|
|
279
|
+
expect(pool).toMatchObject({ status: "bound", ownership: "owned", marker: { stack: ESTATE } });
|
|
280
|
+
expect(front).toMatchObject({ status: "unowned", ownership: "foreign" });
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("draws the facts on the instance nodes the declared graph lists", async () => {
|
|
284
|
+
const { resources } = normalizeObservation(await describeResources(options(await render()), deps(answers(LIVE_GRAPH))));
|
|
285
|
+
const ir = buildLiveGraphIr([{ lexicon: "terraform", resources }]);
|
|
286
|
+
const facts = new Map(ir.nodes.filter((n) => n.facts).map((n) => [n.id, n.facts!.ownership]));
|
|
287
|
+
expect(Object.fromEntries(facts)).toEqual({
|
|
288
|
+
"estate/module.app[0]/aws_cloudwatch_log_group.logs": "bound",
|
|
289
|
+
"estate/module.app[0]/aws_eip.pool[0]": "bound",
|
|
290
|
+
"estate/module.app[0]/aws_eip.pool[1]": "bound",
|
|
291
|
+
"estate/module.app[1]/aws_eip.pool[0]": "bound",
|
|
292
|
+
"estate/module.app[1]/aws_eip.pool[1]": "bound",
|
|
293
|
+
'estate/module.edge["east"]/aws_cloudwatch_log_group.front': "unowned",
|
|
294
|
+
'estate/module.edge["west"]/aws_cloudwatch_log_group.front': "foreign",
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("puts a block edge on the observation's edges, mapped to the live graph's ids", async () => {
|
|
299
|
+
// live-graph prints no edge for this root, since no block reads another.
|
|
300
|
+
// This one is added by the test, out of an instance under the expanded
|
|
301
|
+
// call into a block, the shape #4527's fixture carries.
|
|
302
|
+
const doc = structuredClone(LIVE_GRAPH) as { edges: unknown[] };
|
|
303
|
+
doc.edges.push({
|
|
304
|
+
from: "module.app[0].aws_eip.pool[1]",
|
|
305
|
+
to: "module.app.aws_cloudwatch_log_group.logs",
|
|
306
|
+
kind: "ref",
|
|
307
|
+
viaAttr: "depends_on",
|
|
308
|
+
grain: "block",
|
|
309
|
+
});
|
|
310
|
+
const raw = await describeResources(options(await render()), deps(answers(doc)));
|
|
311
|
+
const observed = normalizeObservation(raw);
|
|
312
|
+
expect(observed.edges).toEqual([
|
|
313
|
+
{ from: "estate/module.app[0]/aws_eip.pool[1]", to: "estate/module.app/aws_cloudwatch_log_group.logs", kind: "ref", viaAttr: "depends_on", grain: "block" },
|
|
314
|
+
]);
|
|
315
|
+
const ir = buildLiveGraphIr([{ lexicon: "terraform", resources: observed.resources, edges: observed.edges }]);
|
|
316
|
+
expect(ir.edges).toEqual(observed.edges);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("with no edges in the document, the observation carries none", async () => {
|
|
320
|
+
const observed = normalizeObservation(await describeResources(options(await render()), deps(answers(LIVE_GRAPH))));
|
|
321
|
+
expect(observed.edges).toBeUndefined();
|
|
322
|
+
expect(observed.notes.some((n) => n.includes("live-graph"))).toBe(false);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe("an older choudoufu: no facts, one note, the rest unchanged (#4528)", () => {
|
|
327
|
+
async function baseline() {
|
|
328
|
+
return normalizeObservation(await describeResources(options(await render()), deps()));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function noFacts(resources: Record<string, { facts?: unknown; instances?: Array<{ facts?: unknown }> }>): boolean {
|
|
332
|
+
return Object.values(resources).every((r) => r.facts === undefined && (r.instances ?? []).every((i) => i.facts === undefined));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
it("a usage error leaves facts absent and adds exactly one note naming the floor", async () => {
|
|
336
|
+
const before = await baseline();
|
|
337
|
+
const after = normalizeObservation(
|
|
338
|
+
await describeResources(
|
|
339
|
+
options(await render()),
|
|
340
|
+
deps(() => ({ supported: false, detail: 'OpenTofu has no command named "live-graph".', dir: ROOT_DIR })),
|
|
341
|
+
),
|
|
342
|
+
);
|
|
343
|
+
expect(noFacts(after.resources)).toBe(true);
|
|
344
|
+
expect(after.resources).toEqual(before.resources);
|
|
345
|
+
expect(after.unobserved).toEqual(before.unobserved);
|
|
346
|
+
expect(after.queried).toEqual(before.queried);
|
|
347
|
+
expect(after.sources).toEqual(before.sources);
|
|
348
|
+
expect(after.edges).toBeUndefined();
|
|
349
|
+
const added = after.notes.filter((n) => !before.notes.includes(n));
|
|
350
|
+
expect(added).toHaveLength(1);
|
|
351
|
+
expect(added[0]).toContain("terraform.roots.estate: engine facts are absent");
|
|
352
|
+
expect(added[0]).toContain('OpenTofu has no command named "live-graph".');
|
|
353
|
+
expect(added[0]).toContain(`v${MIN_CHOUDOUFU_GRAPH_VERSION}`);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("any other live-graph failure degrades the same way, with its own note", async () => {
|
|
357
|
+
const before = await baseline();
|
|
358
|
+
const after = normalizeObservation(
|
|
359
|
+
await describeResources(
|
|
360
|
+
options(await render()),
|
|
361
|
+
deps(() => {
|
|
362
|
+
throw new Error("choudoufu live-graph failed in /x (exit 1)\nThe live plan is of another estate");
|
|
363
|
+
}),
|
|
364
|
+
),
|
|
365
|
+
);
|
|
366
|
+
expect(after.resources).toEqual(before.resources);
|
|
367
|
+
const added = after.notes.filter((n) => !before.notes.includes(n));
|
|
368
|
+
expect(added).toHaveLength(1);
|
|
369
|
+
expect(added[0]).toMatch(/engine facts are absent: `choudoufu live-graph -json -from-plan` failed \(choudoufu live-graph failed in \/x \(exit 1\)\)/);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("a live-plan that failed runs no live-graph at all", async () => {
|
|
373
|
+
const calls: LiveGraphCall[] = [];
|
|
374
|
+
const failing: TerraformReadDeps = {
|
|
375
|
+
...deps(answers(LIVE_GRAPH), calls),
|
|
376
|
+
livePlan: (async () => {
|
|
377
|
+
throw new Error("choudoufu live-plan failed (exit 1)");
|
|
378
|
+
}) as unknown as TerraformReadDeps["livePlan"],
|
|
379
|
+
};
|
|
380
|
+
const observed = normalizeObservation(await describeResources(options(await render()), failing));
|
|
381
|
+
expect(calls).toEqual([]);
|
|
382
|
+
expect(Object.keys(observed.unobserved).length).toBeGreaterThan(0);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("classifies the usage errors older builds print", () => {
|
|
386
|
+
expect(classifyLiveGraphFailure(1, 'OpenTofu has no command named "live-graph".\n\nTo see all of OpenTofu\'s top-level commands, run:\n choudoufu -help\n')).toBe("unsupported");
|
|
387
|
+
expect(classifyLiveGraphFailure(127, "Usage: choudoufu [global options] <subcommand> [args]")).toBe("unsupported");
|
|
388
|
+
expect(classifyLiveGraphFailure(1, "flag provided but not defined: -from-plan")).toBe("unsupported");
|
|
389
|
+
expect(classifyLiveGraphFailure(1, "Error: The live plan is of another estate")).toBe("failed");
|
|
390
|
+
expect(classifyLiveGraphFailure(1, "Error: Cannot read the live plan")).toBe("failed");
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("builds the command with no DIR and no -history", () => {
|
|
394
|
+
expect(choudoufuLiveGraphCommand({ binary: "choudoufu", fromPlan: "/tmp/out/estate.live-plan.json" })).toBe(
|
|
395
|
+
"choudoufu live-graph -json -from-plan=/tmp/out/estate.live-plan.json",
|
|
396
|
+
);
|
|
397
|
+
expect(choudoufuLiveGraphCommand({ binary: "choudoufu", fromPlan: "/tmp/a b/x.json", estate: "web" })).toBe(
|
|
398
|
+
"choudoufu live-graph -json -from-plan='/tmp/a b/x.json' -estate=web",
|
|
399
|
+
);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
describe("the floors (#4528)", () => {
|
|
404
|
+
it("the choudoufu floor is the release that ships live-graph, above the read floor", () => {
|
|
405
|
+
expect(MIN_CHOUDOUFU_GRAPH_VERSION).toBe("0.32.0");
|
|
406
|
+
expect(isOlderVersion(MIN_CHOUDOUFU_VERSION, MIN_CHOUDOUFU_GRAPH_VERSION)).toBe(true);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("the chant floor for writing facts is the next release", () => {
|
|
410
|
+
expect(ENGINE_FACTS_FLOOR).toBe(NEXT_RELEASE);
|
|
411
|
+
});
|
|
412
|
+
});
|