@intentius/chant 0.124.32 → 0.124.34
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/ci-jobs.d.ts +4 -0
- package/dist/ci-jobs.d.ts.map +1 -1
- package/dist/ci-jobs.js +9 -2
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +18 -3
- package/dist/cli/handlers/lifecycle-health.d.ts +16 -0
- package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-health.js +150 -0
- package/dist/cli/handlers/lifecycle.d.ts +26 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.js +1 -1
- package/dist/cli/handlers/pr.d.ts +2 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +124 -2
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +277 -74
- package/dist/cli/handlers/release.d.ts +16 -1
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +83 -11
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +99 -22
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +30 -1
- package/dist/cli/registry.d.ts +21 -5
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/deploy-inputs.d.ts +91 -0
- package/dist/components/deploy-inputs.d.ts.map +1 -0
- package/dist/components/deploy-inputs.js +184 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +9 -0
- package/dist/components/gate-plan.d.ts +8 -0
- package/dist/components/gate-plan.d.ts.map +1 -1
- package/dist/components/gate-plan.js +6 -0
- package/dist/components/pr-pipeline.d.ts +33 -10
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +42 -11
- package/dist/components/pr-run.d.ts +1 -1
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/promote-rounds.d.ts +102 -0
- package/dist/components/promote-rounds.d.ts.map +1 -0
- package/dist/components/promote-rounds.js +174 -0
- package/dist/components/release-compile.d.ts +37 -2
- package/dist/components/release-compile.d.ts.map +1 -1
- package/dist/components/release-compile.js +64 -8
- package/dist/components/release-gate.d.ts +30 -0
- package/dist/components/release-gate.d.ts.map +1 -1
- package/dist/components/release-gate.js +92 -42
- package/dist/components/release-promote.d.ts +17 -3
- package/dist/components/release-promote.d.ts.map +1 -1
- package/dist/components/release-promote.js +79 -18
- package/dist/components/verbs/bom-writer.d.ts +1 -1
- package/dist/components/verbs/bom-writer.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
- package/dist/components/wave-plan.d.ts +10 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +32 -4
- package/dist/graph-declared.d.ts +4 -0
- package/dist/graph-declared.d.ts.map +1 -1
- package/dist/graph-declared.js +11 -1
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +32 -7
- package/dist/health.d.ts +110 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +105 -0
- package/dist/health.schema.json +191 -0
- package/dist/lexicon.d.ts +27 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/merge-record.d.ts +104 -0
- package/dist/lifecycle/merge-record.d.ts.map +1 -0
- package/dist/lifecycle/merge-record.js +102 -0
- package/dist/lifecycle/publish-attachments.d.ts +8 -5
- package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
- package/dist/lifecycle/publish-attachments.js +27 -13
- package/dist/lifecycle/publish-npm.d.ts +3 -2
- package/dist/lifecycle/publish-npm.d.ts.map +1 -1
- package/dist/lifecycle/publish-npm.js +4 -3
- package/dist/lifecycle/release-at.d.ts +40 -0
- package/dist/lifecycle/release-at.d.ts.map +1 -0
- package/dist/lifecycle/release-at.js +83 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -1
- package/dist/lifecycle/release-cut.js +23 -12
- package/dist/lifecycle/release-publish.d.ts +28 -12
- package/dist/lifecycle/release-publish.d.ts.map +1 -1
- package/dist/lifecycle/release-publish.js +29 -17
- package/dist/lifecycle/release-store.d.ts +25 -2
- package/dist/lifecycle/release-store.d.ts.map +1 -1
- package/dist/lifecycle/release-store.js +40 -13
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -0
- package/dist/lint/rules/op/index.d.ts +2 -1
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +4 -2
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
- package/dist/op/activities/activity-contracts.d.ts +5 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +3 -0
- package/dist/op/activities/shell.d.ts +38 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/shell.js +89 -3
- package/dist/op/builders.d.ts +7 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +7 -0
- package/dist/op/runtime.d.ts +2 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/pr-loop.d.ts +14 -3
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +15 -5
- package/dist/pr-report-url.d.ts +2 -2
- package/dist/pr-report-url.d.ts.map +1 -1
- package/dist/runner-start.d.ts +179 -0
- package/dist/runner-start.d.ts.map +1 -0
- package/dist/runner-start.js +277 -0
- package/dist/wave-runtime.mjs +236 -229
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.js +13 -2
- package/dist/workspace/check.schema.json +88 -2
- package/dist/workspace/checks/ci-workflow.d.ts +17 -0
- package/dist/workspace/checks/ci-workflow.d.ts.map +1 -0
- package/dist/workspace/checks/ci-workflow.js +123 -0
- package/dist/workspace/checks/security.d.ts +50 -0
- package/dist/workspace/checks/security.d.ts.map +1 -0
- package/dist/workspace/checks/security.js +305 -0
- package/dist/workspace/checks.d.ts +2 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +8 -0
- package/dist/workspace/ci-builds.d.ts +163 -0
- package/dist/workspace/ci-builds.d.ts.map +1 -0
- package/dist/workspace/ci-builds.js +315 -0
- package/dist/workspace/ci-green-cli.d.ts +2 -1
- package/dist/workspace/ci-green-cli.d.ts.map +1 -1
- package/dist/workspace/ci-green-cli.js +25 -5
- package/dist/workspace/ci-green-forge.d.ts +12 -0
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green-forge.js +12 -0
- package/dist/workspace/ci-green-workflow.d.ts +55 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +128 -1
- package/dist/workspace/ci-green.d.ts +89 -4
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +310 -23
- package/dist/workspace/ci-init.d.ts +100 -0
- package/dist/workspace/ci-init.d.ts.map +1 -0
- package/dist/workspace/ci-init.js +434 -0
- package/dist/workspace/ci-last-green.schema.json +49 -0
- package/dist/workspace/ci-list.schema.json +35 -1
- package/dist/workspace/ci-run-index.d.ts +1 -1
- package/dist/workspace/ci-run-index.d.ts.map +1 -1
- package/dist/workspace/ci-run-index.schema.json +1 -1
- package/dist/workspace/ci-run.d.ts +12 -6
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +72 -16
- package/dist/workspace/ci-runner-start.d.ts +77 -0
- package/dist/workspace/ci-runner-start.d.ts.map +1 -0
- package/dist/workspace/ci-runner-start.js +185 -0
- package/dist/workspace/ci-serve.d.ts +76 -7
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +153 -19
- package/dist/workspace/ci-workflow.d.ts +91 -0
- package/dist/workspace/ci-workflow.d.ts.map +1 -0
- package/dist/workspace/ci-workflow.js +33 -0
- package/dist/workspace/declaration.d.ts +35 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +12 -2
- package/dist/workspace/declaration.schema.json +51 -0
- package/dist/workspace/init.js +2 -2
- package/dist/workspace/ls.d.ts +2 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +1 -1
- package/dist/workspace/ls.schema.json +2 -1
- package/dist/workspace/member-pipeline.d.ts +1 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -1
- package/dist/workspace/member-pipeline.js +2 -0
- package/dist/workspace/merge-record.schema.json +49 -0
- package/dist/workspace/pr-report.schema.json +3 -3
- package/dist/workspace/reason-codes.d.ts +26 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +28 -0
- package/dist/workspace/release-candidates.d.ts +129 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -0
- package/dist/workspace/release-candidates.js +233 -0
- package/dist/workspace/release-candidates.schema.json +353 -0
- package/dist/workspace/release-workflow.d.ts +31 -0
- package/dist/workspace/release-workflow.d.ts.map +1 -0
- package/dist/workspace/release-workflow.js +150 -0
- package/dist/workspace/security.d.ts +40 -0
- package/dist/workspace/security.d.ts.map +1 -0
- package/dist/workspace/security.js +99 -0
- package/package.json +8 -1
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
- package/src/ci-jobs.ts +11 -2
- package/src/cli/handlers/build.test.ts +36 -0
- package/src/cli/handlers/build.ts +18 -3
- package/src/cli/handlers/lifecycle-health.test.ts +123 -0
- package/src/cli/handlers/lifecycle-health.ts +157 -0
- package/src/cli/handlers/lifecycle.ts +1 -1
- package/src/cli/handlers/pr-deploy-inputs.test.ts +209 -0
- package/src/cli/handlers/pr-record.test.ts +201 -0
- package/src/cli/handlers/pr.test.ts +22 -0
- package/src/cli/handlers/pr.ts +127 -4
- package/src/cli/handlers/promote.test.ts +17 -0
- package/src/cli/handlers/promote.ts +296 -84
- package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
- package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
- package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
- package/src/cli/handlers/release.e2e.test.ts +19 -28
- package/src/cli/handlers/release.ts +81 -11
- package/src/cli/main.ts +99 -22
- package/src/cli/parse-args.ts +22 -1
- package/src/cli/registry.ts +21 -5
- package/src/components/deploy-inputs.test.ts +108 -0
- package/src/components/deploy-inputs.ts +225 -0
- package/src/components/driver.ts +11 -0
- package/src/components/gate-plan.ts +9 -0
- package/src/components/pr-pipeline.ts +56 -15
- package/src/components/pr-run.ts +1 -1
- package/src/components/promote-rounds.test.ts +220 -0
- package/src/components/promote-rounds.ts +232 -0
- package/src/components/release-compile.test.ts +34 -0
- package/src/components/release-compile.ts +89 -8
- package/src/components/release-gate.test.ts +47 -0
- package/src/components/release-gate.ts +111 -46
- package/src/components/release-promote.test.ts +55 -2
- package/src/components/release-promote.ts +93 -23
- package/src/components/verbs/bom-writer.ts +1 -1
- package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
- package/src/components/wave-plan.ts +32 -4
- package/src/graph-declared-exports.test.ts +40 -0
- package/src/graph-declared.ts +9 -1
- package/src/graph-detail.test.ts +57 -0
- package/src/graph-detail.ts +33 -7
- package/src/health.schema.json +191 -0
- package/src/health.test.ts +62 -0
- package/src/health.ts +178 -0
- package/src/lexicon.ts +41 -1
- package/src/lifecycle/merge-record.test.ts +111 -0
- package/src/lifecycle/merge-record.ts +154 -0
- package/src/lifecycle/publish-attachments.ts +25 -13
- package/src/lifecycle/publish-npm.ts +4 -3
- package/src/lifecycle/publish-targets.test.ts +34 -4
- package/src/lifecycle/release-at.test.ts +48 -0
- package/src/lifecycle/release-at.ts +100 -0
- package/src/lifecycle/release-cut.test.ts +41 -0
- package/src/lifecycle/release-cut.ts +22 -11
- package/src/lifecycle/release-publish.test.ts +43 -13
- package/src/lifecycle/release-publish.ts +38 -18
- package/src/lifecycle/release-store.ts +57 -13
- package/src/lifecycle/run-ledger.test.ts +13 -0
- package/src/lifecycle/run-ledger.ts +1 -0
- package/src/lint/rules/op/index.ts +4 -2
- package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
- package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
- package/src/op/activities/activity-contracts.ts +3 -0
- package/src/op/activities/shell-container.e2e.test.ts +67 -0
- package/src/op/activities/shell.test.ts +44 -1
- package/src/op/activities/shell.ts +110 -3
- package/src/op/builders.ts +7 -0
- package/src/op/runtime.ts +2 -0
- package/src/op/step-console.test.ts +4 -2
- package/src/pr-loop.test.ts +29 -0
- package/src/pr-loop.ts +26 -7
- package/src/pr-report-url.ts +2 -2
- package/src/runner-start-bundle.test.ts +29 -0
- package/src/runner-start.test.ts +179 -0
- package/src/runner-start.ts +329 -0
- package/src/workspace/__fixtures__/contract-repo.ts +11 -2
- package/src/workspace/check-contract.test.ts +4 -2
- package/src/workspace/check.schema.json +88 -2
- package/src/workspace/checks/ci-workflow.test.ts +150 -0
- package/src/workspace/checks/ci-workflow.ts +129 -0
- package/src/workspace/checks/security.test.ts +138 -0
- package/src/workspace/checks/security.ts +305 -0
- package/src/workspace/checks.ts +8 -0
- package/src/workspace/ci-builds.e2e.test.ts +208 -0
- package/src/workspace/ci-builds.test.ts +174 -0
- package/src/workspace/ci-builds.ts +385 -0
- package/src/workspace/ci-green-builds.test.ts +180 -0
- package/src/workspace/ci-green-cli.test.ts +54 -0
- package/src/workspace/ci-green-cli.ts +26 -5
- package/src/workspace/ci-green-forge.ts +24 -0
- package/src/workspace/ci-green-workflow.test.ts +84 -1
- package/src/workspace/ci-green-workflow.ts +139 -2
- package/src/workspace/ci-green.test.ts +5 -2
- package/src/workspace/ci-green.ts +359 -27
- package/src/workspace/ci-init.test.ts +159 -0
- package/src/workspace/ci-init.ts +445 -0
- package/src/workspace/ci-last-green.schema.json +49 -0
- package/src/workspace/ci-list.schema.json +35 -1
- package/src/workspace/ci-report-url.test.ts +6 -1
- package/src/workspace/ci-run-index.schema.json +1 -1
- package/src/workspace/ci-run-index.ts +1 -1
- package/src/workspace/ci-run.test.ts +24 -7
- package/src/workspace/ci-run.ts +78 -16
- package/src/workspace/ci-runner-start.test.ts +151 -0
- package/src/workspace/ci-runner-start.ts +193 -0
- package/src/workspace/ci-serve-builds.test.ts +86 -0
- package/src/workspace/ci-serve.test.ts +59 -0
- package/src/workspace/ci-serve.ts +177 -22
- package/src/workspace/ci-workflow.ts +71 -0
- package/src/workspace/declaration.schema.json +51 -0
- package/src/workspace/declaration.test.ts +17 -0
- package/src/workspace/declaration.ts +53 -3
- package/src/workspace/init.ts +2 -2
- package/src/workspace/ls.schema.json +2 -1
- package/src/workspace/ls.ts +3 -2
- package/src/workspace/member-pipeline.ts +2 -1
- package/src/workspace/merge-record.schema.json +49 -0
- package/src/workspace/pr-report.schema.json +3 -3
- package/src/workspace/reason-codes.test.ts +4 -0
- package/src/workspace/reason-codes.ts +28 -0
- package/src/workspace/release-candidates.schema.json +353 -0
- package/src/workspace/release-candidates.test.ts +106 -0
- package/src/workspace/release-candidates.ts +315 -0
- package/src/workspace/release-workflow.ts +167 -0
- package/src/workspace/security.test.ts +70 -0
- package/src/workspace/security.ts +118 -0
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
* (`componentPlanDigest`, ./gate-plan.ts, #2574), so a wave mixing roots and
|
|
14
14
|
* other components still has one digest that moves when any of them does.
|
|
15
15
|
*
|
|
16
|
+
* The files a step without a `plan` deploys from are bound too (#4155,
|
|
17
|
+
* ./deploy-inputs.ts). A component with no plannable step folds them into its
|
|
18
|
+
* composition digest. A component with one gets a member more,
|
|
19
|
+
* `<component>#inputs`, over its other steps' files, so a `lambda-deploy`
|
|
20
|
+
* source or a Helm chart beside a `cfn-deploy` moves the wave's digest. A step
|
|
21
|
+
* whose content chant can't name is a hole on that member, so the plan note
|
|
22
|
+
* lists it as unbound.
|
|
23
|
+
*
|
|
16
24
|
* Known limit: a step input that reads an earlier step of the same
|
|
17
25
|
* component (`@Phase.field`) has no value before the component runs, so it
|
|
18
26
|
* plans as `undefined`. Cross-component wiring (`stackOutput()`,
|
|
@@ -20,13 +28,18 @@
|
|
|
20
28
|
*/
|
|
21
29
|
import { resolveStepInput, unresolvedWiringSources } from "./driver.js";
|
|
22
30
|
import { componentPlanDigest } from "./gate-plan.js";
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
import { componentDeployInputs } from "./deploy-inputs.js";
|
|
32
|
+
import { computePlanDigest } from "../lifecycle/plan-digest.js";
|
|
33
|
+
/** A part with no entries, for a member whose planner describes no changes. `unbound` steps become its holes (#4155). */
|
|
34
|
+
function emptyPart(member, unbound = []) {
|
|
35
|
+
const holes = unbound.map((u) => ({ address: `${u.phase}/${u.kind}`, type: u.kind, reason: `unbound: ${u.reason}` }));
|
|
25
36
|
return {
|
|
26
|
-
member: { member: member.member, lexicon: "chant", planner: "chant", status: "planned", planDigest: member.planDigest, holes
|
|
37
|
+
member: { member: member.member, lexicon: "chant", planner: "chant", status: "planned", planDigest: member.planDigest, holes },
|
|
27
38
|
entries: [],
|
|
28
39
|
};
|
|
29
40
|
}
|
|
41
|
+
/** The member a planning component's other steps add (#4155): their files, under the component's name. */
|
|
42
|
+
export const inputsMemberName = (component) => `${component}#inputs`;
|
|
30
43
|
/** Every capability step in a composition, nested phases included, gates left out. */
|
|
31
44
|
export function capabilitySteps(phases) {
|
|
32
45
|
const out = [];
|
|
@@ -75,17 +88,32 @@ export async function planWaveComponent(component, registry, ctx, componentOutpu
|
|
|
75
88
|
if (planned.outputs)
|
|
76
89
|
outputs = mergePlannedOutputs(outputs, planned.outputs);
|
|
77
90
|
}
|
|
91
|
+
// #4155: the steps without a plan, which no member above covers.
|
|
92
|
+
const planless = (step) => !registry.has(step.kind) || registry.resolve(step.kind).plan === undefined;
|
|
78
93
|
if (members.length === 0) {
|
|
94
|
+
const read = componentDeployInputs(component.deploy, process.cwd());
|
|
79
95
|
const member = {
|
|
80
96
|
member: component.name,
|
|
81
97
|
planDigest: componentPlanDigest({
|
|
82
98
|
environment: ctx.env,
|
|
83
99
|
component,
|
|
84
100
|
...(ctx.vars ? { vars: ctx.vars } : {}),
|
|
101
|
+
inputs: read.inputs,
|
|
85
102
|
}),
|
|
86
103
|
};
|
|
87
104
|
members.push(member);
|
|
88
|
-
parts.push(emptyPart(member));
|
|
105
|
+
parts.push(emptyPart(member, read.unbound));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const read = componentDeployInputs(component.deploy, process.cwd(), planless);
|
|
109
|
+
if (read.inputs.length > 0 || read.unbound.length > 0) {
|
|
110
|
+
const member = {
|
|
111
|
+
member: inputsMemberName(component.name),
|
|
112
|
+
planDigest: computePlanDigest("component-inputs", { environment: ctx.env, component: component.name, inputs: read.inputs }),
|
|
113
|
+
};
|
|
114
|
+
members.push(member);
|
|
115
|
+
parts.push(emptyPart(member, read.unbound));
|
|
116
|
+
}
|
|
89
117
|
}
|
|
90
118
|
return { component: component.name, members, plans, parts, ...(outputs ? { outputs } : {}) };
|
|
91
119
|
}
|
package/dist/graph-declared.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { type GraphIR } from "./graph-ir.js";
|
|
|
10
10
|
* that live side, build each stack's `src` in isolation and qualify its node ids
|
|
11
11
|
* and edge endpoints the same way. Stacks are merged into one graph.
|
|
12
12
|
*
|
|
13
|
+
* Each stack's exports and imports come along with their `node` qualified the
|
|
14
|
+
* same way (#4202), so a workspace viewer can still match an import in another
|
|
15
|
+
* member to an export here once an environment is picked.
|
|
16
|
+
*
|
|
13
17
|
* A stack without `src` contributes nothing here — it has no declared source to
|
|
14
18
|
* scope to (its live nodes still show as foreign in the overlay).
|
|
15
19
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-declared.d.ts","sourceRoot":"","sources":["../src/graph-declared.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,OAAO,EAAe,MAAM,YAAY,CAAC;AAErE
|
|
1
|
+
{"version":3,"file":"graph-declared.d.ts","sourceRoot":"","sources":["../src/graph-declared.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,OAAO,EAAe,MAAM,YAAY,CAAC;AAErE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CA2BlB"}
|
package/dist/graph-declared.js
CHANGED
|
@@ -12,6 +12,10 @@ import { buildGraphIr } from "./graph-ir.js";
|
|
|
12
12
|
* that live side, build each stack's `src` in isolation and qualify its node ids
|
|
13
13
|
* and edge endpoints the same way. Stacks are merged into one graph.
|
|
14
14
|
*
|
|
15
|
+
* Each stack's exports and imports come along with their `node` qualified the
|
|
16
|
+
* same way (#4202), so a workspace viewer can still match an import in another
|
|
17
|
+
* member to an export here once an environment is picked.
|
|
18
|
+
*
|
|
15
19
|
* A stack without `src` contributes nothing here — it has no declared source to
|
|
16
20
|
* scope to (its live nodes still show as foreign in the overlay).
|
|
17
21
|
*/
|
|
@@ -19,6 +23,8 @@ export async function buildDeclaredPerStack(stacks, projectPath) {
|
|
|
19
23
|
var _a;
|
|
20
24
|
const nodes = [];
|
|
21
25
|
const edges = [];
|
|
26
|
+
const exports = [];
|
|
27
|
+
const imports = [];
|
|
22
28
|
// Which nodes belong to which stack (#1433). This is not derived or guessed:
|
|
23
29
|
// the stack is declared in config and every node here is being renamed with
|
|
24
30
|
// its name on the line below. The membership was always known and thrown
|
|
@@ -37,9 +43,13 @@ export async function buildDeclaredPerStack(stacks, projectPath) {
|
|
|
37
43
|
}
|
|
38
44
|
for (const e of g.edges)
|
|
39
45
|
edges.push({ ...e, from: q(e.from), to: q(e.to) });
|
|
46
|
+
for (const e of g.exports ?? [])
|
|
47
|
+
exports.push({ ...e, ...(e.node ? { node: q(e.node) } : {}) });
|
|
48
|
+
for (const i of g.imports ?? [])
|
|
49
|
+
imports.push({ ...i, node: q(i.node) });
|
|
40
50
|
}
|
|
41
51
|
for (const ids of Object.values(byStack))
|
|
42
52
|
ids.sort();
|
|
43
53
|
const groups = Object.keys(byStack).length ? { byStack } : {};
|
|
44
|
-
return { nodes, edges, groups };
|
|
54
|
+
return { nodes, edges, groups, ...(exports.length ? { exports } : {}), ...(imports.length ? { imports } : {}) };
|
|
45
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-detail.d.ts","sourceRoot":"","sources":["../src/graph-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,YAAY,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAExC,eAAO,MAAM,MAAM;aACjB,MAAM,EAAE,CAAC;aACT,UAAU,EAAE,CAAC;aACb,WAAW,EAAE,CAAC;aACd,UAAU,EAAE,CAAC;CACL,CAAC;AAEX,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAYpE;
|
|
1
|
+
{"version":3,"file":"graph-detail.d.ts","sourceRoot":"","sources":["../src/graph-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,YAAY,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAExC,eAAO,MAAM,MAAM;aACjB,MAAM,EAAE,CAAC;aACT,UAAU,EAAE,CAAC;aACb,WAAW,EAAE,CAAC;aACd,UAAU,EAAE,CAAC;CACL,CAAC;AAEX,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAYpE;AAyND;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAYtF"}
|
package/dist/graph-detail.js
CHANGED
|
@@ -90,27 +90,45 @@ function toDeclarables(ir) {
|
|
|
90
90
|
/** T1 — collapse each composite instance to one node; internal edges disappear.
|
|
91
91
|
* Topology view: surviving plain nodes keep only overlay paint, not properties. */
|
|
92
92
|
function toComposites(ir) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
// A composite instance is its export name plus the composite that made it:
|
|
94
|
+
// an AWS FargateAlb and a GCP CloudRunServiceComposite both exported as
|
|
95
|
+
// `web` are two instances (#4178). One composite whose members span
|
|
96
|
+
// lexicons stays one instance.
|
|
97
|
+
const instanceKey = (n) => `${n.compositeInstance}\0${n.compositeParent ?? ""}`;
|
|
96
98
|
const instances = new Map();
|
|
97
99
|
const plain = [];
|
|
98
100
|
for (const n of ir.nodes) {
|
|
99
101
|
if (n.compositeInstance) {
|
|
100
|
-
const
|
|
102
|
+
const key = instanceKey(n);
|
|
103
|
+
const arr = instances.get(key) ?? [];
|
|
101
104
|
arr.push(n);
|
|
102
|
-
instances.set(
|
|
105
|
+
instances.set(key, arr);
|
|
103
106
|
}
|
|
104
107
|
else {
|
|
105
108
|
plain.push({ ...n, attrs: paintAttrs(n.attrs) });
|
|
106
109
|
}
|
|
107
110
|
}
|
|
111
|
+
// The collapsed id is the instance name, or `<instance>@<composite>` when
|
|
112
|
+
// two composites share the name.
|
|
113
|
+
const sharing = new Map();
|
|
114
|
+
for (const members of instances.values()) {
|
|
115
|
+
const inst = members[0].compositeInstance;
|
|
116
|
+
sharing.set(inst, (sharing.get(inst) ?? 0) + 1);
|
|
117
|
+
}
|
|
118
|
+
const collapsedId = new Map();
|
|
119
|
+
for (const [key, members] of instances) {
|
|
120
|
+
const { compositeInstance: inst, compositeParent: parent } = members[0];
|
|
121
|
+
collapsedId.set(key, sharing.get(inst) > 1 && parent ? `${inst}@${parent}` : inst);
|
|
122
|
+
}
|
|
123
|
+
const idMap = new Map();
|
|
124
|
+
for (const n of ir.nodes)
|
|
125
|
+
idMap.set(n.id, n.compositeInstance ? collapsedId.get(instanceKey(n)) : n.id);
|
|
108
126
|
const nodes = [...plain];
|
|
109
|
-
for (const [
|
|
127
|
+
for (const [key, members] of instances) {
|
|
110
128
|
const types = new Set(members.map((m) => m.compositeParent).filter(Boolean));
|
|
111
129
|
const lexicons = new Set(members.map((m) => m.lexicon));
|
|
112
130
|
nodes.push({
|
|
113
|
-
id:
|
|
131
|
+
id: collapsedId.get(key),
|
|
114
132
|
kind: types.size === 1 ? [...types][0] : "Composite",
|
|
115
133
|
lexicon: lexicons.size === 1 ? [...lexicons][0] : "multi",
|
|
116
134
|
attrs: { members: members.length },
|
|
@@ -163,11 +181,18 @@ function toComposites(ir) {
|
|
|
163
181
|
if (Object.keys(byPipeline).length)
|
|
164
182
|
groups.byPipeline = byPipeline;
|
|
165
183
|
}
|
|
184
|
+
// Exports (#4178) stay at this tier, each on the node that now holds its
|
|
185
|
+
// producer, so a viewer can still match another member's import to it.
|
|
186
|
+
const exports = ir.exports?.map((x) => (x.node ? { ...x, node: idMap.get(x.node) ?? x.node } : { ...x }));
|
|
166
187
|
return {
|
|
188
|
+
...(ir.version !== undefined ? { version: ir.version } : {}),
|
|
167
189
|
nodes,
|
|
168
190
|
edges: sortEdges([...seen.values()]),
|
|
169
191
|
groups,
|
|
192
|
+
...(ir.meta ? { meta: ir.meta } : {}),
|
|
193
|
+
...(exports && exports.length ? { exports } : {}),
|
|
170
194
|
...(imports && imports.length ? { imports } : {}),
|
|
195
|
+
...(ir.pipeline ? { pipeline: ir.pipeline } : {}),
|
|
171
196
|
...(dangling && dangling.length ? { dangling } : {}),
|
|
172
197
|
};
|
|
173
198
|
}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime health (#4177): whether a declared thing is up, read separately from
|
|
3
|
+
* drift.
|
|
4
|
+
*
|
|
5
|
+
* The observation family answers what is deployed (`describeResources`), what
|
|
6
|
+
* its properties are (`observeResourcesDeep`) and what it would do
|
|
7
|
+
* (`predictBehaviour`). None of them says whether a service is serving. A
|
|
8
|
+
* lexicon that can read that implements {@link HealthLexicon.observeHealth}
|
|
9
|
+
* for the types it names in `healthTypes`, and `chant lifecycle health` reports
|
|
10
|
+
* the answers in the {@link HEALTH_SCHEMA} shape.
|
|
11
|
+
*
|
|
12
|
+
* The verdicts follow #1089's rule. Every entity the caller asks about lands in
|
|
13
|
+
* exactly one place: `entities` (read, with a state), `unobserved` (the read
|
|
14
|
+
* failed, a hole with a reason) or `absent` (the provider says it is not
|
|
15
|
+
* deployed). A failed read is never `unhealthy`: `unhealthy` is something the
|
|
16
|
+
* provider said.
|
|
17
|
+
*
|
|
18
|
+
* Routing is not modelled. A consumer that wants rotation (a latency record
|
|
19
|
+
* whose health check is unhealthy is out of rotation) derives it from the
|
|
20
|
+
* graph's edges and these states.
|
|
21
|
+
*/
|
|
22
|
+
import type { UnobservedEntity, UnobservedReason } from "./observation.js";
|
|
23
|
+
/** The versioned shape `chant lifecycle health --json` prints. The JSON Schema is `./health.schema.json`. */
|
|
24
|
+
export declare const HEALTH_SCHEMA = "chant-health/v1";
|
|
25
|
+
/** The `$id` of `./health.schema.json`, which the package exports as `@intentius/chant/health.schema.json`. */
|
|
26
|
+
export declare const HEALTH_SCHEMA_ID = "https://intentius.io/chant/schemas/health/v1/health.schema.json";
|
|
27
|
+
/**
|
|
28
|
+
* `healthy` and `unhealthy` are what the provider reported. `unknown` means the
|
|
29
|
+
* read succeeded and the provider's answer does not decide either way (a
|
|
30
|
+
* deployment still rolling, a service scaled to zero, a condition pending).
|
|
31
|
+
*/
|
|
32
|
+
export type HealthState = "healthy" | "unhealthy" | "unknown";
|
|
33
|
+
export interface HealthEntry {
|
|
34
|
+
/** Entity type, e.g. `AWS::ECS::Service`. */
|
|
35
|
+
type: string;
|
|
36
|
+
state: HealthState;
|
|
37
|
+
/** One short line saying why, in the provider's terms. */
|
|
38
|
+
detail: string;
|
|
39
|
+
/** When chant read it (ISO 8601). */
|
|
40
|
+
observedAt: string;
|
|
41
|
+
/** When the provider last checked or changed the state, when it says (ISO 8601). */
|
|
42
|
+
checkedAt?: string;
|
|
43
|
+
}
|
|
44
|
+
/** What one lexicon's health read returns. */
|
|
45
|
+
export interface HealthReadResult {
|
|
46
|
+
/** Read, keyed by chant entity name, which is the graph's node id. */
|
|
47
|
+
entities: Record<string, HealthEntry>;
|
|
48
|
+
/** Could not be read. Never folded into `unhealthy`. */
|
|
49
|
+
unobserved: Record<string, UnobservedEntity>;
|
|
50
|
+
/** The provider says these are not deployed. */
|
|
51
|
+
absent: string[];
|
|
52
|
+
}
|
|
53
|
+
/** The options core passes a lexicon's health read. They mirror `observeResourcesDeep`'s. */
|
|
54
|
+
export interface HealthReadOptions {
|
|
55
|
+
environment: string;
|
|
56
|
+
buildOutput: string;
|
|
57
|
+
/** Only entities whose type is in the lexicon's `healthTypes`. */
|
|
58
|
+
entities: Map<string, {
|
|
59
|
+
entityType: string;
|
|
60
|
+
props: Record<string, unknown>;
|
|
61
|
+
}>;
|
|
62
|
+
stack?: string;
|
|
63
|
+
region?: string;
|
|
64
|
+
}
|
|
65
|
+
/** The two plugin members a lexicon implements to answer a health read. */
|
|
66
|
+
export interface HealthLexicon {
|
|
67
|
+
name: string;
|
|
68
|
+
/** Entity types {@link observeHealth} can read. Data, so core picks the entities without calling the reader. */
|
|
69
|
+
healthTypes?: readonly string[];
|
|
70
|
+
observeHealth?(options: HealthReadOptions): Promise<HealthReadResult>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The entities of one lexicon a health read applies to: those whose type the
|
|
74
|
+
* lexicon names in `healthTypes`.
|
|
75
|
+
*/
|
|
76
|
+
export declare function healthApplicable(plugin: HealthLexicon, entities: Map<string, {
|
|
77
|
+
entityType: string;
|
|
78
|
+
props: Record<string, unknown>;
|
|
79
|
+
}>): Map<string, {
|
|
80
|
+
entityType: string;
|
|
81
|
+
props: Record<string, unknown>;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Run one lexicon's health read. Never throws: a thrown reader reports every
|
|
85
|
+
* applicable entity `read-failed`. The result is made total, so an entity the
|
|
86
|
+
* reader forgot comes back `unobserved` rather than missing.
|
|
87
|
+
*/
|
|
88
|
+
export declare function observeHealthFor(plugin: HealthLexicon, options: HealthReadOptions): Promise<HealthReadResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Put every asked-about name in exactly one of the three places. A name in
|
|
91
|
+
* `entities` wins over the others, then `absent`, then `unobserved`; a name in
|
|
92
|
+
* none of them becomes `read-failed`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function totalHealth(names: string[], result: HealthReadResult, types?: Map<string, {
|
|
95
|
+
entityType: string;
|
|
96
|
+
}>): HealthReadResult;
|
|
97
|
+
/** Counts across a health read, for the summary line and `--json`. */
|
|
98
|
+
export interface HealthSummary {
|
|
99
|
+
healthy: number;
|
|
100
|
+
unhealthy: number;
|
|
101
|
+
unknown: number;
|
|
102
|
+
unobserved: number;
|
|
103
|
+
absent: number;
|
|
104
|
+
}
|
|
105
|
+
export declare function summarizeHealth(results: Iterable<HealthReadResult>): HealthSummary;
|
|
106
|
+
/** A health entry, for a reader building its result. */
|
|
107
|
+
export declare function healthEntry(type: string, state: HealthState, detail: string, observedAt: string, checkedAt?: string): HealthEntry;
|
|
108
|
+
/** A hole, for a reader building its result. */
|
|
109
|
+
export declare function healthHole(type: string, reason: UnobservedReason, detail: string): UnobservedEntity;
|
|
110
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"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"}
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime health (#4177): whether a declared thing is up, read separately from
|
|
3
|
+
* drift.
|
|
4
|
+
*
|
|
5
|
+
* The observation family answers what is deployed (`describeResources`), what
|
|
6
|
+
* its properties are (`observeResourcesDeep`) and what it would do
|
|
7
|
+
* (`predictBehaviour`). None of them says whether a service is serving. A
|
|
8
|
+
* lexicon that can read that implements {@link HealthLexicon.observeHealth}
|
|
9
|
+
* for the types it names in `healthTypes`, and `chant lifecycle health` reports
|
|
10
|
+
* the answers in the {@link HEALTH_SCHEMA} shape.
|
|
11
|
+
*
|
|
12
|
+
* The verdicts follow #1089's rule. Every entity the caller asks about lands in
|
|
13
|
+
* exactly one place: `entities` (read, with a state), `unobserved` (the read
|
|
14
|
+
* failed, a hole with a reason) or `absent` (the provider says it is not
|
|
15
|
+
* deployed). A failed read is never `unhealthy`: `unhealthy` is something the
|
|
16
|
+
* provider said.
|
|
17
|
+
*
|
|
18
|
+
* Routing is not modelled. A consumer that wants rotation (a latency record
|
|
19
|
+
* whose health check is unhealthy is out of rotation) derives it from the
|
|
20
|
+
* graph's edges and these states.
|
|
21
|
+
*/
|
|
22
|
+
import { unobservedAll } from "./observation.js";
|
|
23
|
+
/** The versioned shape `chant lifecycle health --json` prints. The JSON Schema is `./health.schema.json`. */
|
|
24
|
+
export const HEALTH_SCHEMA = "chant-health/v1";
|
|
25
|
+
/** The `$id` of `./health.schema.json`, which the package exports as `@intentius/chant/health.schema.json`. */
|
|
26
|
+
export const HEALTH_SCHEMA_ID = "https://intentius.io/chant/schemas/health/v1/health.schema.json";
|
|
27
|
+
/**
|
|
28
|
+
* The entities of one lexicon a health read applies to: those whose type the
|
|
29
|
+
* lexicon names in `healthTypes`.
|
|
30
|
+
*/
|
|
31
|
+
export function healthApplicable(plugin, entities) {
|
|
32
|
+
const types = new Set(plugin.healthTypes ?? []);
|
|
33
|
+
const out = new Map();
|
|
34
|
+
for (const [name, entity] of entities)
|
|
35
|
+
if (types.has(entity.entityType))
|
|
36
|
+
out.set(name, entity);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run one lexicon's health read. Never throws: a thrown reader reports every
|
|
41
|
+
* applicable entity `read-failed`. The result is made total, so an entity the
|
|
42
|
+
* reader forgot comes back `unobserved` rather than missing.
|
|
43
|
+
*/
|
|
44
|
+
export async function observeHealthFor(plugin, options) {
|
|
45
|
+
const names = [...options.entities.keys()];
|
|
46
|
+
if (names.length === 0)
|
|
47
|
+
return { entities: {}, unobserved: {}, absent: [] };
|
|
48
|
+
if (!plugin.observeHealth) {
|
|
49
|
+
return {
|
|
50
|
+
entities: {},
|
|
51
|
+
unobserved: unobservedAll(names, "unsupported-kind", `${plugin.name} has no health read`, options.entities),
|
|
52
|
+
absent: [],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
let result;
|
|
56
|
+
try {
|
|
57
|
+
result = await plugin.observeHealth(options);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
61
|
+
return { entities: {}, unobserved: unobservedAll(names, "read-failed", message, options.entities), absent: [] };
|
|
62
|
+
}
|
|
63
|
+
return totalHealth(names, result, options.entities);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Put every asked-about name in exactly one of the three places. A name in
|
|
67
|
+
* `entities` wins over the others, then `absent`, then `unobserved`; a name in
|
|
68
|
+
* none of them becomes `read-failed`.
|
|
69
|
+
*/
|
|
70
|
+
export function totalHealth(names, result, types) {
|
|
71
|
+
const entities = {};
|
|
72
|
+
const unobserved = {};
|
|
73
|
+
const absentSet = new Set(result.absent ?? []);
|
|
74
|
+
const absent = [];
|
|
75
|
+
for (const name of names) {
|
|
76
|
+
const entry = result.entities?.[name];
|
|
77
|
+
if (entry)
|
|
78
|
+
entities[name] = entry;
|
|
79
|
+
else if (absentSet.has(name))
|
|
80
|
+
absent.push(name);
|
|
81
|
+
else if (result.unobserved?.[name])
|
|
82
|
+
unobserved[name] = result.unobserved[name];
|
|
83
|
+
else
|
|
84
|
+
Object.assign(unobserved, unobservedAll([name], "read-failed", "the health read returned no answer for this entity", types));
|
|
85
|
+
}
|
|
86
|
+
return { entities, unobserved, absent };
|
|
87
|
+
}
|
|
88
|
+
export function summarizeHealth(results) {
|
|
89
|
+
const summary = { healthy: 0, unhealthy: 0, unknown: 0, unobserved: 0, absent: 0 };
|
|
90
|
+
for (const r of results) {
|
|
91
|
+
for (const entry of Object.values(r.entities))
|
|
92
|
+
summary[entry.state]++;
|
|
93
|
+
summary.unobserved += Object.keys(r.unobserved).length;
|
|
94
|
+
summary.absent += r.absent.length;
|
|
95
|
+
}
|
|
96
|
+
return summary;
|
|
97
|
+
}
|
|
98
|
+
/** A health entry, for a reader building its result. */
|
|
99
|
+
export function healthEntry(type, state, detail, observedAt, checkedAt) {
|
|
100
|
+
return { type, state, detail, observedAt, ...(checkedAt ? { checkedAt } : {}) };
|
|
101
|
+
}
|
|
102
|
+
/** A hole, for a reader building its result. */
|
|
103
|
+
export function healthHole(type, reason, detail) {
|
|
104
|
+
return { type, reason, detail };
|
|
105
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/health/v1/health.schema.json",
|
|
4
|
+
"title": "chant-health/v1",
|
|
5
|
+
"description": "What `chant lifecycle health <env> --json` prints (#4177): whether each declared resource that has a health read is up, read separately from drift. Every entity a read applies to lands in exactly one of `entities` (read, with a state), `unobserved` (the read failed, never folded into unhealthy) or `absent` (the provider says it is not deployed). Entity names are the graph's node ids. A single-stack project puts `lexicons` at the top level; a multi-stack one nests them under `stacks`. Written by the first chant release after 0.124.32. Readers ignore fields they do not know; a field is only ever added within a version.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"schema",
|
|
9
|
+
"chantVersion",
|
|
10
|
+
"environment",
|
|
11
|
+
"observedAt",
|
|
12
|
+
"summary"
|
|
13
|
+
],
|
|
14
|
+
"properties": {
|
|
15
|
+
"schema": {
|
|
16
|
+
"const": "chant-health/v1"
|
|
17
|
+
},
|
|
18
|
+
"chantVersion": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "The chant that ran the read."
|
|
21
|
+
},
|
|
22
|
+
"environment": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "The environment named on the command line."
|
|
25
|
+
},
|
|
26
|
+
"observedAt": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "When the command started reading, ISO 8601 UTC."
|
|
29
|
+
},
|
|
30
|
+
"summary": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"required": [
|
|
33
|
+
"healthy",
|
|
34
|
+
"unhealthy",
|
|
35
|
+
"unknown",
|
|
36
|
+
"unobserved",
|
|
37
|
+
"absent"
|
|
38
|
+
],
|
|
39
|
+
"description": "Counts over every lexicon and stack.",
|
|
40
|
+
"properties": {
|
|
41
|
+
"healthy": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"minimum": 0
|
|
44
|
+
},
|
|
45
|
+
"unhealthy": {
|
|
46
|
+
"type": "integer",
|
|
47
|
+
"minimum": 0
|
|
48
|
+
},
|
|
49
|
+
"unknown": {
|
|
50
|
+
"type": "integer",
|
|
51
|
+
"minimum": 0
|
|
52
|
+
},
|
|
53
|
+
"unobserved": {
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"minimum": 0
|
|
56
|
+
},
|
|
57
|
+
"absent": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"minimum": 0
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"oneOf": [
|
|
65
|
+
{
|
|
66
|
+
"required": [
|
|
67
|
+
"lexicons"
|
|
68
|
+
],
|
|
69
|
+
"properties": {
|
|
70
|
+
"lexicons": {
|
|
71
|
+
"$ref": "#/$defs/byLexicon"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"required": [
|
|
77
|
+
"stacks"
|
|
78
|
+
],
|
|
79
|
+
"properties": {
|
|
80
|
+
"stacks": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"description": "Per stack name, the same per-lexicon results.",
|
|
83
|
+
"additionalProperties": {
|
|
84
|
+
"$ref": "#/$defs/byLexicon"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"$defs": {
|
|
91
|
+
"byLexicon": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"description": "Per lexicon name, that lexicon's read. A lexicon with no applicable entity is left out.",
|
|
94
|
+
"additionalProperties": {
|
|
95
|
+
"$ref": "#/$defs/read"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"read": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"required": [
|
|
101
|
+
"entities",
|
|
102
|
+
"unobserved",
|
|
103
|
+
"absent"
|
|
104
|
+
],
|
|
105
|
+
"properties": {
|
|
106
|
+
"entities": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": {
|
|
109
|
+
"$ref": "#/$defs/entry"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"unobserved": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"additionalProperties": {
|
|
115
|
+
"$ref": "#/$defs/hole"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"absent": {
|
|
119
|
+
"type": "array",
|
|
120
|
+
"items": {
|
|
121
|
+
"type": "string"
|
|
122
|
+
},
|
|
123
|
+
"description": "Entity names the provider says are not deployed."
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"entry": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"required": [
|
|
130
|
+
"type",
|
|
131
|
+
"state",
|
|
132
|
+
"detail",
|
|
133
|
+
"observedAt"
|
|
134
|
+
],
|
|
135
|
+
"properties": {
|
|
136
|
+
"type": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "Entity type, such as AWS::ECS::Service."
|
|
139
|
+
},
|
|
140
|
+
"state": {
|
|
141
|
+
"enum": [
|
|
142
|
+
"healthy",
|
|
143
|
+
"unhealthy",
|
|
144
|
+
"unknown"
|
|
145
|
+
],
|
|
146
|
+
"description": "healthy and unhealthy are what the provider reported. unknown means the read succeeded and the answer decides neither way: a rollout in progress, a service scaled to zero, a condition pending."
|
|
147
|
+
},
|
|
148
|
+
"detail": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"description": "One short line saying why, in the provider's terms."
|
|
151
|
+
},
|
|
152
|
+
"observedAt": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"description": "When chant read it, ISO 8601."
|
|
155
|
+
},
|
|
156
|
+
"checkedAt": {
|
|
157
|
+
"type": "string",
|
|
158
|
+
"description": "When the provider last checked or changed the state, when it says, ISO 8601."
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"hole": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"required": [
|
|
165
|
+
"reason"
|
|
166
|
+
],
|
|
167
|
+
"description": "A read that failed. Never counted as unhealthy.",
|
|
168
|
+
"properties": {
|
|
169
|
+
"type": {
|
|
170
|
+
"type": "string"
|
|
171
|
+
},
|
|
172
|
+
"reason": {
|
|
173
|
+
"enum": [
|
|
174
|
+
"read-failed",
|
|
175
|
+
"no-credentials",
|
|
176
|
+
"no-binding",
|
|
177
|
+
"unsupported-kind",
|
|
178
|
+
"filtered"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
"detail": {
|
|
182
|
+
"type": "string"
|
|
183
|
+
},
|
|
184
|
+
"queried": {
|
|
185
|
+
"type": "string",
|
|
186
|
+
"description": "The address the read was issued against, when the lexicon reports it."
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
package/dist/lexicon.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export type { CommandGroup, CommandGroupCommand, CommandGroupContext } from "./c
|
|
|
41
41
|
export type { ReferenceCatalog, IdentityRule, RefRule } from "./graph-refs.js";
|
|
42
42
|
export type { IREdge } from "./graph-ir.js";
|
|
43
43
|
export type { DescribeResourcesResult, ObservationResult, NormalizedObservation, UnobservedEntity, UnobservedReason, } from "./observation.js";
|
|
44
|
+
export type { HealthEntry, HealthReadOptions, HealthReadResult, HealthState, } from "./health.js";
|
|
44
45
|
export type { DescribeIdentityOptions, DescribeIdentityResult, ResolvedIdentity, UnresolvedIdentity, IdentityRow, IdentityStatus, } from "./identity.js";
|
|
45
46
|
export type { Disruption, DisruptionQuery, DisruptionVerdict, DisruptionClassifier, } from "./lifecycle/disruption.js";
|
|
46
47
|
export type { DeepObservationResult, DeepResourceObservation, NormalizedDeepObservation, DeepNormalizationHooks, DeepNode, DeepArrayElement, DeepSide, } from "./deep-observation.js";
|
|
@@ -589,6 +590,15 @@ export type OpTrigger = {
|
|
|
589
590
|
} | {
|
|
590
591
|
kind: "push";
|
|
591
592
|
branches?: string[];
|
|
593
|
+
/**
|
|
594
|
+
* Which pushes run the Op (#4169), for an Op a `ci.green` phase names
|
|
595
|
+
* with `build` and the tick reads from chant runs. `every`: each
|
|
596
|
+
* commit, in a run of its own that no later push cancels. `newest`:
|
|
597
|
+
* one run at a time, the newest push waiting and the ones between
|
|
598
|
+
* dropped, plus a run at each `ci/build/<sha>` tag the tick or `ci run
|
|
599
|
+
* --at` pushes. Absent: one run at a time per Op, as before.
|
|
600
|
+
*/
|
|
601
|
+
build?: "every" | "newest";
|
|
592
602
|
};
|
|
593
603
|
/**
|
|
594
604
|
* One step a generated Op job runs between the checkout and the
|
|
@@ -1617,6 +1627,23 @@ export interface LexiconPlugin {
|
|
|
1617
1627
|
/** Restrict to chant-owned resources (#119). A lexicon with no marker channel on this path says so. */
|
|
1618
1628
|
owned?: boolean;
|
|
1619
1629
|
}): Promise<DeepObservationResult>;
|
|
1630
|
+
/**
|
|
1631
|
+
* Entity types {@link observeHealth} reads (#4177). Data, not a method, so
|
|
1632
|
+
* core picks the entities a health read applies to without calling it.
|
|
1633
|
+
*/
|
|
1634
|
+
healthTypes?: readonly string[];
|
|
1635
|
+
/**
|
|
1636
|
+
* Whether each declared entity of a {@link healthTypes} type is up (#4177),
|
|
1637
|
+
* read separately from drift: a service's running count, a health check's
|
|
1638
|
+
* checkers, a revision's running state, a Ready condition.
|
|
1639
|
+
*
|
|
1640
|
+
* Every entity in `options.entities` lands in exactly one of `entities`,
|
|
1641
|
+
* `unobserved` or `absent`. A read that failed is `unobserved` with a reason,
|
|
1642
|
+
* never `unhealthy`: `unhealthy` is something the provider said. Throwing is
|
|
1643
|
+
* the whole-lexicon failure, and core reports every entity `read-failed`.
|
|
1644
|
+
* Endpoint overrides apply as on the other reads, so an emulator answers.
|
|
1645
|
+
*/
|
|
1646
|
+
observeHealth?(options: import("./health.js").HealthReadOptions): Promise<import("./health.js").HealthReadResult>;
|
|
1620
1647
|
/**
|
|
1621
1648
|
* This lexicon's noise rules for deep observation (#1014): which fields are
|
|
1622
1649
|
* read-only / server-populated / controller-managed / provider-defaulted, and
|