@intentius/chant 0.124.48 → 0.124.49

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.
Files changed (167) hide show
  1. package/dist/cli/handlers/approve.d.ts.map +1 -1
  2. package/dist/cli/handlers/approve.js +20 -12
  3. package/dist/cli/handlers/graph-reader.d.ts +26 -0
  4. package/dist/cli/handlers/graph-reader.d.ts.map +1 -0
  5. package/dist/cli/handlers/graph-reader.js +41 -0
  6. package/dist/cli/handlers/graph.d.ts.map +1 -1
  7. package/dist/cli/handlers/graph.js +14 -0
  8. package/dist/cli/handlers/pr.d.ts.map +1 -1
  9. package/dist/cli/handlers/pr.js +40 -1
  10. package/dist/cli/main.d.ts.map +1 -1
  11. package/dist/cli/main.js +22 -0
  12. package/dist/cli/parse-args.d.ts.map +1 -1
  13. package/dist/cli/parse-args.js +11 -0
  14. package/dist/cli/registry.d.ts +8 -0
  15. package/dist/cli/registry.d.ts.map +1 -1
  16. package/dist/components/pr-run.d.ts +3 -0
  17. package/dist/components/pr-run.d.ts.map +1 -1
  18. package/dist/components/pr-run.js +1 -0
  19. package/dist/config.d.ts +16 -0
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +4 -0
  22. package/dist/gate-decision.d.ts +9 -0
  23. package/dist/gate-decision.d.ts.map +1 -1
  24. package/dist/gate-decision.js +22 -7
  25. package/dist/lexicon.d.ts +23 -0
  26. package/dist/lexicon.d.ts.map +1 -1
  27. package/dist/op/activities/activity-contracts.d.ts +4 -4
  28. package/dist/op/gate-approval-base.d.ts +25 -0
  29. package/dist/op/gate-approval-base.d.ts.map +1 -0
  30. package/dist/op/gate-approval-base.js +71 -0
  31. package/dist/op/gate-approval.d.ts +7 -4
  32. package/dist/op/gate-approval.d.ts.map +1 -1
  33. package/dist/op/gate-approval.js +2 -25
  34. package/dist/op/gate-name.d.ts +13 -0
  35. package/dist/op/gate-name.d.ts.map +1 -1
  36. package/dist/op/gate-name.js +14 -1
  37. package/dist/op/gate.d.ts +4 -3
  38. package/dist/op/gate.d.ts.map +1 -1
  39. package/dist/op/local-executor.d.ts +9 -2
  40. package/dist/op/local-executor.d.ts.map +1 -1
  41. package/dist/op/local-executor.js +24 -5
  42. package/dist/pr-loop.d.ts +10 -0
  43. package/dist/pr-loop.d.ts.map +1 -1
  44. package/dist/pr-loop.js +4 -0
  45. package/dist/pr-migrations.d.ts +62 -0
  46. package/dist/pr-migrations.d.ts.map +1 -0
  47. package/dist/pr-migrations.js +50 -0
  48. package/dist/pr-post.js +1 -1
  49. package/dist/wave-runtime.mjs +219 -218
  50. package/dist/workspace/check.schema.json +4 -2
  51. package/dist/workspace/checks/gate-approval.d.ts +58 -0
  52. package/dist/workspace/checks/gate-approval.d.ts.map +1 -0
  53. package/dist/workspace/checks/gate-approval.js +103 -0
  54. package/dist/workspace/checks.d.ts +1 -0
  55. package/dist/workspace/checks.d.ts.map +1 -1
  56. package/dist/workspace/checks.js +4 -0
  57. package/dist/workspace/declaration.d.ts +7 -0
  58. package/dist/workspace/declaration.d.ts.map +1 -1
  59. package/dist/workspace/declaration.js +13 -1
  60. package/dist/workspace/declaration.schema.json +33 -0
  61. package/dist/workspace/exit-cli.d.ts +44 -0
  62. package/dist/workspace/exit-cli.d.ts.map +1 -0
  63. package/dist/workspace/exit-cli.js +198 -0
  64. package/dist/workspace/exit.d.ts +159 -0
  65. package/dist/workspace/exit.d.ts.map +1 -0
  66. package/dist/workspace/exit.js +480 -0
  67. package/dist/workspace/exit.schema.json +257 -0
  68. package/dist/workspace/graph-cache.d.ts +3 -1
  69. package/dist/workspace/graph-cache.d.ts.map +1 -1
  70. package/dist/workspace/graph-cache.js +12 -1
  71. package/dist/workspace/import-fetch.d.ts +38 -0
  72. package/dist/workspace/import-fetch.d.ts.map +1 -0
  73. package/dist/workspace/import-fetch.js +99 -0
  74. package/dist/workspace/import-init.d.ts +26 -0
  75. package/dist/workspace/import-init.d.ts.map +1 -0
  76. package/dist/workspace/import-init.js +130 -0
  77. package/dist/workspace/import-source.d.ts +147 -0
  78. package/dist/workspace/import-source.d.ts.map +1 -0
  79. package/dist/workspace/import-source.js +370 -0
  80. package/dist/workspace/init.d.ts +4 -0
  81. package/dist/workspace/init.d.ts.map +1 -1
  82. package/dist/workspace/init.js +70 -3
  83. package/dist/workspace/kind-readers.d.ts +6 -0
  84. package/dist/workspace/kind-readers.d.ts.map +1 -1
  85. package/dist/workspace/kind-readers.js +18 -0
  86. package/dist/workspace/kinds.d.ts +24 -1
  87. package/dist/workspace/kinds.d.ts.map +1 -1
  88. package/dist/workspace/kinds.js +64 -4
  89. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  90. package/dist/workspace/lineage-upgrade.js +13 -4
  91. package/dist/workspace/new-migrations.d.ts +47 -0
  92. package/dist/workspace/new-migrations.d.ts.map +1 -0
  93. package/dist/workspace/new-migrations.js +91 -0
  94. package/dist/workspace/pr-report.schema.json +46 -0
  95. package/dist/workspace/promote.d.ts +96 -0
  96. package/dist/workspace/promote.d.ts.map +1 -0
  97. package/dist/workspace/promote.js +263 -0
  98. package/dist/workspace/reason-codes.d.ts +13 -0
  99. package/dist/workspace/reason-codes.d.ts.map +1 -1
  100. package/dist/workspace/reason-codes.js +14 -0
  101. package/dist/workspace/search-contract.d.ts +1 -1
  102. package/dist/workspace/search-contract.d.ts.map +1 -1
  103. package/dist/workspace/workspace-kinds.schema.json +50 -7
  104. package/package.json +1 -1
  105. package/src/cli/handlers/approve.ts +10 -2
  106. package/src/cli/handlers/graph-reader.test.ts +31 -0
  107. package/src/cli/handlers/graph-reader.ts +51 -0
  108. package/src/cli/handlers/graph.ts +14 -0
  109. package/src/cli/handlers/pr.ts +38 -1
  110. package/src/cli/main.test.ts +2 -0
  111. package/src/cli/main.ts +22 -0
  112. package/src/cli/parse-args.ts +8 -0
  113. package/src/cli/registry.ts +8 -0
  114. package/src/components/pr-env-run-bundle.test.ts +1 -0
  115. package/src/components/pr-run.ts +4 -0
  116. package/src/config.ts +16 -0
  117. package/src/gate-decision-bundle.test.ts +4 -2
  118. package/src/gate-decision-identity.test.ts +11 -0
  119. package/src/gate-decision.ts +26 -6
  120. package/src/lexicon.ts +24 -0
  121. package/src/op/gate-approval-at-base.test.ts +97 -0
  122. package/src/op/gate-approval-base.ts +72 -0
  123. package/src/op/gate-approval.ts +10 -21
  124. package/src/op/gate-name.ts +16 -1
  125. package/src/op/gate.ts +4 -3
  126. package/src/op/local-executor.ts +25 -5
  127. package/src/pr-loop-bundle.test.ts +3 -2
  128. package/src/pr-loop.test.ts +52 -0
  129. package/src/pr-loop.ts +12 -0
  130. package/src/pr-migrations.ts +97 -0
  131. package/src/pr-post.ts +1 -1
  132. package/src/workspace/__fixtures__/import/spacelift.json +9 -0
  133. package/src/workspace/__fixtures__/import/tfc.json +13 -0
  134. package/src/workspace/behold-kinds.test.ts +1 -0
  135. package/src/workspace/check-contract.test.ts +3 -2
  136. package/src/workspace/check.schema.json +4 -2
  137. package/src/workspace/checks/gate-approval.test.ts +77 -0
  138. package/src/workspace/checks/gate-approval.ts +121 -0
  139. package/src/workspace/checks.ts +4 -0
  140. package/src/workspace/declaration.schema.json +33 -0
  141. package/src/workspace/declaration.ts +19 -2
  142. package/src/workspace/exit-cli.ts +219 -0
  143. package/src/workspace/exit.schema.json +257 -0
  144. package/src/workspace/exit.test.ts +185 -0
  145. package/src/workspace/exit.ts +560 -0
  146. package/src/workspace/graph-cache.ts +12 -2
  147. package/src/workspace/identity.test.ts +18 -3
  148. package/src/workspace/import-fetch.ts +151 -0
  149. package/src/workspace/import-init.ts +147 -0
  150. package/src/workspace/import-source.test.ts +183 -0
  151. package/src/workspace/import-source.ts +462 -0
  152. package/src/workspace/init.test.ts +55 -1
  153. package/src/workspace/init.ts +66 -4
  154. package/src/workspace/kind-readers.test.ts +36 -0
  155. package/src/workspace/kind-readers.ts +18 -1
  156. package/src/workspace/kinds.test.ts +23 -0
  157. package/src/workspace/kinds.ts +81 -5
  158. package/src/workspace/lineage-upgrade.test.ts +20 -0
  159. package/src/workspace/lineage-upgrade.ts +16 -7
  160. package/src/workspace/new-migrations.test.ts +98 -0
  161. package/src/workspace/new-migrations.ts +109 -0
  162. package/src/workspace/pr-report.schema.json +46 -0
  163. package/src/workspace/promote.test.ts +114 -0
  164. package/src/workspace/promote.ts +302 -0
  165. package/src/workspace/reason-codes.test.ts +4 -0
  166. package/src/workspace/reason-codes.ts +14 -0
  167. package/src/workspace/workspace-kinds.schema.json +50 -7
