@intentius/chant-lexicon-fly 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/describe-resources.d.ts +2 -2
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/package.json +2 -2
- package/src/describe-resources.test.ts +87 -14
- package/src/describe-resources.ts +0 -0
- package/src/op/activities/describe-resources.integration.test.ts +6 -6
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* real-Fly target flyApply writes. Secrets are apply-only (D7): flaps returns
|
|
27
27
|
* only a digest, so they never enter a diff and are excluded here.
|
|
28
28
|
*/
|
|
29
|
-
import type { ResourceMetadata } from "@intentius/chant/lexicon";
|
|
29
|
+
import type { ObservationResult, ResourceMetadata } from "@intentius/chant/lexicon";
|
|
30
30
|
import { type ChangeSet } from "@intentius/chant/lifecycle/change-set";
|
|
31
31
|
import { type FlyHttp } from "./op/activities/fly-apply.js";
|
|
32
32
|
export interface DescribeResourcesOptions {
|
|
@@ -51,7 +51,7 @@ export interface DescribeResourcesOptions {
|
|
|
51
51
|
* `http` is injectable for tests; the default reuses the applier's fetch client
|
|
52
52
|
* (bearer token from FLY_API_TOKEN).
|
|
53
53
|
*/
|
|
54
|
-
export declare function describeResources(options: DescribeResourcesOptions, http?: FlyHttp, signal?: AbortSignal): Promise<
|
|
54
|
+
export declare function describeResources(options: DescribeResourcesOptions, http?: FlyHttp, signal?: AbortSignal): Promise<ObservationResult>;
|
|
55
55
|
/**
|
|
56
56
|
* Read-only plan (#767 §4): a `flyApply` dry-run. Reads live state via
|
|
57
57
|
* {@link describeResources}, promotes it to core's typed change set, then
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAoB,MAAM,0BAA0B,CAAC;AAEtG,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAqBL,KAAK,OAAO,EAIb,MAAM,2BAA2B,CAAC;AAcnC,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAeD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,EACjC,IAAI,GAAE,OAA0B,EAChC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,iBAAiB,CAAC,CA4R5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,wBAAwB,GAAG;IAClC,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACjD,EACD,IAAI,GAAE,OAA0B,EAChC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCrD"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "86254139efb10326ce0e8a7b6b9ed24c0102d04cbcfe76d34a7f240f6ab8cd90",
|
|
5
5
|
"meta.json": "e46e65ba7544fafc6dbb3fd48b841904b5ae6f7cb4d517a940ed68b01626c097",
|
|
6
6
|
"types/index.d.ts": "07f5d04d0d3831cae053b1f0f5dd661c58e9708f45067a0fc85dd94079ac144b"
|
|
7
7
|
},
|
|
8
|
-
"composite": "
|
|
8
|
+
"composite": "ae3129117c419a0b312b406775d02e8e5ea6fe76df8f11df75dbe2d74c2325a4"
|
|
9
9
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-fly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"typescript": "^5.9.3"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@intentius/chant": "^0.
|
|
60
|
+
"@intentius/chant": "^0.29.0",
|
|
61
61
|
"typescript": "^5.9.3"
|
|
62
62
|
},
|
|
63
63
|
"description": "Google Cloud lexicon for chant — declarative IaC in TypeScript",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { describeObservationConformance } from "@intentius/chant-test-utils";
|
|
2
3
|
import { describeResources, flyPlan } from "./describe-resources";
|
|
3
4
|
import type { FlyHttp } from "./op/activities/fly-apply";
|
|
4
5
|
|
|
@@ -72,21 +73,21 @@ describe("describeResources: live machines → ResourceMetadata verdicts", () =>
|
|
|
72
73
|
);
|
|
73
74
|
|
|
74
75
|
// Declared machine keyed by its entity name; orphan keyed by its live name.
|
|
75
|
-
expect(res.web.type).toBe("Fly::Machines::Machine");
|
|
76
|
-
expect(res.web.ownership).toBe("owned");
|
|
77
|
-
expect(res.web.physicalId).toBe("m-web");
|
|
78
|
-
expect(res.web.status).toBe("started");
|
|
79
|
-
expect((res.web.attributes as { config?: unknown }).config).toEqual({
|
|
76
|
+
expect(res.resources.web.type).toBe("Fly::Machines::Machine");
|
|
77
|
+
expect(res.resources.web.ownership).toBe("owned");
|
|
78
|
+
expect(res.resources.web.physicalId).toBe("m-web");
|
|
79
|
+
expect(res.resources.web.status).toBe("started");
|
|
80
|
+
expect((res.resources.web.attributes as { config?: unknown }).config).toEqual({
|
|
80
81
|
image: "nginx:1",
|
|
81
82
|
metadata: { "managed-by": "chant" },
|
|
82
83
|
});
|
|
83
84
|
|
|
84
|
-
expect(res.legacy.ownership).toBe("foreign");
|
|
85
|
-
expect(res.legacy.type).toBe("Fly::Machines::Machine");
|
|
85
|
+
expect(res.resources.legacy.ownership).toBe("foreign");
|
|
86
|
+
expect(res.resources.legacy.type).toBe("Fly::Machines::Machine");
|
|
86
87
|
|
|
87
88
|
// App surfaced as owned (app-boundary: it carries an owned machine).
|
|
88
|
-
expect(res.app.type).toBe("Fly::Machines::App");
|
|
89
|
-
expect(res.app.ownership).toBe("owned");
|
|
89
|
+
expect(res.resources.app.type).toBe("Fly::Machines::App");
|
|
90
|
+
expect(res.resources.app.ownership).toBe("owned");
|
|
90
91
|
});
|
|
91
92
|
|
|
92
93
|
test("the owned filter drops foreign entries", async () => {
|
|
@@ -98,8 +99,8 @@ describe("describeResources: live machines → ResourceMetadata verdicts", () =>
|
|
|
98
99
|
{ environment: "prod", buildOutput: PLAN, entityNames: ["app", "web"], entities: ENTS, owned: true, endpoint: ENDPOINT },
|
|
99
100
|
http,
|
|
100
101
|
);
|
|
101
|
-
expect(res.web?.ownership).toBe("owned");
|
|
102
|
-
expect(res.legacy).toBeUndefined(); // foreign machine filtered out
|
|
102
|
+
expect(res.resources.web?.ownership).toBe("owned");
|
|
103
|
+
expect(res.resources.legacy).toBeUndefined(); // foreign machine filtered out
|
|
103
104
|
});
|
|
104
105
|
|
|
105
106
|
test("terminal machines (destroyed/destroying) are not reported live", async () => {
|
|
@@ -111,8 +112,8 @@ describe("describeResources: live machines → ResourceMetadata verdicts", () =>
|
|
|
111
112
|
{ environment: "prod", buildOutput: PLAN, entityNames: ["app", "web"], entities: ENTS, endpoint: ENDPOINT },
|
|
112
113
|
http,
|
|
113
114
|
);
|
|
114
|
-
expect(res.web).toBeDefined();
|
|
115
|
-
expect(res.gone).toBeUndefined();
|
|
115
|
+
expect(res.resources.web).toBeDefined();
|
|
116
|
+
expect(res.resources.gone).toBeUndefined();
|
|
116
117
|
});
|
|
117
118
|
|
|
118
119
|
test("empty build output returns nothing", async () => {
|
|
@@ -120,7 +121,27 @@ describe("describeResources: live machines → ResourceMetadata verdicts", () =>
|
|
|
120
121
|
{ environment: "prod", buildOutput: "", entityNames: [], entities: new Map(), endpoint: ENDPOINT },
|
|
121
122
|
fakeHttp([]),
|
|
122
123
|
);
|
|
123
|
-
expect(res).toEqual({});
|
|
124
|
+
expect(res.resources).toEqual({});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("with no readable plan, declared entities are unobserved rather than absent (#1089)", async () => {
|
|
128
|
+
const res = await describeResources(
|
|
129
|
+
{ environment: "prod", buildOutput: "", entityNames: ["web"], entities: ENTS, endpoint: ENDPOINT },
|
|
130
|
+
fakeHttp([]),
|
|
131
|
+
);
|
|
132
|
+
expect(res.resources).toEqual({});
|
|
133
|
+
expect(res.unobserved?.web?.reason).toBe("read-failed");
|
|
134
|
+
expect(res.unobserved?.app?.reason).toBe("read-failed");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("the owned filter records a withheld declared machine as `filtered`, not absent (#1089)", async () => {
|
|
138
|
+
const http = fakeHttp([liveMachine("web", "nginx:1", { id: "m-web", owned: false })]);
|
|
139
|
+
const res = await describeResources(
|
|
140
|
+
{ environment: "prod", buildOutput: PLAN, entityNames: ["app", "web"], entities: ENTS, owned: true, endpoint: ENDPOINT },
|
|
141
|
+
http,
|
|
142
|
+
);
|
|
143
|
+
expect(res.resources.web).toBeUndefined();
|
|
144
|
+
expect(res.unobserved?.web?.reason).toBe("filtered");
|
|
124
145
|
});
|
|
125
146
|
});
|
|
126
147
|
|
|
@@ -185,4 +206,56 @@ describe("flyPlan: declared-vs-live change set (create/noop/delete/adopt)", () =
|
|
|
185
206
|
);
|
|
186
207
|
expect(changeSet.entries.find((e) => e.name === "web")?.action).toBe("update");
|
|
187
208
|
});
|
|
209
|
+
|
|
210
|
+
test("an unreadable plan makes every declared entity unobserved, not a create (#1089)", async () => {
|
|
211
|
+
const { changeSet } = await flyPlan(
|
|
212
|
+
{ environment: "prod", buildOutput: "not json", entityNames: [...ENTS.keys()], entities: ENTS, endpoint: ENDPOINT },
|
|
213
|
+
fakeHttp([]),
|
|
214
|
+
);
|
|
215
|
+
expect(changeSet.entries.map((e) => e.action)).toEqual(["unobserved", "unobserved"]);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// The shared conformance suite (#1089).
|
|
220
|
+
describeObservationConformance({
|
|
221
|
+
lexicon: "fly",
|
|
222
|
+
scenarios: [
|
|
223
|
+
{
|
|
224
|
+
name: "a build output that is not a readable fly plan",
|
|
225
|
+
declared: ["app", "web"],
|
|
226
|
+
expectUnobserved: ["app", "web"],
|
|
227
|
+
run: () =>
|
|
228
|
+
describeResources(
|
|
229
|
+
{ environment: "prod", buildOutput: "{{ not json", entityNames: ["app", "web"], entities: ENTS, endpoint: ENDPOINT },
|
|
230
|
+
fakeHttp([]),
|
|
231
|
+
),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "the owned filter withholding a declared machine",
|
|
235
|
+
declared: ["app", "web"],
|
|
236
|
+
expectUnobserved: ["web"],
|
|
237
|
+
run: () =>
|
|
238
|
+
describeResources(
|
|
239
|
+
{
|
|
240
|
+
environment: "prod",
|
|
241
|
+
buildOutput: PLAN,
|
|
242
|
+
entityNames: ["app", "web"],
|
|
243
|
+
entities: ENTS,
|
|
244
|
+
owned: true,
|
|
245
|
+
endpoint: ENDPOINT,
|
|
246
|
+
},
|
|
247
|
+
fakeHttp([liveMachine("web", "nginx:1", { owned: false })]),
|
|
248
|
+
),
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: "a healthy read",
|
|
252
|
+
declared: ["app", "web"],
|
|
253
|
+
expectPresent: ["app", "web"],
|
|
254
|
+
run: () =>
|
|
255
|
+
describeResources(
|
|
256
|
+
{ environment: "prod", buildOutput: PLAN, entityNames: ["app", "web"], entities: ENTS, endpoint: ENDPOINT },
|
|
257
|
+
fakeHttp([liveMachine("web", "nginx:1")]),
|
|
258
|
+
),
|
|
259
|
+
},
|
|
260
|
+
],
|
|
188
261
|
});
|
|
Binary file
|
|
@@ -77,15 +77,15 @@ describe("describeResources against live mudflaps (#767)", () => {
|
|
|
77
77
|
|
|
78
78
|
// 3. describeResources sees web owned, legacy foreign.
|
|
79
79
|
const live = await describeResources({ environment: "it", buildOutput, entityNames: [...ents.keys()], entities: ents, endpoint });
|
|
80
|
-
expect(live.web?.ownership).toBe("owned");
|
|
81
|
-
expect(live.web?.status).toBe("started");
|
|
82
|
-
expect(live.legacy?.ownership).toBe("foreign");
|
|
83
|
-
expect(live.app?.ownership).toBe("owned"); // app-boundary: carries an owned machine
|
|
80
|
+
expect(live.resources.web?.ownership).toBe("owned");
|
|
81
|
+
expect(live.resources.web?.status).toBe("started");
|
|
82
|
+
expect(live.resources.legacy?.ownership).toBe("foreign");
|
|
83
|
+
expect(live.resources.app?.ownership).toBe("owned"); // app-boundary: carries an owned machine
|
|
84
84
|
|
|
85
85
|
// 4. The owned filter drops the unmarked machine.
|
|
86
86
|
const ownedOnly = await describeResources({ environment: "it", buildOutput, entityNames: [...ents.keys()], entities: ents, owned: true, endpoint });
|
|
87
|
-
expect(ownedOnly.web?.ownership).toBe("owned");
|
|
88
|
-
expect(ownedOnly.legacy).toBeUndefined();
|
|
87
|
+
expect(ownedOnly.resources.web?.ownership).toBe("owned");
|
|
88
|
+
expect(ownedOnly.resources.legacy).toBeUndefined();
|
|
89
89
|
|
|
90
90
|
// 5. Drop "web" from the declared plan. The plan now classifies the live
|
|
91
91
|
// owned "web" as a delete; the unmarked "legacy" stays adopt (never delete).
|