@intentius/chant-lexicon-terraform 0.104.1 → 0.104.3
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/components/capability-plugin.d.ts +22 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/terraform.d.ts +177 -0
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/capability-plugin.test.ts +90 -0
- package/src/components/capability-plugin.ts +77 -1
- package/src/op/activities/choudoufu-waves.test.ts +176 -0
- package/src/op/activities/terraform.ts +408 -3
|
@@ -25,6 +25,28 @@
|
|
|
25
25
|
* Run without a wave plan (`chant run --components`, or a fan-out with no
|
|
26
26
|
* wave gate), `run` plans and applies in one go, which is what `terraform
|
|
27
27
|
* apply` with no plan file does too.
|
|
28
|
+
*
|
|
29
|
+
* ## choudoufu roots in a gated wave (#3459)
|
|
30
|
+
*
|
|
31
|
+
* A live choudoufu root that `live-plan-set` can plan as chant would (no
|
|
32
|
+
* `vars`, no var files, no backend config; see `choudoufuWaveRoot`) goes
|
|
33
|
+
* through choudoufu's own set commands (choudoufu#1754), which need
|
|
34
|
+
* choudoufu v0.22.0 (`MIN_CHOUDOUFU_WAVES_VERSION`):
|
|
35
|
+
*
|
|
36
|
+
* - `plan` runs `live-plan-set -json` over the root as a one-root set. The
|
|
37
|
+
* wave gate still binds chant's `terraformPlanDigest` of the plan the
|
|
38
|
+
* document embeds, the same string a single-root gate binds. choudoufu's
|
|
39
|
+
* set digest is kept for the apply, and its root digest is the change-set
|
|
40
|
+
* part's `nativeDigest`.
|
|
41
|
+
* - `run` hands that document and choudoufu's set digest to
|
|
42
|
+
* `live-wave-apply`, which plans the root again and applies nothing when
|
|
43
|
+
* the plan moved (exit 3).
|
|
44
|
+
* - choudoufu's resume file is kept in the fan-out's attempt record
|
|
45
|
+
* (`DeployContext.carry`) after every apply, landed or not, and written
|
|
46
|
+
* back on the next attempt when it was written for the same set digest.
|
|
47
|
+
*
|
|
48
|
+
* chant's waves stay the order. Each root is its own one-root set, so
|
|
49
|
+
* choudoufu's wave over it is always wave 1.
|
|
28
50
|
*/
|
|
29
51
|
import type { Capability } from "@intentius/chant/components/capability";
|
|
30
52
|
import { type CapabilityPlugin } from "@intentius/chant/components/capability-plugin";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAiC,MAAM,wCAAwC,CAAC;AAExG,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAWzG,0CAA0C;AAC1C,MAAM,WAAW,uBAAuB;IACtC,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,6FAA6F;AAC7F,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,YAAY,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAmED,eAAO,MAAM,wBAAwB,EAAE,UAAU,CAAC,uBAAuB,EAAE,wBAAwB,CAwClG,CAAC;AAEF,eAAO,MAAM,uBAAuB;aAClC,KAAK,YAAG,iBAAiB;CACjB,CAAC;AAEX,eAAO,MAAM,yBAAyB,EAAE,gBAWvC,CAAC"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "3ee2ce9ce0166f20d489f1628e86c43499330e1117ea31805b3103d569770d23",
|
|
5
5
|
"meta.json": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
|
|
6
6
|
"types/index.d.ts": "022927e6a7b351cc4cf52d5f973f60ccd140e5810e17b32fb8868965aa1db161",
|
|
7
7
|
"rules/plan-before-apply.ts": "31b1b3176799fd365b2583fe3947edd187c2a863e3dc0094ed9e91ece2464c99",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"rules/tf045.ts": "760b1f4f385fbe7a86897efe3078fdeac11bcc9bfb806285d63db50488174b7b",
|
|
57
57
|
"skills/chant-terraform.md": "d9ca7b7c28aed0038ce775a3491150298492eed2858fd3651ed9bfca0e577ae8"
|
|
58
58
|
},
|
|
59
|
-
"composite": "
|
|
59
|
+
"composite": "57d4f388168f72ef71e52530804ecdc19628cf0707ede67c432bde5a0efeb45c"
|
|
60
60
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -71,6 +71,34 @@ export declare const DEFAULT_LIVE_PLAN_DOCUMENT_FILE = "chant.live-plan.json";
|
|
|
71
71
|
* shipped the last of the three.
|
|
72
72
|
*/
|
|
73
73
|
export declare const MIN_CHOUDOUFU_VERSION = "0.15.0";
|
|
74
|
+
/**
|
|
75
|
+
* The choudoufu release a gated wave needs for a choudoufu root (#3459):
|
|
76
|
+
* the set digest on `live-plan-set -json`, and `live-wave-apply` with its
|
|
77
|
+
* resume file (choudoufu#1754, merged as choudoufu PR 1816 after v0.21.0).
|
|
78
|
+
* choudoufu's changelog lists both under `v0.22.0 (Unreleased)`, so this is
|
|
79
|
+
* the version main releases as.
|
|
80
|
+
*
|
|
81
|
+
* Only the wave path checks it, so plain `terraform` and `tofu` roots, and a
|
|
82
|
+
* choudoufu root run any other way, do not wait on it. A dev build prints no
|
|
83
|
+
* release version. For one, the check is the capability itself: a set plan
|
|
84
|
+
* document without a top-level `digest` came from a choudoufu older than
|
|
85
|
+
* choudoufu#1754, and {@link choudoufuPlanSet} refuses it.
|
|
86
|
+
*/
|
|
87
|
+
export declare const MIN_CHOUDOUFU_WAVES_VERSION = "0.22.0";
|
|
88
|
+
/**
|
|
89
|
+
* Where a choudoufu root's wave files live, relative to the project root:
|
|
90
|
+
* `<root>/plan-set.json` (the set plan document chant planned and the
|
|
91
|
+
* approver approved), `<root>/resume-<digest>.json` (choudoufu's resume
|
|
92
|
+
* file) and `<root>/out/` (plan files and logs).
|
|
93
|
+
*/
|
|
94
|
+
export declare const CHOUDOUFU_WAVES_DIR = ".chant/choudoufu-waves";
|
|
95
|
+
/** `live-wave-apply`'s exit statuses (choudoufu#1754). */
|
|
96
|
+
export declare const CHOUDOUFU_WAVE_EXIT: {
|
|
97
|
+
readonly landed: 0;
|
|
98
|
+
readonly error: 1;
|
|
99
|
+
readonly setMoved: 3;
|
|
100
|
+
readonly rootFailed: 4;
|
|
101
|
+
};
|
|
74
102
|
/**
|
|
75
103
|
* choudoufu's own refusal summary for `-out` on the `live-plan -estate`
|
|
76
104
|
* surface (`internal/command/live_mode.go`). That is the one surface where a
|
|
@@ -550,6 +578,14 @@ export declare function isOlderVersion(version: string, min: string): boolean;
|
|
|
550
578
|
export declare function parseChoudoufuVersion(versionOutput: string): string | undefined;
|
|
551
579
|
/** Test-only: clear the cached version check so a test can simulate a fresh module load. */
|
|
552
580
|
export declare function __resetChoudoufuVersionCheckForTests(): void;
|
|
581
|
+
/**
|
|
582
|
+
* Why `choudoufu version`'s output cannot drive a gated wave, or `undefined`
|
|
583
|
+
* when it can (#3459). A release older than
|
|
584
|
+
* {@link MIN_CHOUDOUFU_WAVES_VERSION} is refused. A dev build names no
|
|
585
|
+
* release and passes here; {@link parseChoudoufuPlanSet} then refuses a set
|
|
586
|
+
* plan document with no digest, which is what an older dev build prints.
|
|
587
|
+
*/
|
|
588
|
+
export declare function choudoufuWavesVersionRefusal(versionOutput: string): string | undefined;
|
|
553
589
|
/**
|
|
554
590
|
* `terraform init` in the named root, with the root's `backendConfig` supplied
|
|
555
591
|
* as `-backend-config` flags. Uses the longInfra profile: init downloads
|
|
@@ -605,6 +641,147 @@ export declare function terraformApply(args: TerraformApplyArgs, signal?: AbortS
|
|
|
605
641
|
* asked for the values to hand them on.
|
|
606
642
|
*/
|
|
607
643
|
export declare function terraformOutputs(args: TerraformRootArgs, signal?: AbortSignal): Promise<Record<string, unknown>>;
|
|
644
|
+
/**
|
|
645
|
+
* `live-plan-set -json` over one root, from the project root, so the
|
|
646
|
+
* document names the root by its path from there, which is what
|
|
647
|
+
* `live-wave-apply` resolves it against.
|
|
648
|
+
*/
|
|
649
|
+
export declare function choudoufuPlanSetCommand(opts: {
|
|
650
|
+
binary: string;
|
|
651
|
+
root: string;
|
|
652
|
+
outDir: string;
|
|
653
|
+
}): string;
|
|
654
|
+
/**
|
|
655
|
+
* `live-wave-apply` over a one-root set. The set chant hands choudoufu is
|
|
656
|
+
* one root, so choudoufu's waves over it are a single wave and `-wave=1` is
|
|
657
|
+
* always that root's. chant's waves are the order; choudoufu's command is
|
|
658
|
+
* the apply, with its set check and its resume file.
|
|
659
|
+
*/
|
|
660
|
+
export declare function choudoufuWaveApplyCommand(opts: {
|
|
661
|
+
binary: string;
|
|
662
|
+
planSet: string;
|
|
663
|
+
digest: string;
|
|
664
|
+
resume: string;
|
|
665
|
+
outDir: string;
|
|
666
|
+
}): string;
|
|
667
|
+
/**
|
|
668
|
+
* The root's directory as a set plan document names it: its path from the
|
|
669
|
+
* project root, with forward slashes. `undefined` when the root is the
|
|
670
|
+
* project root itself or outside it, since choudoufu takes only roots inside
|
|
671
|
+
* the working directory.
|
|
672
|
+
*/
|
|
673
|
+
export declare function choudoufuSetRootPath(projectRoot: string, dir: string): string | undefined;
|
|
674
|
+
/** A root that a gated wave runs through `live-plan-set` and `live-wave-apply`. */
|
|
675
|
+
export interface ChoudoufuWaveRootArgs extends TerraformRootArgs {
|
|
676
|
+
/** The step's `-var` values. A root given any is not a wave root: see {@link choudoufuWaveRoot}. */
|
|
677
|
+
vars?: Record<string, unknown>;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Whether a gated wave runs this root through choudoufu's own set commands
|
|
681
|
+
* (#3459), and if not, why not. It does for a live choudoufu root that
|
|
682
|
+
* `live-plan-set` can plan as chant would: those commands run plain `init`
|
|
683
|
+
* and `plan` in each root, with no `-var-file`, no `-var` and no
|
|
684
|
+
* `-backend-config`, so a root that needs any of them goes the `plan -out`
|
|
685
|
+
* and `apply PLANFILE` way instead, where choudoufu's per-root refusal
|
|
686
|
+
* (choudoufu #878) still stands in front of the apply.
|
|
687
|
+
*/
|
|
688
|
+
export declare function choudoufuWaveRoot(args: ChoudoufuWaveRootArgs, signal?: AbortSignal): Promise<{
|
|
689
|
+
wave: true;
|
|
690
|
+
root: string;
|
|
691
|
+
} | {
|
|
692
|
+
wave: false;
|
|
693
|
+
reason: string;
|
|
694
|
+
}>;
|
|
695
|
+
/** What {@link parseChoudoufuPlanSet} read out of a one-root set plan document. */
|
|
696
|
+
export interface ChoudoufuPlanSet {
|
|
697
|
+
/** choudoufu's set digest: what `live-wave-apply -digest` takes. */
|
|
698
|
+
setDigest: string;
|
|
699
|
+
/** choudoufu's digest of the one root. */
|
|
700
|
+
rootDigest: string;
|
|
701
|
+
/** chant's {@link terraformPlanDigest} over the root's embedded plan: what the wave gate binds. */
|
|
702
|
+
planDigest: string;
|
|
703
|
+
changed: boolean;
|
|
704
|
+
/** The root's `show -json` plan, as the document embeds it. */
|
|
705
|
+
json: unknown;
|
|
706
|
+
/** The member's change-set part, with choudoufu's root digest as `nativeDigest`. */
|
|
707
|
+
changeSet: ChangeSetPart;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Read `live-plan-set -json`'s document for one root (#3459). Refuses a
|
|
711
|
+
* document with no set digest: that choudoufu predates choudoufu#1754, and
|
|
712
|
+
* this is how a dev build, which names no release, is held to
|
|
713
|
+
* {@link MIN_CHOUDOUFU_WAVES_VERSION}. Refuses a root that did not plan,
|
|
714
|
+
* with choudoufu's own error.
|
|
715
|
+
*/
|
|
716
|
+
export declare function parseChoudoufuPlanSet(stdout: string, opts: {
|
|
717
|
+
member: string;
|
|
718
|
+
root: string;
|
|
719
|
+
}): ChoudoufuPlanSet;
|
|
720
|
+
/** What {@link choudoufuPlanSet} planned. */
|
|
721
|
+
export interface ChoudoufuPlanSetResult extends ChoudoufuPlanSet {
|
|
722
|
+
/** The set plan document, written as choudoufu printed it. `live-wave-apply -plan-set` reads this file. */
|
|
723
|
+
planSetFile: string;
|
|
724
|
+
/** The root's path as the document names it. */
|
|
725
|
+
root: string;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Plan one live choudoufu root as a one-root set: `live-plan-set -json` from
|
|
729
|
+
* the project root (#3459). The document goes to
|
|
730
|
+
* `<CHOUDOUFU_WAVES_DIR>/<root>/plan-set.json`, the file a later
|
|
731
|
+
* `live-wave-apply` hands back to choudoufu with the set digest.
|
|
732
|
+
*/
|
|
733
|
+
export declare function choudoufuPlanSet(args: TerraformRootArgs, signal?: AbortSignal): Promise<ChoudoufuPlanSetResult>;
|
|
734
|
+
/**
|
|
735
|
+
* What a choudoufu root keeps in the fan-out's attempt record (#3459):
|
|
736
|
+
* choudoufu's resume file, under the set digest it was written for.
|
|
737
|
+
*/
|
|
738
|
+
export interface ChoudoufuCarriedResume {
|
|
739
|
+
kind: "choudoufu-wave-resume";
|
|
740
|
+
setDigest: string;
|
|
741
|
+
resume: unknown;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* The resume file to hand choudoufu for `setDigest`, from what an earlier
|
|
745
|
+
* attempt carried, or `undefined`. choudoufu refuses a resume file written
|
|
746
|
+
* for another digest, and a re-planned root with a moved plan has another
|
|
747
|
+
* digest, so only a file for this same set comes back.
|
|
748
|
+
*/
|
|
749
|
+
export declare function carriedChoudoufuResume(carried: unknown, setDigest: string): unknown;
|
|
750
|
+
export interface ChoudoufuWaveApplyArgs extends TerraformRootArgs {
|
|
751
|
+
/** {@link ChoudoufuPlanSetResult.planSetFile}: the approved document. */
|
|
752
|
+
planSetFile: string;
|
|
753
|
+
/** {@link ChoudoufuPlanSetResult.setDigest}: choudoufu's digest of that document. */
|
|
754
|
+
setDigest: string;
|
|
755
|
+
/** What the root carried from an earlier attempt (`DeployContext.carried[root]`). */
|
|
756
|
+
carried?: unknown;
|
|
757
|
+
}
|
|
758
|
+
export interface ChoudoufuWaveApplyResult {
|
|
759
|
+
/** `live-wave-apply`'s exit status. See {@link CHOUDOUFU_WAVE_EXIT}. */
|
|
760
|
+
exitCode: number;
|
|
761
|
+
/** Exit 0: the root landed. */
|
|
762
|
+
landed: boolean;
|
|
763
|
+
/** `-json`'s result document, when it printed one. */
|
|
764
|
+
result?: unknown;
|
|
765
|
+
/** choudoufu's resume file after the run, to carry. Absent when choudoufu wrote none. */
|
|
766
|
+
carry?: ChoudoufuCarriedResume;
|
|
767
|
+
/** One line for a person: what happened, in choudoufu's words where it gave some. */
|
|
768
|
+
message: string;
|
|
769
|
+
}
|
|
770
|
+
/** One line for each of `live-wave-apply`'s exit statuses, with choudoufu's own error when it gave one. */
|
|
771
|
+
export declare function describeChoudoufuWaveExit(exitCode: number, result: unknown, stderr: string): string;
|
|
772
|
+
/**
|
|
773
|
+
* Apply one live choudoufu root through `live-wave-apply` (#3459), with the
|
|
774
|
+
* set plan document and set digest {@link choudoufuPlanSet} produced. When
|
|
775
|
+
* the root carried a resume file for this same digest from an earlier
|
|
776
|
+
* attempt, it is written back first, so choudoufu sees what it already
|
|
777
|
+
* recorded. Its resume file after the run comes back as `carry`, landed or
|
|
778
|
+
* not.
|
|
779
|
+
*
|
|
780
|
+
* Never throws for a choudoufu answer: exit 3 (the set moved) and exit 4 (the
|
|
781
|
+
* root failed) come back with `landed: false`, and so does exit 1. An abort
|
|
782
|
+
* or a spawn failure propagates.
|
|
783
|
+
*/
|
|
784
|
+
export declare function choudoufuWaveApply(args: ChoudoufuWaveApplyArgs, signal?: AbortSignal): Promise<ChoudoufuWaveApplyResult>;
|
|
608
785
|
/**
|
|
609
786
|
* `terraform show` over current state, or over a saved plan when `planFile` is
|
|
610
787
|
* given. Returns the parsed `-json` output and the `-no-color` render, plus
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terraform.d.ts","sourceRoot":"","sources":["../../../src/op/activities/terraform.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"terraform.d.ts","sourceRoot":"","sources":["../../../src/op/activities/terraform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAUH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAWrB,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,cAAc,CAAC;AAEpD,gHAAgH;AAChH,eAAO,MAAM,+BAA+B,yBAAyB,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,WAAW,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAE5D,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB;aAAK,MAAM,EAAE,CAAC;aAAE,KAAK,EAAE,CAAC;aAAE,QAAQ,EAAE,CAAC;aAAE,UAAU,EAAE,CAAC;CAAW,CAAC;AAEhG;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,mEACsB,CAAC;AAEnE,mHAAmH;AACnH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,wGAAwG;AACxG,eAAO,MAAM,mCAAmC,wDAAwD,CAAC;AAEzG,0GAA0G;AAC1G,eAAO,MAAM,8BAA8B,oDAAoD,CAAC;AAIhG,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,mHAAmH;IACnH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAEvD,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D;;;;;OAKG;IACH,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B;;;;OAIG;IACH,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,2DAA2D;AAC3D,MAAM,WAAW,gBAAgB;IAC/B,qGAAqG;IACrG,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE7G,+FAA+F;AAC/F,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;IACjB,+FAA+F;IAC/F,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,IAAI,EAAE,OAAO,CAAC;IACd,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,EAAE,aAAa,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB,GAAG,mBAAmB,GAAG,cAAc,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB,EAAE,gBAAgB;IACtF,wFAAwF;IACxF,KAAK,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iHAAiH;IACjH,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,kGAAkG;IAClG,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,yHAAyH;IACzH,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6CAA6C;AAC7C,MAAM,WAAW,qBAAqB;IACpC,sFAAsF;IACtF,IAAI,EAAE,OAAO,CAAC;IACd,yHAAyH;IACzH,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,SAAS,EAAE,WAAW,CAAC;IACvB,mFAAmF;IACnF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,gDAAgD;AAChD,MAAM,WAAW,wBAAwB;IACvC,8FAA8F;IAC9F,OAAO,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,IAAI,EAAE,OAAO,CAAC;IACd,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK1G;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,MAAM,CAQT;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CAUT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAExF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,CAcT;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAI7G;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,qBAAqB,CAS7E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAIvG;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,gBAAgB,CAYpE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAMxE;AAgBD,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAOpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/E;AA8BD,4FAA4F;AAC5F,wBAAgB,oCAAoC,IAAI,IAAI,CAG3D;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQtF;AAsHD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,iBAAiB,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAa9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,iBAAiB,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAmD9B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAI5F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAoC/B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,iBAAiB,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAKlC;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEtG;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAWT;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzF;AAED,mFAAmF;AACnF,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,oGAAoG;IACpG,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBzE;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAC;IACd,oFAAoF;IACpF,SAAS,EAAE,aAAa,CAAC;CAC1B;AAKD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAyC9G;AAYD,6CAA6C;AAC7C,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,2GAA2G;IAC3G,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA6BrH;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAInF;AAED,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAoBnG;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA0D9H;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,iBAAiB,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CA2B9B;AA6BD;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED;;;;GAIG;AACH,MAAM,WAAW,+BAAgC,SAAQ,qBAAqB;IAC5E,wFAAwF;IACxF,KAAK,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,qBAAqB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,+BAA+B,CAAC,CAiD1C;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,EACvD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,uBAAuB,CAAC,CAiElC;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,mBAAmB,EACzB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,qBAAqB,CAAC,CAkBhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA8C/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,wBAAwB,CAAC,CAuBnC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-terraform",
|
|
3
|
-
"version": "0.104.
|
|
3
|
+
"version": "0.104.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@intentius/chant": "^0.104.
|
|
70
|
+
"@intentius/chant": "^0.104.3",
|
|
71
71
|
"typescript": "^5.9.3",
|
|
72
72
|
"zod": "^4.3.6"
|
|
73
73
|
},
|
|
@@ -8,8 +8,31 @@ import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
|
8
8
|
const calls: string[] = [];
|
|
9
9
|
let applyResult: Record<string, unknown> = { applied: true };
|
|
10
10
|
let changeSet: Record<string, unknown> | undefined;
|
|
11
|
+
// #3459: whether the root goes through choudoufu's set commands, and what they answer.
|
|
12
|
+
let waveRoot: { wave: true; root: string } | { wave: false; reason: string } = { wave: false, reason: "the root runs terraform" };
|
|
13
|
+
let waveApply: Record<string, unknown> = { exitCode: 0, landed: true, message: "landed" };
|
|
14
|
+
const waveApplyArgs: Array<Record<string, unknown>> = [];
|
|
11
15
|
|
|
12
16
|
vi.mock("../op/activities/terraform", () => ({
|
|
17
|
+
choudoufuWaveRoot: vi.fn(async () => waveRoot),
|
|
18
|
+
choudoufuPlanSet: vi.fn(async (args: { root: string }) => {
|
|
19
|
+
calls.push(`plan-set ${args.root}`);
|
|
20
|
+
return {
|
|
21
|
+
setDigest: `sha256:set-${args.root}`,
|
|
22
|
+
rootDigest: `sha256:root-${args.root}`,
|
|
23
|
+
planDigest: `jcs1-sha256:${args.root}`,
|
|
24
|
+
changed: true,
|
|
25
|
+
json: {},
|
|
26
|
+
changeSet: { member: { member: args.root, nativeDigest: `sha256:root-${args.root}` }, entries: [] },
|
|
27
|
+
planSetFile: `/x/.chant/choudoufu-waves/${args.root}/plan-set.json`,
|
|
28
|
+
root: `estates/${args.root}`,
|
|
29
|
+
};
|
|
30
|
+
}),
|
|
31
|
+
choudoufuWaveApply: vi.fn(async (args: Record<string, unknown>) => {
|
|
32
|
+
calls.push(`wave-apply ${String(args.root)} ${String(args.setDigest)}`);
|
|
33
|
+
waveApplyArgs.push(args);
|
|
34
|
+
return waveApply;
|
|
35
|
+
}),
|
|
13
36
|
terraformInit: vi.fn(async (args: { root: string }) => {
|
|
14
37
|
calls.push(`init ${args.root}`);
|
|
15
38
|
return { dir: `/x/${args.root}` };
|
|
@@ -34,6 +57,73 @@ beforeEach(() => {
|
|
|
34
57
|
calls.length = 0;
|
|
35
58
|
applyResult = { applied: true };
|
|
36
59
|
changeSet = undefined;
|
|
60
|
+
waveRoot = { wave: false, reason: "the root runs terraform" };
|
|
61
|
+
waveApply = { exitCode: 0, landed: true, message: "landed" };
|
|
62
|
+
waveApplyArgs.length = 0;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("terraform-apply on a choudoufu root in a gated wave (#3459)", () => {
|
|
66
|
+
const resume = { format_version: "1", set_digest: "sha256:set-e01", roots: [{ root: "estates/e01", wave: 1, outcome: "landed" }] };
|
|
67
|
+
const carry = { kind: "choudoufu-wave-resume", setDigest: "sha256:set-e01", resume };
|
|
68
|
+
const wavePlan = {
|
|
69
|
+
planDigest: "jcs1-sha256:e01",
|
|
70
|
+
choudoufu: { planSetFile: "/x/.chant/choudoufu-waves/e01/plan-set.json", setDigest: "sha256:set-e01" },
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
test("plan runs live-plan-set and binds chant's plan digest, keeping choudoufu's set digest for the apply", async () => {
|
|
74
|
+
waveRoot = { wave: true, root: "estates/e01" };
|
|
75
|
+
const planned = await terraformApplyCapability.plan!({ env: "test", component: "e01" }, { root: "e01" });
|
|
76
|
+
expect(calls).toEqual(["plan-set e01"]);
|
|
77
|
+
expect(planned.member).toBe("e01");
|
|
78
|
+
expect(planned.planDigest).toBe("jcs1-sha256:e01");
|
|
79
|
+
expect(planned.artifact).toEqual(wavePlan);
|
|
80
|
+
expect(planned.changeSet).toEqual({ member: { member: "e01", nativeDigest: "sha256:root-e01" }, entries: [] });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("a choudoufu root live-plan-set cannot plan as chant would keeps plan -out", async () => {
|
|
84
|
+
waveRoot = { wave: false, reason: "the step passes -var values, which live-plan-set does not take" };
|
|
85
|
+
await terraformApplyCapability.plan!({ env: "test", component: "e01" }, { root: "e01", vars: { a: "b" } });
|
|
86
|
+
expect(calls).toEqual(["init e01", 'plan e01 {"a":"b"}']);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("run hands the approved document and set digest to live-wave-apply and carries the resume file", async () => {
|
|
90
|
+
waveApply = { exitCode: 0, landed: true, message: "landed", carry };
|
|
91
|
+
const kept: Array<[string, unknown]> = [];
|
|
92
|
+
const out = await terraformApplyCapability.run(
|
|
93
|
+
{ env: "test", component: "e01", plans: { e01: wavePlan }, carry: (m, v) => kept.push([m, v]) },
|
|
94
|
+
{ root: "e01" },
|
|
95
|
+
);
|
|
96
|
+
expect(calls).toEqual(["wave-apply e01 sha256:set-e01", "output e01"]);
|
|
97
|
+
expect(waveApplyArgs[0]).toMatchObject({ root: "e01", planSetFile: wavePlan.choudoufu.planSetFile, setDigest: "sha256:set-e01" });
|
|
98
|
+
expect(kept).toEqual([["e01", carry]]);
|
|
99
|
+
expect(out).toEqual({ root: "e01", planDigest: "jcs1-sha256:e01", fromWavePlan: true, outputs: { id: "e01-id" } });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("run passes what an earlier attempt carried for the root", async () => {
|
|
103
|
+
await terraformApplyCapability.run(
|
|
104
|
+
{ env: "test", component: "e01", plans: { e01: wavePlan }, carried: { e01: carry, other: { x: 1 } } },
|
|
105
|
+
{ root: "e01" },
|
|
106
|
+
);
|
|
107
|
+
expect(waveApplyArgs[0]!.carried).toEqual(carry);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("a moved set fails the step, applies nothing more, and still carries the resume file", async () => {
|
|
111
|
+
waveApply = {
|
|
112
|
+
exitCode: 3,
|
|
113
|
+
landed: false,
|
|
114
|
+
message: "choudoufu refused the approved set: the root's plan moved since it was approved, and nothing was applied",
|
|
115
|
+
carry,
|
|
116
|
+
};
|
|
117
|
+
const kept: unknown[] = [];
|
|
118
|
+
await expect(
|
|
119
|
+
terraformApplyCapability.run(
|
|
120
|
+
{ env: "test", component: "e01", plans: { e01: wavePlan }, carry: (_m, v) => kept.push(v) },
|
|
121
|
+
{ root: "e01" },
|
|
122
|
+
),
|
|
123
|
+
).rejects.toThrow(/root "e01": choudoufu refused the approved set/);
|
|
124
|
+
expect(calls).toEqual(["wave-apply e01 sha256:set-e01"]);
|
|
125
|
+
expect(kept).toEqual([carry]);
|
|
126
|
+
});
|
|
37
127
|
});
|
|
38
128
|
|
|
39
129
|
describe("terraform-apply", () => {
|
|
@@ -25,12 +25,42 @@
|
|
|
25
25
|
* Run without a wave plan (`chant run --components`, or a fan-out with no
|
|
26
26
|
* wave gate), `run` plans and applies in one go, which is what `terraform
|
|
27
27
|
* apply` with no plan file does too.
|
|
28
|
+
*
|
|
29
|
+
* ## choudoufu roots in a gated wave (#3459)
|
|
30
|
+
*
|
|
31
|
+
* A live choudoufu root that `live-plan-set` can plan as chant would (no
|
|
32
|
+
* `vars`, no var files, no backend config; see `choudoufuWaveRoot`) goes
|
|
33
|
+
* through choudoufu's own set commands (choudoufu#1754), which need
|
|
34
|
+
* choudoufu v0.22.0 (`MIN_CHOUDOUFU_WAVES_VERSION`):
|
|
35
|
+
*
|
|
36
|
+
* - `plan` runs `live-plan-set -json` over the root as a one-root set. The
|
|
37
|
+
* wave gate still binds chant's `terraformPlanDigest` of the plan the
|
|
38
|
+
* document embeds, the same string a single-root gate binds. choudoufu's
|
|
39
|
+
* set digest is kept for the apply, and its root digest is the change-set
|
|
40
|
+
* part's `nativeDigest`.
|
|
41
|
+
* - `run` hands that document and choudoufu's set digest to
|
|
42
|
+
* `live-wave-apply`, which plans the root again and applies nothing when
|
|
43
|
+
* the plan moved (exit 3).
|
|
44
|
+
* - choudoufu's resume file is kept in the fan-out's attempt record
|
|
45
|
+
* (`DeployContext.carry`) after every apply, landed or not, and written
|
|
46
|
+
* back on the next attempt when it was written for the same set digest.
|
|
47
|
+
*
|
|
48
|
+
* chant's waves stay the order. Each root is its own one-root set, so
|
|
49
|
+
* choudoufu's wave over it is always wave 1.
|
|
28
50
|
*/
|
|
29
51
|
|
|
30
52
|
import type { Capability, DeployContext, CapabilityPlan } from "@intentius/chant/components/capability";
|
|
31
53
|
import type { ChangeSetPart } from "@intentius/chant/change-set";
|
|
32
54
|
import { ownPackageVersion, type CapabilityPlugin } from "@intentius/chant/components/capability-plugin";
|
|
33
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
choudoufuPlanSet,
|
|
57
|
+
choudoufuWaveApply,
|
|
58
|
+
choudoufuWaveRoot,
|
|
59
|
+
terraformApply,
|
|
60
|
+
terraformInit,
|
|
61
|
+
terraformOutputs,
|
|
62
|
+
terraformPlan,
|
|
63
|
+
} from "../op/activities/terraform";
|
|
34
64
|
|
|
35
65
|
/** The `terraform-apply` step's input. */
|
|
36
66
|
export interface TerraformApplyStepInput {
|
|
@@ -82,12 +112,57 @@ function isPlannedRoot(value: unknown): value is PlannedRoot {
|
|
|
82
112
|
return typeof v?.planFile === "string" && typeof v.planDigest === "string";
|
|
83
113
|
}
|
|
84
114
|
|
|
115
|
+
/** What `plan` hands `run` for a choudoufu root planned as a one-root set (#3459). */
|
|
116
|
+
interface ChoudoufuWavePlannedRoot {
|
|
117
|
+
planDigest: string;
|
|
118
|
+
choudoufu: { planSetFile: string; setDigest: string };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isChoudoufuWavePlan(value: unknown): value is ChoudoufuWavePlannedRoot {
|
|
122
|
+
const v = value as Partial<ChoudoufuWavePlannedRoot> | undefined;
|
|
123
|
+
return (
|
|
124
|
+
typeof v?.planDigest === "string" &&
|
|
125
|
+
typeof v.choudoufu?.planSetFile === "string" &&
|
|
126
|
+
typeof v.choudoufu.setDigest === "string"
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Apply a choudoufu root through `live-wave-apply`, carrying its resume file either way. */
|
|
131
|
+
async function runChoudoufuWave(
|
|
132
|
+
ctx: DeployContext,
|
|
133
|
+
input: TerraformApplyStepInput,
|
|
134
|
+
planned: ChoudoufuWavePlannedRoot,
|
|
135
|
+
): Promise<TerraformApplyStepOutput> {
|
|
136
|
+
const applied = await choudoufuWaveApply({
|
|
137
|
+
...rootArgs(input),
|
|
138
|
+
planSetFile: planned.choudoufu.planSetFile,
|
|
139
|
+
setDigest: planned.choudoufu.setDigest,
|
|
140
|
+
...(ctx.carried?.[input.root] !== undefined ? { carried: ctx.carried[input.root] } : {}),
|
|
141
|
+
});
|
|
142
|
+
if (applied.carry) ctx.carry?.(input.root, applied.carry);
|
|
143
|
+
if (!applied.landed) {
|
|
144
|
+
throw new Error(`terraform-apply: root "${input.root}": ${applied.message}`);
|
|
145
|
+
}
|
|
146
|
+
const outputs = await terraformOutputs(rootArgs(input));
|
|
147
|
+
return { root: input.root, planDigest: planned.planDigest, fromWavePlan: true, outputs };
|
|
148
|
+
}
|
|
149
|
+
|
|
85
150
|
export const terraformApplyCapability: Capability<TerraformApplyStepInput, TerraformApplyStepOutput> = {
|
|
86
151
|
kind: "terraform-apply",
|
|
87
152
|
// A root's apply has no undo short of applying the previous configuration,
|
|
88
153
|
// which is a change of its own. COMP003 asks the component to say so.
|
|
89
154
|
rollbackPolicy: "needs-opt-out",
|
|
90
155
|
async plan(_ctx: DeployContext, input: TerraformApplyStepInput): Promise<CapabilityPlan> {
|
|
156
|
+
requireRoot(input);
|
|
157
|
+
const wave = await choudoufuWaveRoot({ ...rootArgs(input), ...(input.vars ? { vars: input.vars } : {}) });
|
|
158
|
+
if (wave.wave) {
|
|
159
|
+
const set = await choudoufuPlanSet(rootArgs(input));
|
|
160
|
+
const artifact: ChoudoufuWavePlannedRoot = {
|
|
161
|
+
planDigest: set.planDigest,
|
|
162
|
+
choudoufu: { planSetFile: set.planSetFile, setDigest: set.setDigest },
|
|
163
|
+
};
|
|
164
|
+
return { member: input.root, planDigest: set.planDigest, artifact, changeSet: set.changeSet };
|
|
165
|
+
}
|
|
91
166
|
const { changeSet, ...planned } = await planRoot(input);
|
|
92
167
|
return { member: input.root, planDigest: planned.planDigest, artifact: planned, ...(changeSet ? { changeSet } : {}) };
|
|
93
168
|
},
|
|
@@ -100,6 +175,7 @@ export const terraformApplyCapability: Capability<TerraformApplyStepInput, Terra
|
|
|
100
175
|
},
|
|
101
176
|
async run(ctx: DeployContext, input: TerraformApplyStepInput): Promise<TerraformApplyStepOutput> {
|
|
102
177
|
const fromWave = ctx.plans?.[input.root];
|
|
178
|
+
if (isChoudoufuWavePlan(fromWave)) return runChoudoufuWave(ctx, input, fromWave);
|
|
103
179
|
const planned: PlannedRoot = isPlannedRoot(fromWave) ? fromWave : await planRoot(input);
|
|
104
180
|
const applied = await terraformApply({ ...rootArgs(input), planFile: planned.planFile });
|
|
105
181
|
if (!applied.applied) {
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* choudoufu roots in a gated wave (#3459): the version floor, the one-root
|
|
3
|
+
* set plan document, the commands, and which resume file comes back.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import {
|
|
9
|
+
MIN_CHOUDOUFU_WAVES_VERSION,
|
|
10
|
+
carriedChoudoufuResume,
|
|
11
|
+
choudoufuPlanSetCommand,
|
|
12
|
+
choudoufuSetRootPath,
|
|
13
|
+
choudoufuWaveApplyCommand,
|
|
14
|
+
choudoufuWavesVersionRefusal,
|
|
15
|
+
describeChoudoufuWaveExit,
|
|
16
|
+
parseChoudoufuPlanSet,
|
|
17
|
+
terraformPlanDigest,
|
|
18
|
+
} from "./terraform";
|
|
19
|
+
|
|
20
|
+
const plan = {
|
|
21
|
+
format_version: "1.2",
|
|
22
|
+
resource_changes: [
|
|
23
|
+
{
|
|
24
|
+
address: "aws_sqs_queue.q",
|
|
25
|
+
mode: "managed",
|
|
26
|
+
type: "aws_sqs_queue",
|
|
27
|
+
name: "q",
|
|
28
|
+
change: { actions: ["create"], before: null, after: { name: "q" } },
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function setDocument(overrides: Record<string, unknown> = {}, root: Record<string, unknown> = {}): string {
|
|
34
|
+
return JSON.stringify({
|
|
35
|
+
format_version: "1",
|
|
36
|
+
roots: [
|
|
37
|
+
{
|
|
38
|
+
root: "estates/e01",
|
|
39
|
+
estate: "e01",
|
|
40
|
+
status: "planned",
|
|
41
|
+
error: "",
|
|
42
|
+
changes: true,
|
|
43
|
+
plan_file: ".chant/choudoufu-waves/e01/out/estates/e01.tfplan",
|
|
44
|
+
log_file: ".chant/choudoufu-waves/e01/out/estates/e01.log",
|
|
45
|
+
duration_ms: 10,
|
|
46
|
+
plan,
|
|
47
|
+
digest: "sha256:root",
|
|
48
|
+
...root,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
summary: { roots: 1, planned: 1, changed: 1, failed: 0 },
|
|
52
|
+
digest: "sha256:set",
|
|
53
|
+
exit_code: 2,
|
|
54
|
+
...overrides,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe("the version floor", () => {
|
|
59
|
+
test("is the release choudoufu#1754 ships in", () => {
|
|
60
|
+
expect(MIN_CHOUDOUFU_WAVES_VERSION).toBe("0.22.0");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("refuses a release older than it", () => {
|
|
64
|
+
const refusal = choudoufuWavesVersionRefusal("choudoufu v0.21.0 (based on OpenTofu v1.13.0)\non darwin_arm64");
|
|
65
|
+
expect(refusal).toMatch(/choudoufu 0\.21\.0 is older than v0\.22\.0/);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("passes that release and later ones", () => {
|
|
69
|
+
expect(choudoufuWavesVersionRefusal("choudoufu v0.22.0 (based on OpenTofu v1.13.0)")).toBeUndefined();
|
|
70
|
+
expect(choudoufuWavesVersionRefusal("choudoufu v1.0.0 (based on OpenTofu v1.13.0)")).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("passes a dev build, which names no release; the document's digest is the check there", () => {
|
|
74
|
+
expect(choudoufuWavesVersionRefusal("OpenTofu v1.13.0-dev\non darwin_arm64")).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("parseChoudoufuPlanSet", () => {
|
|
79
|
+
test("binds chant's digest of the embedded plan and keeps choudoufu's set and root digests", () => {
|
|
80
|
+
const parsed = parseChoudoufuPlanSet(setDocument(), { member: "e01", root: "estates/e01" });
|
|
81
|
+
expect(parsed.setDigest).toBe("sha256:set");
|
|
82
|
+
expect(parsed.rootDigest).toBe("sha256:root");
|
|
83
|
+
expect(parsed.planDigest).toBe(terraformPlanDigest(plan));
|
|
84
|
+
expect(parsed.changed).toBe(true);
|
|
85
|
+
expect(parsed.changeSet.member.member).toBe("e01");
|
|
86
|
+
expect(parsed.changeSet.member.nativeDigest).toBe("sha256:root");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("refuses a document with no set digest: that choudoufu predates choudoufu#1754", () => {
|
|
90
|
+
expect(() => parseChoudoufuPlanSet(setDocument({ digest: undefined }), { member: "e01", root: "estates/e01" })).toThrow(
|
|
91
|
+
/carries no set digest.*v0\.22\.0/,
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("refuses a root that did not plan, with choudoufu's error", () => {
|
|
96
|
+
const doc = setDocument({}, { status: "failed", stage: "init", error: "provider not found", plan: null });
|
|
97
|
+
expect(() => parseChoudoufuPlanSet(doc, { member: "e01", root: "estates/e01" })).toThrow(
|
|
98
|
+
'choudoufu could not plan root "e01" at init: provider not found',
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("refuses a document that is not about this root alone", () => {
|
|
103
|
+
expect(() => parseChoudoufuPlanSet(setDocument(), { member: "e01", root: "estates/e02" })).toThrow(/not only "estates\/e02"/);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("refuses output that is not JSON", () => {
|
|
107
|
+
expect(() => parseChoudoufuPlanSet("Error: something", { member: "e01", root: "estates/e01" })).toThrow(/no JSON document/);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("commands", () => {
|
|
112
|
+
test("live-plan-set plans the one root, as a document", () => {
|
|
113
|
+
expect(choudoufuPlanSetCommand({ binary: "choudoufu", root: "estates/e01", outDir: ".chant/choudoufu-waves/e01/out" })).toBe(
|
|
114
|
+
"choudoufu live-plan-set -json -out-dir=.chant/choudoufu-waves/e01/out estates/e01",
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("live-wave-apply takes the approved document, its set digest, wave 1 and the resume file", () => {
|
|
119
|
+
expect(
|
|
120
|
+
choudoufuWaveApplyCommand({
|
|
121
|
+
binary: "choudoufu",
|
|
122
|
+
planSet: ".chant/choudoufu-waves/e01/plan-set.json",
|
|
123
|
+
digest: "sha256:set",
|
|
124
|
+
resume: ".chant/choudoufu-waves/e01/resume-set.json",
|
|
125
|
+
outDir: ".chant/choudoufu-waves/e01/out",
|
|
126
|
+
}),
|
|
127
|
+
).toBe(
|
|
128
|
+
"choudoufu live-wave-apply -plan-set=.chant/choudoufu-waves/e01/plan-set.json -digest=sha256:set -wave=1 " +
|
|
129
|
+
"-resume=.chant/choudoufu-waves/e01/resume-set.json -out-dir=.chant/choudoufu-waves/e01/out -json",
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a root is named by its path from the project root, and only inside it", () => {
|
|
134
|
+
expect(choudoufuSetRootPath("/p", join("/p", "estates", "e01"))).toBe("estates/e01");
|
|
135
|
+
expect(choudoufuSetRootPath("/p", "/p")).toBeUndefined();
|
|
136
|
+
expect(choudoufuSetRootPath("/p", "/elsewhere/e01")).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("the carried resume file", () => {
|
|
141
|
+
const resume = { format_version: "1", set_digest: "sha256:set", roots: [{ root: "estates/e01", wave: 1, outcome: "failed" }] };
|
|
142
|
+
|
|
143
|
+
test("comes back for the same set digest", () => {
|
|
144
|
+
expect(carriedChoudoufuResume({ kind: "choudoufu-wave-resume", setDigest: "sha256:set", resume }, "sha256:set")).toEqual(resume);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("does not come back for another set digest, which choudoufu would refuse", () => {
|
|
148
|
+
expect(carriedChoudoufuResume({ kind: "choudoufu-wave-resume", setDigest: "sha256:set", resume }, "sha256:other")).toBeUndefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("does not come back when the file inside names another digest, or for something else carried", () => {
|
|
152
|
+
const wrong = { ...resume, set_digest: "sha256:other" };
|
|
153
|
+
expect(carriedChoudoufuResume({ kind: "choudoufu-wave-resume", setDigest: "sha256:set", resume: wrong }, "sha256:set")).toBeUndefined();
|
|
154
|
+
expect(carriedChoudoufuResume({ kind: "something-else" }, "sha256:set")).toBeUndefined();
|
|
155
|
+
expect(carriedChoudoufuResume(undefined, "sha256:set")).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("describeChoudoufuWaveExit", () => {
|
|
160
|
+
test("exit 3 names the moved root and both digests", () => {
|
|
161
|
+
const message = describeChoudoufuWaveExit(
|
|
162
|
+
3,
|
|
163
|
+
{ exit_code: 3, moved: [{ root: "estates/e01", approved_digest: "sha256:a", fresh_digest: "sha256:b" }] },
|
|
164
|
+
"",
|
|
165
|
+
);
|
|
166
|
+
expect(message).toMatch(/nothing was applied/);
|
|
167
|
+
expect(message).toMatch(/estates\/e01 moved: approved sha256:a, now sha256:b/);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("exit 4 points at the resume file, and exit 1 says the command could not run", () => {
|
|
171
|
+
expect(describeChoudoufuWaveExit(4, { exit_code: 4 }, "")).toMatch(/resume file records why/);
|
|
172
|
+
expect(describeChoudoufuWaveExit(1, undefined, "Error: Missing options\n")).toBe(
|
|
173
|
+
"choudoufu live-wave-apply could not run (exit 1) (Error: Missing options)",
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
import { exec } from "node:child_process";
|
|
43
|
-
import { writeFileSync } from "node:fs";
|
|
43
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
44
44
|
import { promisify } from "node:util";
|
|
45
|
-
import { resolve, dirname, join } from "node:path";
|
|
45
|
+
import { resolve, dirname, join, relative, sep } from "node:path";
|
|
46
46
|
import { loadChantConfigUpward } from "@intentius/chant/config";
|
|
47
47
|
import { liveReadKey, memoLiveRead } from "@intentius/chant/live-read-session";
|
|
48
48
|
import { terraformPlanDigest } from "../../plan-digest";
|
|
49
|
-
import { plannerForBinary, terraformChangeSetPart } from "../../change-set";
|
|
49
|
+
import { choudoufuSetPlanParts, plannerForBinary, terraformChangeSetPart } from "../../change-set";
|
|
50
50
|
import type { ChangeSetPart } from "@intentius/chant/change-set";
|
|
51
51
|
import type { TerraformConfig, TerraformRootConfig } from "../../config";
|
|
52
52
|
import { detectLiveEstate } from "./live-detect";
|
|
@@ -100,6 +100,32 @@ export const DEFAULT_LIVE_PLAN_DOCUMENT_FILE = "chant.live-plan.json";
|
|
|
100
100
|
*/
|
|
101
101
|
export const MIN_CHOUDOUFU_VERSION = "0.15.0";
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The choudoufu release a gated wave needs for a choudoufu root (#3459):
|
|
105
|
+
* the set digest on `live-plan-set -json`, and `live-wave-apply` with its
|
|
106
|
+
* resume file (choudoufu#1754, merged as choudoufu PR 1816 after v0.21.0).
|
|
107
|
+
* choudoufu's changelog lists both under `v0.22.0 (Unreleased)`, so this is
|
|
108
|
+
* the version main releases as.
|
|
109
|
+
*
|
|
110
|
+
* Only the wave path checks it, so plain `terraform` and `tofu` roots, and a
|
|
111
|
+
* choudoufu root run any other way, do not wait on it. A dev build prints no
|
|
112
|
+
* release version. For one, the check is the capability itself: a set plan
|
|
113
|
+
* document without a top-level `digest` came from a choudoufu older than
|
|
114
|
+
* choudoufu#1754, and {@link choudoufuPlanSet} refuses it.
|
|
115
|
+
*/
|
|
116
|
+
export const MIN_CHOUDOUFU_WAVES_VERSION = "0.22.0";
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Where a choudoufu root's wave files live, relative to the project root:
|
|
120
|
+
* `<root>/plan-set.json` (the set plan document chant planned and the
|
|
121
|
+
* approver approved), `<root>/resume-<digest>.json` (choudoufu's resume
|
|
122
|
+
* file) and `<root>/out/` (plan files and logs).
|
|
123
|
+
*/
|
|
124
|
+
export const CHOUDOUFU_WAVES_DIR = ".chant/choudoufu-waves";
|
|
125
|
+
|
|
126
|
+
/** `live-wave-apply`'s exit statuses (choudoufu#1754). */
|
|
127
|
+
export const CHOUDOUFU_WAVE_EXIT = { landed: 0, error: 1, setMoved: 3, rootFailed: 4 } as const;
|
|
128
|
+
|
|
103
129
|
/**
|
|
104
130
|
* choudoufu's own refusal summary for `-out` on the `live-plan -estate`
|
|
105
131
|
* surface (`internal/command/live_mode.go`). That is the one surface where a
|
|
@@ -745,6 +771,36 @@ async function ensureChoudoufuVersion(binary: string, signal?: AbortSignal): Pro
|
|
|
745
771
|
/** Test-only: clear the cached version check so a test can simulate a fresh module load. */
|
|
746
772
|
export function __resetChoudoufuVersionCheckForTests(): void {
|
|
747
773
|
choudoufuVersionCheck = undefined;
|
|
774
|
+
choudoufuWavesVersionCheck = undefined;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Why `choudoufu version`'s output cannot drive a gated wave, or `undefined`
|
|
779
|
+
* when it can (#3459). A release older than
|
|
780
|
+
* {@link MIN_CHOUDOUFU_WAVES_VERSION} is refused. A dev build names no
|
|
781
|
+
* release and passes here; {@link parseChoudoufuPlanSet} then refuses a set
|
|
782
|
+
* plan document with no digest, which is what an older dev build prints.
|
|
783
|
+
*/
|
|
784
|
+
export function choudoufuWavesVersionRefusal(versionOutput: string): string | undefined {
|
|
785
|
+
const version = parseChoudoufuVersion(versionOutput);
|
|
786
|
+
if (version === undefined || !isOlderVersion(version, MIN_CHOUDOUFU_WAVES_VERSION)) return undefined;
|
|
787
|
+
return (
|
|
788
|
+
`choudoufu ${version} is older than v${MIN_CHOUDOUFU_WAVES_VERSION}, the first release with the set digest and ` +
|
|
789
|
+
"live-wave-apply (choudoufu#1754) that a gated wave uses for a choudoufu root. Upgrade choudoufu, or run the " +
|
|
790
|
+
"fan-out without --wave-gate."
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/** Cached like {@link choudoufuVersionCheck}, and only ever run on the wave path. */
|
|
795
|
+
let choudoufuWavesVersionCheck: Promise<void> | undefined;
|
|
796
|
+
|
|
797
|
+
async function ensureChoudoufuWavesVersion(binary: string, signal?: AbortSignal): Promise<void> {
|
|
798
|
+
choudoufuWavesVersionCheck ??= (async () => {
|
|
799
|
+
const { stdout } = await execAsync(`${binary} version`, { env: process.env, signal });
|
|
800
|
+
const refusal = choudoufuWavesVersionRefusal(stdout);
|
|
801
|
+
if (refusal) throw new Error(refusal);
|
|
802
|
+
})();
|
|
803
|
+
return choudoufuWavesVersionCheck;
|
|
748
804
|
}
|
|
749
805
|
|
|
750
806
|
// ── Root resolution ─────────────────────────────────────────────────────────
|
|
@@ -759,6 +815,8 @@ interface ResolvedRoot {
|
|
|
759
815
|
estate?: string;
|
|
760
816
|
/** `true` exactly when this root is live: `binary` is `"choudoufu"` and `estate` is set. */
|
|
761
817
|
live: boolean;
|
|
818
|
+
/** The directory the project's `chant.config.*` lives in, which `root.dir` resolves against. */
|
|
819
|
+
projectRoot: string;
|
|
762
820
|
}
|
|
763
821
|
|
|
764
822
|
/**
|
|
@@ -802,6 +860,7 @@ async function resolveRoot(args: TerraformRootArgs, signal?: AbortSignal): Promi
|
|
|
802
860
|
dir,
|
|
803
861
|
...(estate !== undefined ? { estate } : {}),
|
|
804
862
|
live: estate !== undefined || configEstate !== undefined,
|
|
863
|
+
projectRoot,
|
|
805
864
|
};
|
|
806
865
|
}
|
|
807
866
|
|
|
@@ -1029,6 +1088,352 @@ export async function terraformOutputs(
|
|
|
1029
1088
|
return Object.fromEntries(Object.entries(parsed).map(([name, entry]) => [name, entry?.value]));
|
|
1030
1089
|
}
|
|
1031
1090
|
|
|
1091
|
+
// ── choudoufu gated waves (#3459) ───────────────────────────────────────────
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* `live-plan-set -json` over one root, from the project root, so the
|
|
1095
|
+
* document names the root by its path from there, which is what
|
|
1096
|
+
* `live-wave-apply` resolves it against.
|
|
1097
|
+
*/
|
|
1098
|
+
export function choudoufuPlanSetCommand(opts: { binary: string; root: string; outDir: string }): string {
|
|
1099
|
+
return [opts.binary, "live-plan-set", "-json", `-out-dir=${quoteArg(opts.outDir)}`, quoteArg(opts.root)].join(" ");
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* `live-wave-apply` over a one-root set. The set chant hands choudoufu is
|
|
1104
|
+
* one root, so choudoufu's waves over it are a single wave and `-wave=1` is
|
|
1105
|
+
* always that root's. chant's waves are the order; choudoufu's command is
|
|
1106
|
+
* the apply, with its set check and its resume file.
|
|
1107
|
+
*/
|
|
1108
|
+
export function choudoufuWaveApplyCommand(opts: {
|
|
1109
|
+
binary: string;
|
|
1110
|
+
planSet: string;
|
|
1111
|
+
digest: string;
|
|
1112
|
+
resume: string;
|
|
1113
|
+
outDir: string;
|
|
1114
|
+
}): string {
|
|
1115
|
+
return [
|
|
1116
|
+
opts.binary,
|
|
1117
|
+
"live-wave-apply",
|
|
1118
|
+
`-plan-set=${quoteArg(opts.planSet)}`,
|
|
1119
|
+
`-digest=${quoteArg(opts.digest)}`,
|
|
1120
|
+
"-wave=1",
|
|
1121
|
+
`-resume=${quoteArg(opts.resume)}`,
|
|
1122
|
+
`-out-dir=${quoteArg(opts.outDir)}`,
|
|
1123
|
+
"-json",
|
|
1124
|
+
].join(" ");
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* The root's directory as a set plan document names it: its path from the
|
|
1129
|
+
* project root, with forward slashes. `undefined` when the root is the
|
|
1130
|
+
* project root itself or outside it, since choudoufu takes only roots inside
|
|
1131
|
+
* the working directory.
|
|
1132
|
+
*/
|
|
1133
|
+
export function choudoufuSetRootPath(projectRoot: string, dir: string): string | undefined {
|
|
1134
|
+
const rel = relative(projectRoot, dir);
|
|
1135
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${sep}`) || resolve(projectRoot, rel) !== resolve(dir)) return undefined;
|
|
1136
|
+
return rel.split(sep).join("/");
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/** A root that a gated wave runs through `live-plan-set` and `live-wave-apply`. */
|
|
1140
|
+
export interface ChoudoufuWaveRootArgs extends TerraformRootArgs {
|
|
1141
|
+
/** The step's `-var` values. A root given any is not a wave root: see {@link choudoufuWaveRoot}. */
|
|
1142
|
+
vars?: Record<string, unknown>;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Whether a gated wave runs this root through choudoufu's own set commands
|
|
1147
|
+
* (#3459), and if not, why not. It does for a live choudoufu root that
|
|
1148
|
+
* `live-plan-set` can plan as chant would: those commands run plain `init`
|
|
1149
|
+
* and `plan` in each root, with no `-var-file`, no `-var` and no
|
|
1150
|
+
* `-backend-config`, so a root that needs any of them goes the `plan -out`
|
|
1151
|
+
* and `apply PLANFILE` way instead, where choudoufu's per-root refusal
|
|
1152
|
+
* (choudoufu #878) still stands in front of the apply.
|
|
1153
|
+
*/
|
|
1154
|
+
export async function choudoufuWaveRoot(
|
|
1155
|
+
args: ChoudoufuWaveRootArgs,
|
|
1156
|
+
signal?: AbortSignal,
|
|
1157
|
+
): Promise<{ wave: true; root: string } | { wave: false; reason: string }> {
|
|
1158
|
+
const resolved = await resolveRoot(args, signal);
|
|
1159
|
+
if (resolved.binary !== "choudoufu") return { wave: false, reason: `the root runs ${resolved.binary}` };
|
|
1160
|
+
if (!resolved.live) return { wave: false, reason: "the root declares no live estate" };
|
|
1161
|
+
if (args.vars && Object.values(args.vars).some((v) => v !== undefined)) {
|
|
1162
|
+
return { wave: false, reason: "the step passes -var values, which live-plan-set does not take" };
|
|
1163
|
+
}
|
|
1164
|
+
if (resolved.root.varFiles && resolved.root.varFiles.length > 0) {
|
|
1165
|
+
return { wave: false, reason: "the root has var files, which live-plan-set does not take" };
|
|
1166
|
+
}
|
|
1167
|
+
if (resolved.root.backendConfig && Object.keys(resolved.root.backendConfig).length > 0) {
|
|
1168
|
+
return { wave: false, reason: "the root has backend config, which live-plan-set does not take" };
|
|
1169
|
+
}
|
|
1170
|
+
const root = choudoufuSetRootPath(resolved.projectRoot, resolved.dir);
|
|
1171
|
+
if (root === undefined) return { wave: false, reason: "the root's directory is not inside the project" };
|
|
1172
|
+
return { wave: true, root };
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/** What {@link parseChoudoufuPlanSet} read out of a one-root set plan document. */
|
|
1176
|
+
export interface ChoudoufuPlanSet {
|
|
1177
|
+
/** choudoufu's set digest: what `live-wave-apply -digest` takes. */
|
|
1178
|
+
setDigest: string;
|
|
1179
|
+
/** choudoufu's digest of the one root. */
|
|
1180
|
+
rootDigest: string;
|
|
1181
|
+
/** chant's {@link terraformPlanDigest} over the root's embedded plan: what the wave gate binds. */
|
|
1182
|
+
planDigest: string;
|
|
1183
|
+
changed: boolean;
|
|
1184
|
+
/** The root's `show -json` plan, as the document embeds it. */
|
|
1185
|
+
json: unknown;
|
|
1186
|
+
/** The member's change-set part, with choudoufu's root digest as `nativeDigest`. */
|
|
1187
|
+
changeSet: ChangeSetPart;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
const isObjectValue = (value: unknown): value is Record<string, unknown> =>
|
|
1191
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Read `live-plan-set -json`'s document for one root (#3459). Refuses a
|
|
1195
|
+
* document with no set digest: that choudoufu predates choudoufu#1754, and
|
|
1196
|
+
* this is how a dev build, which names no release, is held to
|
|
1197
|
+
* {@link MIN_CHOUDOUFU_WAVES_VERSION}. Refuses a root that did not plan,
|
|
1198
|
+
* with choudoufu's own error.
|
|
1199
|
+
*/
|
|
1200
|
+
export function parseChoudoufuPlanSet(stdout: string, opts: { member: string; root: string }): ChoudoufuPlanSet {
|
|
1201
|
+
let doc: unknown;
|
|
1202
|
+
try {
|
|
1203
|
+
doc = JSON.parse(stdout);
|
|
1204
|
+
} catch {
|
|
1205
|
+
throw new Error(`choudoufu live-plan-set printed no JSON document for root "${opts.member}"`);
|
|
1206
|
+
}
|
|
1207
|
+
if (!isObjectValue(doc) || !Array.isArray(doc.roots)) {
|
|
1208
|
+
throw new Error(`choudoufu live-plan-set printed no set plan document for root "${opts.member}"`);
|
|
1209
|
+
}
|
|
1210
|
+
if (typeof doc.digest !== "string" || doc.digest === "") {
|
|
1211
|
+
throw new Error(
|
|
1212
|
+
`choudoufu's set plan document for root "${opts.member}" carries no set digest, so this choudoufu predates ` +
|
|
1213
|
+
`choudoufu#1754. A gated wave over a choudoufu root needs v${MIN_CHOUDOUFU_WAVES_VERSION} or later.`,
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
const roots = doc.roots.filter(isObjectValue);
|
|
1217
|
+
const entry = roots.find((r) => r.root === opts.root);
|
|
1218
|
+
if (roots.length !== 1 || !entry) {
|
|
1219
|
+
throw new Error(
|
|
1220
|
+
`choudoufu's set plan document for root "${opts.member}" names ${roots.map((r) => String(r.root)).join(", ") || "no root"}, ` +
|
|
1221
|
+
`not only "${opts.root}"`,
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
if (entry.status !== "planned" || !isObjectValue(entry.plan)) {
|
|
1225
|
+
const stage = typeof entry.stage === "string" && entry.stage ? ` at ${entry.stage}` : "";
|
|
1226
|
+
const error = typeof entry.error === "string" && entry.error ? `: ${entry.error}` : "";
|
|
1227
|
+
throw new Error(`choudoufu could not plan root "${opts.member}"${stage}${error}`);
|
|
1228
|
+
}
|
|
1229
|
+
if (typeof entry.digest !== "string" || entry.digest === "") {
|
|
1230
|
+
throw new Error(`choudoufu's set plan document gives root "${opts.member}" no digest`);
|
|
1231
|
+
}
|
|
1232
|
+
const [changeSet] = choudoufuSetPlanParts({ document: doc, memberFor: () => opts.member });
|
|
1233
|
+
return {
|
|
1234
|
+
setDigest: doc.digest,
|
|
1235
|
+
rootDigest: entry.digest,
|
|
1236
|
+
planDigest: terraformPlanDigest(entry.plan),
|
|
1237
|
+
changed: entry.changes === true,
|
|
1238
|
+
json: entry.plan,
|
|
1239
|
+
changeSet: changeSet!,
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/** The directory a root's wave files go in, absolute. */
|
|
1244
|
+
function choudoufuWavesDir(projectRoot: string, root: string): string {
|
|
1245
|
+
return join(projectRoot, CHOUDOUFU_WAVES_DIR, root.replace(/[^A-Za-z0-9._-]/g, "_"));
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/** A path under the project root as choudoufu, run from there, should be given it. */
|
|
1249
|
+
function fromProject(projectRoot: string, path: string): string {
|
|
1250
|
+
return relative(projectRoot, path).split(sep).join("/");
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/** What {@link choudoufuPlanSet} planned. */
|
|
1254
|
+
export interface ChoudoufuPlanSetResult extends ChoudoufuPlanSet {
|
|
1255
|
+
/** The set plan document, written as choudoufu printed it. `live-wave-apply -plan-set` reads this file. */
|
|
1256
|
+
planSetFile: string;
|
|
1257
|
+
/** The root's path as the document names it. */
|
|
1258
|
+
root: string;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/**
|
|
1262
|
+
* Plan one live choudoufu root as a one-root set: `live-plan-set -json` from
|
|
1263
|
+
* the project root (#3459). The document goes to
|
|
1264
|
+
* `<CHOUDOUFU_WAVES_DIR>/<root>/plan-set.json`, the file a later
|
|
1265
|
+
* `live-wave-apply` hands back to choudoufu with the set digest.
|
|
1266
|
+
*/
|
|
1267
|
+
export async function choudoufuPlanSet(args: TerraformRootArgs, signal?: AbortSignal): Promise<ChoudoufuPlanSetResult> {
|
|
1268
|
+
const resolved = await resolveRoot(args, signal);
|
|
1269
|
+
const { binary, root, dir, projectRoot } = resolved;
|
|
1270
|
+
if (binary !== "choudoufu") throw new Error(`choudoufuPlanSet: root "${args.root}" runs ${binary}, not choudoufu`);
|
|
1271
|
+
await ensureChoudoufuWavesVersion(binary, signal);
|
|
1272
|
+
const rootPath = choudoufuSetRootPath(projectRoot, dir);
|
|
1273
|
+
if (rootPath === undefined) throw new Error(`choudoufuPlanSet: root "${args.root}" (${dir}) is not inside ${projectRoot}`);
|
|
1274
|
+
const wavesDir = choudoufuWavesDir(projectRoot, args.root);
|
|
1275
|
+
mkdirSync(wavesDir, { recursive: true });
|
|
1276
|
+
const cmd = choudoufuPlanSetCommand({ binary, root: rootPath, outDir: fromProject(projectRoot, join(wavesDir, "out")) });
|
|
1277
|
+
|
|
1278
|
+
let stdout: string;
|
|
1279
|
+
try {
|
|
1280
|
+
const out = await run(cmd, projectRoot, terraformEnvironment(root), signal);
|
|
1281
|
+
report("", out.stderr);
|
|
1282
|
+
stdout = out.stdout;
|
|
1283
|
+
} catch (err) {
|
|
1284
|
+
// 2 is "planned, with changes" and 4 is "a root failed", which the
|
|
1285
|
+
// document itself explains. Anything else is the command not running.
|
|
1286
|
+
const failure = err as ExecFailure;
|
|
1287
|
+
if (failure.code !== 2 && failure.code !== 4) throw err;
|
|
1288
|
+
report("", failure.stderr ?? "");
|
|
1289
|
+
stdout = failure.stdout ?? "";
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
const parsed = parseChoudoufuPlanSet(stdout, { member: args.root, root: rootPath });
|
|
1293
|
+
const planSetFile = join(wavesDir, "plan-set.json");
|
|
1294
|
+
writeFileSync(planSetFile, stdout);
|
|
1295
|
+
return { ...parsed, planSetFile, root: rootPath };
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* What a choudoufu root keeps in the fan-out's attempt record (#3459):
|
|
1300
|
+
* choudoufu's resume file, under the set digest it was written for.
|
|
1301
|
+
*/
|
|
1302
|
+
export interface ChoudoufuCarriedResume {
|
|
1303
|
+
kind: "choudoufu-wave-resume";
|
|
1304
|
+
setDigest: string;
|
|
1305
|
+
resume: unknown;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* The resume file to hand choudoufu for `setDigest`, from what an earlier
|
|
1310
|
+
* attempt carried, or `undefined`. choudoufu refuses a resume file written
|
|
1311
|
+
* for another digest, and a re-planned root with a moved plan has another
|
|
1312
|
+
* digest, so only a file for this same set comes back.
|
|
1313
|
+
*/
|
|
1314
|
+
export function carriedChoudoufuResume(carried: unknown, setDigest: string): unknown {
|
|
1315
|
+
if (!isObjectValue(carried) || carried.kind !== "choudoufu-wave-resume") return undefined;
|
|
1316
|
+
if (carried.setDigest !== setDigest || !isObjectValue(carried.resume)) return undefined;
|
|
1317
|
+
return carried.resume.set_digest === setDigest ? carried.resume : undefined;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
export interface ChoudoufuWaveApplyArgs extends TerraformRootArgs {
|
|
1321
|
+
/** {@link ChoudoufuPlanSetResult.planSetFile}: the approved document. */
|
|
1322
|
+
planSetFile: string;
|
|
1323
|
+
/** {@link ChoudoufuPlanSetResult.setDigest}: choudoufu's digest of that document. */
|
|
1324
|
+
setDigest: string;
|
|
1325
|
+
/** What the root carried from an earlier attempt (`DeployContext.carried[root]`). */
|
|
1326
|
+
carried?: unknown;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
export interface ChoudoufuWaveApplyResult {
|
|
1330
|
+
/** `live-wave-apply`'s exit status. See {@link CHOUDOUFU_WAVE_EXIT}. */
|
|
1331
|
+
exitCode: number;
|
|
1332
|
+
/** Exit 0: the root landed. */
|
|
1333
|
+
landed: boolean;
|
|
1334
|
+
/** `-json`'s result document, when it printed one. */
|
|
1335
|
+
result?: unknown;
|
|
1336
|
+
/** choudoufu's resume file after the run, to carry. Absent when choudoufu wrote none. */
|
|
1337
|
+
carry?: ChoudoufuCarriedResume;
|
|
1338
|
+
/** One line for a person: what happened, in choudoufu's words where it gave some. */
|
|
1339
|
+
message: string;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
/** One line for each of `live-wave-apply`'s exit statuses, with choudoufu's own error when it gave one. */
|
|
1343
|
+
export function describeChoudoufuWaveExit(exitCode: number, result: unknown, stderr: string): string {
|
|
1344
|
+
const error = isObjectValue(result) && typeof result.error === "string" && result.error ? result.error : "";
|
|
1345
|
+
const moved =
|
|
1346
|
+
isObjectValue(result) && Array.isArray(result.moved)
|
|
1347
|
+
? result.moved
|
|
1348
|
+
.filter(isObjectValue)
|
|
1349
|
+
.map((m) => `${String(m.root)} moved: approved ${String(m.approved_digest)}, now ${String(m.fresh_digest)}`)
|
|
1350
|
+
: [];
|
|
1351
|
+
const detail = error || moved.join("; ") || stderr.trim().split("\n").find((l) => l.trim() !== "")?.trim() || "";
|
|
1352
|
+
const suffix = detail ? ` (${detail})` : "";
|
|
1353
|
+
switch (exitCode) {
|
|
1354
|
+
case CHOUDOUFU_WAVE_EXIT.landed:
|
|
1355
|
+
return "landed";
|
|
1356
|
+
case CHOUDOUFU_WAVE_EXIT.setMoved:
|
|
1357
|
+
return `choudoufu refused the approved set: the root's plan moved since it was approved, and nothing was applied${suffix}`;
|
|
1358
|
+
case CHOUDOUFU_WAVE_EXIT.rootFailed:
|
|
1359
|
+
return `choudoufu could not land the root; its resume file records why${suffix}`;
|
|
1360
|
+
default:
|
|
1361
|
+
return `choudoufu live-wave-apply could not run (exit ${exitCode})${suffix}`;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* Apply one live choudoufu root through `live-wave-apply` (#3459), with the
|
|
1367
|
+
* set plan document and set digest {@link choudoufuPlanSet} produced. When
|
|
1368
|
+
* the root carried a resume file for this same digest from an earlier
|
|
1369
|
+
* attempt, it is written back first, so choudoufu sees what it already
|
|
1370
|
+
* recorded. Its resume file after the run comes back as `carry`, landed or
|
|
1371
|
+
* not.
|
|
1372
|
+
*
|
|
1373
|
+
* Never throws for a choudoufu answer: exit 3 (the set moved) and exit 4 (the
|
|
1374
|
+
* root failed) come back with `landed: false`, and so does exit 1. An abort
|
|
1375
|
+
* or a spawn failure propagates.
|
|
1376
|
+
*/
|
|
1377
|
+
export async function choudoufuWaveApply(args: ChoudoufuWaveApplyArgs, signal?: AbortSignal): Promise<ChoudoufuWaveApplyResult> {
|
|
1378
|
+
const resolved = await resolveRoot(args, signal);
|
|
1379
|
+
const { binary, root, projectRoot } = resolved;
|
|
1380
|
+
if (binary !== "choudoufu") throw new Error(`choudoufuWaveApply: root "${args.root}" runs ${binary}, not choudoufu`);
|
|
1381
|
+
await ensureChoudoufuWavesVersion(binary, signal);
|
|
1382
|
+
const wavesDir = choudoufuWavesDir(projectRoot, args.root);
|
|
1383
|
+
mkdirSync(wavesDir, { recursive: true });
|
|
1384
|
+
// One file per digest: choudoufu refuses a resume file written for
|
|
1385
|
+
// another, and a file left by an earlier set must not block this one.
|
|
1386
|
+
const resumeFile = join(wavesDir, `resume-${args.setDigest.replace(/^sha256:/, "").slice(0, 16)}.json`);
|
|
1387
|
+
const carried = carriedChoudoufuResume(args.carried, args.setDigest);
|
|
1388
|
+
if (carried !== undefined) writeFileSync(resumeFile, JSON.stringify(carried, null, 2) + "\n");
|
|
1389
|
+
|
|
1390
|
+
const cmd = choudoufuWaveApplyCommand({
|
|
1391
|
+
binary,
|
|
1392
|
+
planSet: fromProject(projectRoot, args.planSetFile),
|
|
1393
|
+
digest: args.setDigest,
|
|
1394
|
+
resume: fromProject(projectRoot, resumeFile),
|
|
1395
|
+
outDir: fromProject(projectRoot, join(wavesDir, "out")),
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
let exitCode = 0;
|
|
1399
|
+
let stdout = "";
|
|
1400
|
+
let stderr = "";
|
|
1401
|
+
try {
|
|
1402
|
+
const out = await run(cmd, projectRoot, terraformEnvironment(root), signal);
|
|
1403
|
+
stdout = out.stdout;
|
|
1404
|
+
stderr = out.stderr;
|
|
1405
|
+
} catch (err) {
|
|
1406
|
+
const failure = err as ExecFailure;
|
|
1407
|
+
if (typeof failure.code !== "number") throw err;
|
|
1408
|
+
exitCode = failure.code;
|
|
1409
|
+
stdout = failure.stdout ?? "";
|
|
1410
|
+
stderr = failure.stderr ?? "";
|
|
1411
|
+
}
|
|
1412
|
+
report(stdout, stderr);
|
|
1413
|
+
|
|
1414
|
+
let result: unknown;
|
|
1415
|
+
try {
|
|
1416
|
+
result = stdout.trim() ? JSON.parse(stdout) : undefined;
|
|
1417
|
+
} catch {
|
|
1418
|
+
result = undefined;
|
|
1419
|
+
}
|
|
1420
|
+
let carry: ChoudoufuCarriedResume | undefined;
|
|
1421
|
+
if (existsSync(resumeFile)) {
|
|
1422
|
+
try {
|
|
1423
|
+
carry = { kind: "choudoufu-wave-resume", setDigest: args.setDigest, resume: JSON.parse(readFileSync(resumeFile, "utf8")) };
|
|
1424
|
+
} catch {
|
|
1425
|
+
carry = undefined;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
return {
|
|
1429
|
+
exitCode,
|
|
1430
|
+
landed: exitCode === CHOUDOUFU_WAVE_EXIT.landed,
|
|
1431
|
+
...(result !== undefined ? { result } : {}),
|
|
1432
|
+
...(carry ? { carry } : {}),
|
|
1433
|
+
message: describeChoudoufuWaveExit(exitCode, result, stderr),
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1032
1437
|
/**
|
|
1033
1438
|
* `terraform show` over current state, or over a saved plan when `planFile` is
|
|
1034
1439
|
* given. Returns the parsed `-json` output and the `-no-color` render, plus
|