@@ -0,0 +1,257 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/exit/v1/exit.schema.json",
4
+ "title": "chant workspace exit output",
5
+ "description": "What `chant workspace exit [<member>...] --json` prints (#3177): the drill report with --drill, and otherwise the staged exit, its drill report and the outcome of the gate. A refused member carries one of the codes in $defs.memberResult.properties.code, and a drill finding one of the codes in $defs.finding.properties.code; both are in the one closed list of `reason-codes.ts`. A failure that stops the command before it prints this document (no such member, a dirty tree, no git repository) prints an error message and exits 1. Readers ignore fields they do not know; a field is only ever added within a version.",
6
+ "oneOf": [
7
+ {
8
+ "$ref": "#/$defs/drill"
9
+ },
10
+ {
11
+ "$ref": "#/$defs/exit"
12
+ }
13
+ ],
14
+ "$defs": {
15
+ "drill": {
16
+ "description": "--drill: the exit run on a scratch copy and checked. Exit code 0 when ok, else 1.",
17
+ "type": "object",
18
+ "required": [
19
+ "outcome",
20
+ "ok",
21
+ "members"
22
+ ],
23
+ "properties": {
24
+ "outcome": {
25
+ "const": "drill"
26
+ },
27
+ "ok": {
28
+ "type": "boolean",
29
+ "description": "True when no member failed. A not-run member does not fail the drill."
30
+ },
31
+ "members": {
32
+ "type": "array",
33
+ "items": {
34
+ "$ref": "#/$defs/drillMember"
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "exit": {
40
+ "description": "The exit staged in a worktree. Exit code 0 for nothing-to-exit, dry-run and applied, 1 for checks-failed and 3 for gated.",
41
+ "type": "object",
42
+ "required": [
43
+ "outcome",
44
+ "digest",
45
+ "members",
46
+ "report"
47
+ ],
48
+ "properties": {
49
+ "outcome": {
50
+ "enum": [
51
+ "nothing-to-exit",
52
+ "checks-failed",
53
+ "dry-run",
54
+ "gated",
55
+ "applied"
56
+ ]
57
+ },
58
+ "digest": {
59
+ "type": "string",
60
+ "description": "sha256: and the first 16 hex digits of the staged patch. The gate binds it."
61
+ },
62
+ "members": {
63
+ "type": "array",
64
+ "items": {
65
+ "$ref": "#/$defs/memberResult"
66
+ }
67
+ },
68
+ "report": {
69
+ "$ref": "#/$defs/report"
70
+ },
71
+ "pending": {
72
+ "description": "With outcome gated: the pending gate fact, as the gate ledger records it."
73
+ },
74
+ "approvedBy": {
75
+ "type": "string",
76
+ "description": "With outcome applied: who approved the gate."
77
+ }
78
+ }
79
+ },
80
+ "report": {
81
+ "description": "The drill's checks of the staged tree.",
82
+ "type": "object",
83
+ "required": [
84
+ "ok",
85
+ "members"
86
+ ],
87
+ "properties": {
88
+ "ok": {
89
+ "type": "boolean"
90
+ },
91
+ "members": {
92
+ "type": "array",
93
+ "items": {
94
+ "$ref": "#/$defs/drillMember"
95
+ }
96
+ }
97
+ }
98
+ },
99
+ "memberResult": {
100
+ "description": "What the exit did to one member.",
101
+ "type": "object",
102
+ "required": [
103
+ "name",
104
+ "dir",
105
+ "kind",
106
+ "status",
107
+ "native",
108
+ "deploy",
109
+ "ci",
110
+ "ops",
111
+ "steps"
112
+ ],
113
+ "properties": {
114
+ "name": {
115
+ "type": "string"
116
+ },
117
+ "dir": {
118
+ "type": "string"
119
+ },
120
+ "kind": {
121
+ "type": "string"
122
+ },
123
+ "status": {
124
+ "enum": [
125
+ "exited",
126
+ "kept",
127
+ "manual",
128
+ "refused",
129
+ "failed"
130
+ ]
131
+ },
132
+ "code": {
133
+ "enum": [
134
+ "missing-dir",
135
+ "no-lexicon",
136
+ "lexicon-unsupported"
137
+ ],
138
+ "description": "With status refused: why the member can't be exited."
139
+ },
140
+ "native": {
141
+ "type": "array",
142
+ "items": {
143
+ "type": "string"
144
+ },
145
+ "description": "Native files written, relative to the workspace root."
146
+ },
147
+ "deploy": {
148
+ "type": "array",
149
+ "items": {
150
+ "type": "string"
151
+ },
152
+ "description": "The stock command for each native file, relative to the member's directory."
153
+ },
154
+ "ci": {
155
+ "type": "array",
156
+ "items": {
157
+ "type": "string"
158
+ },
159
+ "description": "CI files rewritten or written, relative to the workspace root."
160
+ },
161
+ "ops": {
162
+ "type": "array",
163
+ "items": {
164
+ "type": "string"
165
+ },
166
+ "description": "op.json files left in place, relative to the workspace root."
167
+ },
168
+ "steps": {
169
+ "type": "array",
170
+ "items": {
171
+ "type": "string"
172
+ },
173
+ "description": "Steps a person runs, for a member the exit can't do alone."
174
+ },
175
+ "detail": {
176
+ "type": "string"
177
+ }
178
+ }
179
+ },
180
+ "drillMember": {
181
+ "description": "The drill's verdict on one member.",
182
+ "type": "object",
183
+ "required": [
184
+ "name",
185
+ "kind",
186
+ "status",
187
+ "findings",
188
+ "native",
189
+ "deploy"
190
+ ],
191
+ "properties": {
192
+ "name": {
193
+ "type": "string"
194
+ },
195
+ "kind": {
196
+ "type": "string"
197
+ },
198
+ "status": {
199
+ "enum": [
200
+ "passed",
201
+ "failed",
202
+ "not-run",
203
+ "kept"
204
+ ]
205
+ },
206
+ "note": {
207
+ "type": "string",
208
+ "description": "Why the member is not-run or kept."
209
+ },
210
+ "findings": {
211
+ "type": "array",
212
+ "items": {
213
+ "$ref": "#/$defs/finding"
214
+ }
215
+ },
216
+ "native": {
217
+ "type": "array",
218
+ "items": {
219
+ "type": "string"
220
+ }
221
+ },
222
+ "deploy": {
223
+ "type": "array",
224
+ "items": {
225
+ "type": "string"
226
+ }
227
+ }
228
+ }
229
+ },
230
+ "finding": {
231
+ "description": "One thing the drill found wrong with an exited member.",
232
+ "type": "object",
233
+ "required": [
234
+ "code",
235
+ "message"
236
+ ],
237
+ "properties": {
238
+ "code": {
239
+ "enum": [
240
+ "native-missing",
241
+ "native-unreadable",
242
+ "chant-dependency",
243
+ "chant-config-left",
244
+ "chant-in-ci",
245
+ "no-deploy-command",
246
+ "declaration-not-other",
247
+ "exit-failed",
248
+ "choudoufu-steps-missing"
249
+ ]
250
+ },
251
+ "message": {
252
+ "type": "string"
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
@@ -85,7 +85,9 @@ export declare function memberStamp(abs: string, exclude?: readonly string[], at
85
85
  export declare function toolchainStamp(toolchain: Toolchain): string;
86
86
  /** What a kind's reader adds to the key: its graph block, and the installed version of the package supplying it. */
87
87
  export declare function readerStamp(reader: {
88
- lexicon: string;
88
+ lexicon?: string;
89
+ reader?: string;
90
+ readerFile?: string;
89
91
  config: unknown;
90
92
  packageDir: string;
91
93
  }): string;
@@ -1 +1 @@
1
- {"version":3,"file":"graph-cache.d.ts","sourceRoot":"","sources":["../../src/workspace/graph-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph-cache.d.ts","sourceRoot":"","sources":["../../src/workspace/graph-cache.ts"],"names":[],"mappings":"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"}
@@ -197,7 +197,18 @@ export function readerStamp(reader) {
197
197
  catch {
198
198
  // An unreadable manifest keys on the directory alone.
199
199
  }
200
- return JSON.stringify([reader.lexicon, reader.config, reader.packageDir, version]);
200
+ // A reader module is code: its size and mtime key too, so an edit under the same version is a new read (#4413).
201
+ let module = "";
202
+ if (reader.readerFile) {
203
+ try {
204
+ const st = statSync(reader.readerFile);
205
+ module = `${reader.reader}:${st.size}:${st.mtimeMs}`;
206
+ }
207
+ catch {
208
+ module = `${reader.reader}:unreadable`;
209
+ }
210
+ }
211
+ return JSON.stringify([reader.lexicon, reader.config, reader.packageDir, version, ...(module ? [module] : [])]);
201
212
  }
202
213
  /** The ambient environment, less {@link VOLATILE_ENV}, as one digest. */
203
214
  export function environmentStamp(env = process.env) {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The network half of `chant workspace init --from tfc|spacelift` (#3178).
3
+ *
4
+ * Reads the Terraform Cloud API or the Spacelift GraphQL API into the input
5
+ * documents `import-source.ts` maps. The transport is a parameter, so a test
6
+ * feeds fixture responses and nothing here is reached without a token. A
7
+ * token is read from `--token`, else `TFE_TOKEN` / `TF_TOKEN_app_terraform_io`
8
+ * for Terraform Cloud and `SPACELIFT_API_TOKEN` for Spacelift. Only reads:
9
+ * every request is a GET, or a GraphQL query with no mutation.
10
+ */
11
+ import type { SpaceliftInput, TfcInput } from "./import-source.js";
12
+ export type Fetcher = (url: string, init?: {
13
+ method?: string;
14
+ headers?: Record<string, string>;
15
+ body?: string;
16
+ }) => Promise<{
17
+ ok: boolean;
18
+ status: number;
19
+ json(): Promise<unknown>;
20
+ }>;
21
+ export declare class ImportFetchError extends Error {
22
+ }
23
+ export interface TfcFetchOptions {
24
+ organization: string;
25
+ token: string;
26
+ /** Default `https://app.terraform.io`; a Terraform Enterprise host works too. */
27
+ host?: string;
28
+ fetcher?: Fetcher;
29
+ }
30
+ export declare function fetchTfc(options: TfcFetchOptions): Promise<TfcInput>;
31
+ export interface SpaceliftFetchOptions {
32
+ /** The account's endpoint, e.g. `https://acme.app.spacelift.io/graphql`. */
33
+ endpoint: string;
34
+ token: string;
35
+ fetcher?: Fetcher;
36
+ }
37
+ export declare function fetchSpacelift(options: SpaceliftFetchOptions): Promise<SpaceliftInput>;
38
+ //# sourceMappingURL=import-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-fetch.d.ts","sourceRoot":"","sources":["../../src/workspace/import-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhE,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAEvL,qBAAa,gBAAiB,SAAQ,KAAK;CAAG;AAa9C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqD1E;AAID,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AASD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2C5F"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * The network half of `chant workspace init --from tfc|spacelift` (#3178).
3
+ *
4
+ * Reads the Terraform Cloud API or the Spacelift GraphQL API into the input
5
+ * documents `import-source.ts` maps. The transport is a parameter, so a test
6
+ * feeds fixture responses and nothing here is reached without a token. A
7
+ * token is read from `--token`, else `TFE_TOKEN` / `TF_TOKEN_app_terraform_io`
8
+ * for Terraform Cloud and `SPACELIFT_API_TOKEN` for Spacelift. Only reads:
9
+ * every request is a GET, or a GraphQL query with no mutation.
10
+ */
11
+ export class ImportFetchError extends Error {
12
+ }
13
+ const defaultFetch = (url, init) => fetch(url, init);
14
+ export async function fetchTfc(options) {
15
+ const fetcher = options.fetcher ?? defaultFetch;
16
+ const base = (options.host ?? "https://app.terraform.io").replace(/\/$/, "");
17
+ const headers = { Authorization: `Bearer ${options.token}`, "Content-Type": "application/vnd.api+json" };
18
+ const list = async (path) => {
19
+ const out = [];
20
+ let url = `${base}/api/v2${path}${path.includes("?") ? "&" : "?"}page%5Bsize%5D=100`;
21
+ while (url) {
22
+ const res = await fetcher(url, { method: "GET", headers });
23
+ if (!res.ok)
24
+ throw new ImportFetchError(`Terraform Cloud answered ${res.status} for ${url.replace(base, "")}`);
25
+ const body = (await res.json());
26
+ out.push(...(body.data ?? []));
27
+ url = body.links?.next ?? undefined;
28
+ }
29
+ return out;
30
+ };
31
+ const org = encodeURIComponent(options.organization);
32
+ const [projects, workspaces, policySets] = await Promise.all([list(`/organizations/${org}/projects`), list(`/organizations/${org}/workspaces`), list(`/organizations/${org}/policy-sets`)]);
33
+ const full = [];
34
+ for (const w of workspaces) {
35
+ const a = w.attributes ?? {};
36
+ const [vars, triggers] = await Promise.all([list(`/workspaces/${w.id}/vars`), list(`/workspaces/${w.id}/run-triggers?filter%5Brun-trigger%5D%5Btype%5D=inbound`)]);
37
+ const project = w.relationships?.project?.data;
38
+ full.push({
39
+ id: w.id,
40
+ name: String(a.name ?? w.id),
41
+ ...(project && !Array.isArray(project) ? { project: project.id } : {}),
42
+ ...(a["working-directory"] ? { workingDirectory: String(a["working-directory"]) } : {}),
43
+ ...(a["terraform-version"] ? { terraformVersion: String(a["terraform-version"]) } : {}),
44
+ ...(a["vcs-repo"]?.identifier ? { vcsRepo: a["vcs-repo"].identifier } : {}),
45
+ tags: Array.isArray(a["tag-names"]) ? a["tag-names"] : [],
46
+ variables: vars.map((v) => ({ key: String(v.attributes?.key ?? ""), category: String(v.attributes?.category ?? ""), sensitive: v.attributes?.sensitive === true })),
47
+ runTriggers: triggers
48
+ .map((t) => t.relationships?.sourceable?.data?.id)
49
+ .filter((id) => typeof id === "string"),
50
+ });
51
+ }
52
+ return {
53
+ organization: options.organization,
54
+ projects: projects.map((p) => ({ id: p.id, name: String(p.attributes?.name ?? p.id) })),
55
+ workspaces: full,
56
+ policySets: policySets.map((p) => ({
57
+ id: p.id,
58
+ name: String(p.attributes?.name ?? p.id),
59
+ kind: String(p.attributes?.kind ?? "sentinel"),
60
+ global: p.attributes?.global === true,
61
+ workspaces: (p.relationships?.workspaces?.data ?? []).map((x) => x.id),
62
+ })),
63
+ };
64
+ }
65
+ const SPACELIFT_QUERY = `query ChantImport {
66
+ stacks { id name space repository branch projectRoot vendor { __typename } labels
67
+ attachedPolicies: attachedPolicies { id }
68
+ dependsOn: dependencies { stackId references { outputName inputName } } }
69
+ policies { id name type }
70
+ }`;
71
+ export async function fetchSpacelift(options) {
72
+ const fetcher = options.fetcher ?? defaultFetch;
73
+ const res = await fetcher(options.endpoint, {
74
+ method: "POST",
75
+ headers: { Authorization: `Bearer ${options.token}`, "Content-Type": "application/json" },
76
+ body: JSON.stringify({ query: SPACELIFT_QUERY }),
77
+ });
78
+ if (!res.ok)
79
+ throw new ImportFetchError(`Spacelift answered ${res.status} for ${options.endpoint}`);
80
+ const body = (await res.json());
81
+ if (body.errors?.length)
82
+ throw new ImportFetchError(`Spacelift: ${body.errors.map((e) => e.message).join("; ")}`);
83
+ return {
84
+ account: new URL(options.endpoint).hostname.split(".")[0],
85
+ stacks: (body.data?.stacks ?? []).map((s) => ({
86
+ id: s.id,
87
+ name: s.name,
88
+ ...(s.space ? { space: s.space } : {}),
89
+ ...(s.repository ? { repository: s.repository } : {}),
90
+ ...(s.branch ? { branch: s.branch } : {}),
91
+ ...(s.projectRoot ? { projectRoot: s.projectRoot } : {}),
92
+ vendor: (s.vendor?.__typename ?? "TerraformStackVendor").replace(/StackVendor$|Vendor$/, "").toLowerCase() || "terraform",
93
+ labels: s.labels ?? [],
94
+ policies: (s.attachedPolicies ?? []).map((p) => p.id),
95
+ dependsOn: (s.dependsOn ?? []).map((d) => ({ stack: d.stackId, references: d.references ?? [] })),
96
+ })),
97
+ policies: body.data?.policies ?? [],
98
+ };
99
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `chant workspace init --from tfc|spacelift|backstage` (#3178): the command
3
+ * around `import-source.ts`. It reads the source, prints the proposal and what
4
+ * was left out, and writes only on confirmation, as `init` does (#2525 rule 1).
5
+ * Besides `chant.workspace.json` it writes `chant-import.<source>.json`: the
6
+ * environments and constraint records the declaration has no field for.
7
+ */
8
+ import type { CommandContext } from "../cli/registry.js";
9
+ import { ImportFetchError, type Fetcher } from "./import-fetch.js";
10
+ import { type ImportProposal, type ImportSource } from "./import-source.js";
11
+ export declare const IMPORT_USAGE: string;
12
+ export declare const isImportSource: (v: string | undefined) => v is ImportSource;
13
+ export interface ImportDeps {
14
+ /** For tests: the transport the API readers use. */
15
+ fetcher?: Fetcher;
16
+ env?: Record<string, string | undefined>;
17
+ /** For tests: answers the confirmation. */
18
+ confirm?: (question: string) => Promise<boolean>;
19
+ isTTY?: boolean;
20
+ }
21
+ /** Read the source into a proposal. Throws {@link ImportFetchError} or an Error naming what is missing. */
22
+ export declare function loadProposal(source: ImportSource, root: string, args: CommandContext["args"], deps?: ImportDeps): Promise<ImportProposal>;
23
+ export declare function formatImportProposal(p: ImportProposal): string[];
24
+ export declare function runImportInit(source: ImportSource, root: string, args: CommandContext["args"], deps?: ImportDeps): Promise<number>;
25
+ export { ImportFetchError };
26
+ //# sourceMappingURL=import-init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-init.d.ts","sourceRoot":"","sources":["../../src/workspace/import-init.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAA4B,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,YAAY,EAGlB,MAAM,iBAAiB,CAAC;AAGzB,eAAO,MAAM,YAAY,QAGqD,CAAC;AAE/E,eAAO,MAAM,cAAc,MAAO,MAAM,GAAG,SAAS,KAAG,CAAC,IAAI,YAAuE,CAAC;AAEpI,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,2GAA2G;AAC3G,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAuBnJ;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAiBhE;AAcD,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C5I;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * `chant workspace init --from tfc|spacelift|backstage` (#3178): the command
3
+ * around `import-source.ts`. It reads the source, prints the proposal and what
4
+ * was left out, and writes only on confirmation, as `init` does (#2525 rule 1).
5
+ * Besides `chant.workspace.json` it writes `chant-import.<source>.json`: the
6
+ * environments and constraint records the declaration has no field for.
7
+ */
8
+ import { existsSync, writeFileSync } from "node:fs";
9
+ import { join, resolve } from "node:path";
10
+ import { formatError, formatSuccess } from "../cli/format.js";
11
+ import { fetchSpacelift, fetchTfc, ImportFetchError } from "./import-fetch.js";
12
+ import { IMPORT_SOURCES, proposeFromBackstage, proposeFromSpacelift, proposeFromTfc, readInputFile, } from "./import-source.js";
13
+ import { WorkspaceReadError } from "./declaration.js";
14
+ export const IMPORT_USAGE = "chant workspace init --from tfc --org <organization> [--input <export.json>] [--token <token>] [dir] [--name <name>] [--yes]\n" +
15
+ " chant workspace init --from spacelift --endpoint <https://acme.app.spacelift.io/graphql> [--input <export.json>] [--token <token>] [dir] [--yes]\n" +
16
+ " chant workspace init --from backstage [dir] [--name <name>] [--yes]";
17
+ export const isImportSource = (v) => IMPORT_SOURCES.includes(v ?? "");
18
+ /** Read the source into a proposal. Throws {@link ImportFetchError} or an Error naming what is missing. */
19
+ export async function loadProposal(source, root, args, deps = {}) {
20
+ const env = deps.env ?? process.env;
21
+ if (source === "backstage")
22
+ return proposeFromBackstage(root, { name: args.selectName });
23
+ if (source === "tfc") {
24
+ let input;
25
+ if (args.input)
26
+ input = readInputFile("tfc", resolve(args.input));
27
+ else {
28
+ const token = args.token ?? env.TFE_TOKEN ?? env.TF_TOKEN_app_terraform_io;
29
+ if (!token)
30
+ throw new Error("--from tfc needs --input <export.json>, or a token in --token, TFE_TOKEN or TF_TOKEN_app_terraform_io");
31
+ if (!args.org)
32
+ throw new Error("--from tfc needs --org <organization>");
33
+ input = await fetchTfc({ organization: args.org, token, fetcher: deps.fetcher });
34
+ }
35
+ return proposeFromTfc(input, { name: args.selectName });
36
+ }
37
+ let input;
38
+ if (args.input)
39
+ input = readInputFile("spacelift", resolve(args.input));
40
+ else {
41
+ const token = args.token ?? env.SPACELIFT_API_TOKEN;
42
+ if (!token)
43
+ throw new Error("--from spacelift needs --input <export.json>, or a token in --token or SPACELIFT_API_TOKEN");
44
+ if (!args.endpoint)
45
+ throw new Error("--from spacelift needs --endpoint <https://<account>.app.spacelift.io/graphql>");
46
+ input = await fetchSpacelift({ endpoint: args.endpoint, token, fetcher: deps.fetcher });
47
+ }
48
+ return proposeFromSpacelift(input, { name: args.selectName });
49
+ }
50
+ export function formatImportProposal(p) {
51
+ const lines = [];
52
+ const links = p.declaration.members.reduce((n, m) => n + (m.links?.length ?? 0), 0);
53
+ lines.push(`${p.declaration.members.length} member(s), ${links} link(s), ${p.environments.length} environment(s), ${p.records.length} constraint record(s).`);
54
+ if (p.environments.length > 0) {
55
+ lines.push("", "Environments:");
56
+ for (const e of p.environments)
57
+ lines.push(` ${e.name}: ${e.members.join(", ")}`);
58
+ }
59
+ if (p.records.length > 0) {
60
+ lines.push("", "Constraint records:");
61
+ for (const r of p.records)
62
+ lines.push(` ${r.id}${r.policyKind ? ` (${r.policyKind})` : ""} applies to ${r.appliesTo.length === 0 ? "every member" : r.appliesTo.join(", ")}`);
63
+ }
64
+ lines.push("", "Left out:");
65
+ if (p.leftOut.length === 0)
66
+ lines.push(" nothing");
67
+ for (const l of p.leftOut)
68
+ lines.push(` ${l.count} ${l.what}: ${l.why}`);
69
+ for (const n of p.notes)
70
+ lines.push("", n);
71
+ return lines;
72
+ }
73
+ async function defaultConfirm(question) {
74
+ const { createInterface } = await import("node:readline");
75
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
76
+ return new Promise((done) => {
77
+ rl.question(question, (a) => {
78
+ done(/^y(es)?$/i.test(a.trim()));
79
+ rl.close();
80
+ });
81
+ rl.on("close", () => done(false));
82
+ });
83
+ }
84
+ export async function runImportInit(source, root, args, deps = {}) {
85
+ let proposal;
86
+ try {
87
+ proposal = await loadProposal(source, root, args, deps);
88
+ }
89
+ catch (err) {
90
+ if (err instanceof WorkspaceReadError) {
91
+ console.error(formatError({ message: `the proposed declaration is not valid: ${err.describe()}`, hint: "Write chant.workspace.json by hand for now." }));
92
+ return 1;
93
+ }
94
+ console.error(formatError({ message: err instanceof Error ? err.message : String(err), hint: IMPORT_USAGE }));
95
+ return 1;
96
+ }
97
+ const target = join(root, "chant.workspace.json");
98
+ const sidecar = join(root, `chant-import.${source}.json`);
99
+ const text = `${JSON.stringify(proposal.declaration, null, 2)}\n`;
100
+ const sideText = `${JSON.stringify({ source, environments: proposal.environments, records: proposal.records, leftOut: proposal.leftOut }, null, 2)}\n`;
101
+ console.log(`Proposed ${target}:`);
102
+ console.log("");
103
+ console.log(text);
104
+ for (const line of formatImportProposal(proposal))
105
+ console.log(line);
106
+ console.log("");
107
+ console.log(`Confirming also writes ${sidecar}, holding the environments, constraint records and the left-out list.`);
108
+ console.log("");
109
+ let write = !!args.yes;
110
+ if (!write) {
111
+ if (!(deps.isTTY ?? process.stdin.isTTY)) {
112
+ console.log("Nothing written. Re-run with --yes to write it, or save the proposal above and edit it first.");
113
+ return 0;
114
+ }
115
+ write = await (deps.confirm ?? defaultConfirm)("Write chant.workspace.json? [y/N] ");
116
+ }
117
+ if (!write) {
118
+ console.log("Nothing written.");
119
+ return 0;
120
+ }
121
+ if (existsSync(sidecar)) {
122
+ console.error(formatError({ message: `${sidecar} already exists`, hint: "Move it aside and run again." }));
123
+ return 1;
124
+ }
125
+ writeFileSync(target, text, { flag: "wx" });
126
+ writeFileSync(sidecar, sideText, { flag: "wx" });
127
+ console.log(formatSuccess(`Wrote ${target} and ${sidecar}. chant workspace ls lists what it declares.`));
128
+ return 0;
129
+ }
130
+ export { ImportFetchError };