redkite 0.1.6

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 (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +819 -0
  3. package/bin/redkite.mjs +12 -0
  4. package/dist/build.d.ts +27 -0
  5. package/dist/build.d.ts.map +1 -0
  6. package/dist/build.js +132 -0
  7. package/dist/build.js.map +1 -0
  8. package/dist/checks.d.ts +4 -0
  9. package/dist/checks.d.ts.map +1 -0
  10. package/dist/checks.js +49 -0
  11. package/dist/checks.js.map +1 -0
  12. package/dist/cli/agent.d.ts +2 -0
  13. package/dist/cli/agent.d.ts.map +1 -0
  14. package/dist/cli/agent.js +24 -0
  15. package/dist/cli/agent.js.map +1 -0
  16. package/dist/cli/config.d.ts +5 -0
  17. package/dist/cli/config.d.ts.map +1 -0
  18. package/dist/cli/config.js +217 -0
  19. package/dist/cli/config.js.map +1 -0
  20. package/dist/cli/index.d.ts +11 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +438 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cli/log.d.ts +9 -0
  25. package/dist/cli/log.d.ts.map +1 -0
  26. package/dist/cli/log.js +128 -0
  27. package/dist/cli/log.js.map +1 -0
  28. package/dist/cli/screen.d.ts +34 -0
  29. package/dist/cli/screen.d.ts.map +1 -0
  30. package/dist/cli/screen.js +298 -0
  31. package/dist/cli/screen.js.map +1 -0
  32. package/dist/cli/viewer.d.ts +9 -0
  33. package/dist/cli/viewer.d.ts.map +1 -0
  34. package/dist/cli/viewer.js +139 -0
  35. package/dist/cli/viewer.js.map +1 -0
  36. package/dist/config.d.ts +7 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +79 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/deploy.d.ts +19 -0
  41. package/dist/deploy.d.ts.map +1 -0
  42. package/dist/deploy.js +275 -0
  43. package/dist/deploy.js.map +1 -0
  44. package/dist/docker.d.ts +96 -0
  45. package/dist/docker.d.ts.map +1 -0
  46. package/dist/docker.js +325 -0
  47. package/dist/docker.js.map +1 -0
  48. package/dist/dockerfile.d.ts +14 -0
  49. package/dist/dockerfile.d.ts.map +1 -0
  50. package/dist/dockerfile.js +160 -0
  51. package/dist/dockerfile.js.map +1 -0
  52. package/dist/health.d.ts +13 -0
  53. package/dist/health.d.ts.map +1 -0
  54. package/dist/health.js +54 -0
  55. package/dist/health.js.map +1 -0
  56. package/dist/host.d.ts +21 -0
  57. package/dist/host.d.ts.map +1 -0
  58. package/dist/host.js +27 -0
  59. package/dist/host.js.map +1 -0
  60. package/dist/index.d.ts +26 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +26 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/layout.d.ts +5 -0
  65. package/dist/layout.d.ts.map +1 -0
  66. package/dist/layout.js +45 -0
  67. package/dist/layout.js.map +1 -0
  68. package/dist/localHost.d.ts +7 -0
  69. package/dist/localHost.d.ts.map +1 -0
  70. package/dist/localHost.js +32 -0
  71. package/dist/localHost.js.map +1 -0
  72. package/dist/log.d.ts +14 -0
  73. package/dist/log.d.ts.map +1 -0
  74. package/dist/log.js +15 -0
  75. package/dist/log.js.map +1 -0
  76. package/dist/nginx.d.ts +4 -0
  77. package/dist/nginx.d.ts.map +1 -0
  78. package/dist/nginx.js +53 -0
  79. package/dist/nginx.js.map +1 -0
  80. package/dist/pipeline.d.ts +103 -0
  81. package/dist/pipeline.d.ts.map +1 -0
  82. package/dist/pipeline.js +142 -0
  83. package/dist/pipeline.js.map +1 -0
  84. package/dist/presets/index.d.ts +3 -0
  85. package/dist/presets/index.d.ts.map +1 -0
  86. package/dist/presets/index.js +3 -0
  87. package/dist/presets/index.js.map +1 -0
  88. package/dist/presets/nextApp.d.ts +15 -0
  89. package/dist/presets/nextApp.d.ts.map +1 -0
  90. package/dist/presets/nextApp.js +53 -0
  91. package/dist/presets/nextApp.js.map +1 -0
  92. package/dist/presets/nodeApp.d.ts +19 -0
  93. package/dist/presets/nodeApp.d.ts.map +1 -0
  94. package/dist/presets/nodeApp.js +29 -0
  95. package/dist/presets/nodeApp.js.map +1 -0
  96. package/dist/secrets/bitwarden.d.ts +3 -0
  97. package/dist/secrets/bitwarden.d.ts.map +1 -0
  98. package/dist/secrets/bitwarden.js +6 -0
  99. package/dist/secrets/bitwarden.js.map +1 -0
  100. package/dist/secrets/refs.d.ts +9 -0
  101. package/dist/secrets/refs.d.ts.map +1 -0
  102. package/dist/secrets/refs.js +20 -0
  103. package/dist/secrets/refs.js.map +1 -0
  104. package/dist/secrets/store.d.ts +9 -0
  105. package/dist/secrets/store.d.ts.map +1 -0
  106. package/dist/secrets/store.js +104 -0
  107. package/dist/secrets/store.js.map +1 -0
  108. package/dist/services/ensure.d.ts +18 -0
  109. package/dist/services/ensure.d.ts.map +1 -0
  110. package/dist/services/ensure.js +93 -0
  111. package/dist/services/ensure.js.map +1 -0
  112. package/dist/services/index.d.ts +19 -0
  113. package/dist/services/index.d.ts.map +1 -0
  114. package/dist/services/index.js +27 -0
  115. package/dist/services/index.js.map +1 -0
  116. package/dist/services/planned.d.ts +20 -0
  117. package/dist/services/planned.d.ts.map +1 -0
  118. package/dist/services/planned.js +77 -0
  119. package/dist/services/planned.js.map +1 -0
  120. package/dist/shell.d.ts +11 -0
  121. package/dist/shell.d.ts.map +1 -0
  122. package/dist/shell.js +65 -0
  123. package/dist/shell.js.map +1 -0
  124. package/dist/source.d.ts +16 -0
  125. package/dist/source.d.ts.map +1 -0
  126. package/dist/source.js +108 -0
  127. package/dist/source.js.map +1 -0
  128. package/dist/sshHost.d.ts +15 -0
  129. package/dist/sshHost.d.ts.map +1 -0
  130. package/dist/sshHost.js +91 -0
  131. package/dist/sshHost.js.map +1 -0
  132. package/dist/steps.d.ts +27 -0
  133. package/dist/steps.d.ts.map +1 -0
  134. package/dist/steps.js +69 -0
  135. package/dist/steps.js.map +1 -0
  136. package/dist/topology.d.ts +40 -0
  137. package/dist/topology.d.ts.map +1 -0
  138. package/dist/topology.js +113 -0
  139. package/dist/topology.js.map +1 -0
  140. package/dist/types.d.ts +100 -0
  141. package/dist/types.d.ts.map +1 -0
  142. package/dist/types.js +2 -0
  143. package/dist/types.js.map +1 -0
  144. package/package.json +64 -0
  145. package/src/build.ts +236 -0
  146. package/src/checks.ts +65 -0
  147. package/src/cli/agent.ts +28 -0
  148. package/src/cli/config.ts +275 -0
  149. package/src/cli/index.ts +559 -0
  150. package/src/cli/log.ts +168 -0
  151. package/src/cli/screen.ts +409 -0
  152. package/src/cli/viewer.ts +192 -0
  153. package/src/config.ts +90 -0
  154. package/src/deploy.ts +409 -0
  155. package/src/docker.ts +433 -0
  156. package/src/dockerfile.ts +228 -0
  157. package/src/health.ts +83 -0
  158. package/src/host.ts +54 -0
  159. package/src/index.ts +25 -0
  160. package/src/layout.ts +41 -0
  161. package/src/localHost.ts +50 -0
  162. package/src/log.ts +38 -0
  163. package/src/nginx.ts +63 -0
  164. package/src/pipeline.ts +335 -0
  165. package/src/presets/index.ts +2 -0
  166. package/src/presets/nextApp.ts +70 -0
  167. package/src/presets/nodeApp.ts +46 -0
  168. package/src/secrets/bitwarden.ts +7 -0
  169. package/src/secrets/refs.ts +32 -0
  170. package/src/secrets/store.ts +147 -0
  171. package/src/services/ensure.ts +160 -0
  172. package/src/services/index.ts +48 -0
  173. package/src/services/planned.ts +119 -0
  174. package/src/shell.ts +95 -0
  175. package/src/source.ts +171 -0
  176. package/src/sshHost.ts +145 -0
  177. package/src/steps.ts +101 -0
  178. package/src/topology.ts +199 -0
  179. package/src/types.ts +243 -0
@@ -0,0 +1,438 @@
1
+ import { environmentOf } from "../config.js";
2
+ import { deploy, verify } from "../deploy.js";
3
+ import { Docker } from "../docker.js";
4
+ import { localHost } from "../localHost.js";
5
+ import { silent } from "../log.js";
6
+ import { renderNginx } from "../nginx.js";
7
+ import { addressOf, RUNS, SLOTS } from "../pipeline.js";
8
+ import { listRefs } from "../secrets/refs.js";
9
+ import { bitwardenStore } from "../secrets/store.js";
10
+ import { driftOf, plannedServices } from "../services/planned.js";
11
+ import { sshHost } from "../sshHost.js";
12
+ import { topologyFor } from "../topology.js";
13
+ import { requireAgent } from "./agent.js";
14
+ import { loadConfig } from "./config.js";
15
+ import { createLog, describeFailure } from "./log.js";
16
+ // One command that reads the config and does everything under it: the agent,
17
+ // the vault, the checkout, the build, the swap and the cleanup.
18
+ const USAGE = `redkite <command> [environment]
19
+
20
+ plan [environment] Print the derived topology, the pipeline and the nginx
21
+ deploy [environment] Build, swap, health check, and revert on failure
22
+ verify [environment] Bring the services up, build, and run each app's checks
23
+
24
+ --config <path> Defaults to redkite.config.ts at the root of the project
25
+ --local Build the images here and ship them to the host
26
+ --full No step view: every line of every step, in full
27
+ --verbose Every host command, and every line a build printed
28
+ --version Print the version and exit
29
+
30
+ Environment defaults to staging. A deployment is one redkite.config.ts at the root
31
+ of the project, and everything below it is derived.
32
+ `;
33
+ // Wraps a host rather than living inside one, so both implementations are
34
+ // measured the same way and neither knows it is being timed
35
+ function measured(host, log) {
36
+ const totals = { commands: 0, commandMs: 0, files: 0 };
37
+ const wrapped = {
38
+ directory: host.directory,
39
+ cache: host.cache,
40
+ pipe: host.pipe.bind(host),
41
+ stop: host.stop.bind(host),
42
+ sh: async (command, onLine) => {
43
+ const started = Date.now();
44
+ const result = await host.sh(command, onLine);
45
+ totals.commands += 1;
46
+ totals.commandMs += Date.now() - started;
47
+ // The exit code matters: several of these are allowed to fail, and a
48
+ // deploy reading verbose output is one where somebody wants to know which
49
+ log?.(` $ ${command} ${Date.now() - started}ms exit ${result.code}`);
50
+ return result;
51
+ },
52
+ write: async (name, contents) => {
53
+ totals.files += 1;
54
+ return await host.write(name, contents);
55
+ },
56
+ close: host.close?.bind(host),
57
+ };
58
+ const summary = () => `${totals.commands} commands in ${seconds(totals.commandMs)}, ` +
59
+ `${totals.files} files written`;
60
+ return { host: wrapped, summary };
61
+ }
62
+ function seconds(ms) {
63
+ return `${(ms / 1000).toFixed(1)}s`;
64
+ }
65
+ // Read rather than generated into the build, so a published package and a
66
+ // linked checkout answer with the same thing
67
+ async function version() {
68
+ const manifest = new URL("../../package.json", import.meta.url);
69
+ const { readFile } = await import("node:fs/promises");
70
+ const { version: found } = JSON.parse(await readFile(manifest, "utf8"));
71
+ return found;
72
+ }
73
+ // Flags that take a value, so the value is not mistaken for the environment
74
+ const VALUED = new Set(["--config"]);
75
+ function flag(argv, name) {
76
+ const joined = argv.find((arg) => arg.startsWith(`${name}=`));
77
+ if (joined)
78
+ return joined.slice(name.length + 1);
79
+ const at = argv.indexOf(name);
80
+ return at === -1 ? undefined : argv[at + 1];
81
+ }
82
+ export function positional(argv) {
83
+ const args = [];
84
+ for (let index = 0; index < argv.length; index += 1) {
85
+ const arg = argv[index];
86
+ if (!arg.startsWith("--")) {
87
+ args.push(arg);
88
+ continue;
89
+ }
90
+ // Only the two-word form consumes the next item. --flag=value does not
91
+ if (VALUED.has(arg))
92
+ index += 1;
93
+ }
94
+ return args;
95
+ }
96
+ export async function main(argv) {
97
+ try {
98
+ return await dispatch(argv);
99
+ }
100
+ catch (error) {
101
+ // A deploy reports its own failure through the live view. Everything before
102
+ // one has started, a config that will not load above all, lands here
103
+ process.stderr.write(`${describeFailure(error)}\n`);
104
+ process.exitCode = 1;
105
+ }
106
+ }
107
+ async function dispatch(argv) {
108
+ const args = positional(argv);
109
+ const command = args[0] ?? "";
110
+ const environment = args[1] ?? "staging";
111
+ if (argv.includes("--version") || command === "version") {
112
+ return process.stdout.write(`${await version()}\n`);
113
+ }
114
+ const configPath = flag(argv, "--config");
115
+ if (command === "plan")
116
+ return await plan(environment, configPath);
117
+ if (command === "deploy" || command === "verify") {
118
+ return await run(command, environment, configPath, {
119
+ verbose: argv.includes("--verbose"),
120
+ full: argv.includes("--full"),
121
+ local: argv.includes("--local"),
122
+ });
123
+ }
124
+ process.stdout.write(USAGE);
125
+ process.exitCode = command ? 1 : 0;
126
+ }
127
+ async function plan(environment, configPath) {
128
+ const config = await loadConfig(configPath);
129
+ const topology = topologyFor(config, environment);
130
+ const say = (message = "") => process.stdout.write(`${message}\n`);
131
+ say(`# ${config.project} · ${environment}\n`);
132
+ say(`network ${topology.network} ${topology.cidr}`);
133
+ say(`branch ${topology.branch}`);
134
+ // A verify environment publishes nothing, because nothing in one serves
135
+ say(topology.publicPort
136
+ ? `published ${topology.publicPort} -> ${topology.router.container} ${topology.router.address}\n`
137
+ : "published nothing, this environment has no publicPort\n");
138
+ const sources = new Map(config.apps.map((app) => [app.name, app.path ?? app.repo]));
139
+ for (const app of topology.apps) {
140
+ say(`app ${app.name}`);
141
+ say(` source ${sources.get(app.name) ?? "?"}`);
142
+ say(` current ${app.container} ${app.currentAddress}:${app.port}`);
143
+ say(` retired ${app.retired} ${app.retiredAddress}`);
144
+ say(` route ${app.route}`);
145
+ for (const volume of app.volumes) {
146
+ say(` volume ${volume.volume} -> ${volume.mountPath}`);
147
+ }
148
+ for (const [name, key] of Object.entries(app.caches)) {
149
+ say(` cache ${name} -> ${key}`);
150
+ }
151
+ say();
152
+ }
153
+ for (const service of topology.services) {
154
+ say(`service ${service.name} ${service.container} ${service.address}`);
155
+ for (const volume of service.volumes) {
156
+ say(` volume ${volume.volume} -> ${volume.mountPath}`);
157
+ }
158
+ }
159
+ // An environment that publishes nothing cannot serve, so verify is the only
160
+ // run it supports. Nothing declares that: the missing port is what says it
161
+ const serves = Boolean(topology.publicPort);
162
+ sayPipeline(config, serves, say);
163
+ await sayDrift(config, topology, serves ? "deploy" : "verify", say);
164
+ if (!serves)
165
+ return;
166
+ say(`\n# rendered nginx ${"-".repeat(44)}\n`);
167
+ say(renderNginx(topology, config.maxBodySize));
168
+ }
169
+ // What is running against what this file says should be. Services outlive a
170
+ // deploy, so this is the only part of a plan that cannot be answered from the
171
+ // config alone, and the only part that needs the host
172
+ async function sayDrift(config, topology, run, say) {
173
+ say(`\nservices on the host (${run})`);
174
+ const bastion = environmentOf(config, topology.environment)?.host;
175
+ let host;
176
+ try {
177
+ host = await hostFor(bastion, silent);
178
+ const planned = plannedServices(config, topology, run);
179
+ const drifted = await driftOf(planned, topology, new Docker(host));
180
+ if (drifted.length === 0)
181
+ return say(" every service is what this file says");
182
+ for (const drift of drifted)
183
+ say(` ${drift.container.padEnd(34)}${DRIFT[drift.reason]}`);
184
+ say(`\n a ${run} converges these`);
185
+ }
186
+ catch (error) {
187
+ // A plan is worth printing without a host. Saying so beats printing
188
+ // nothing, and beats printing a clean bill of health nobody checked
189
+ say(` not checked: ${describeFailure(error).split("\n")[0]}`);
190
+ }
191
+ finally {
192
+ await host?.close?.();
193
+ }
194
+ }
195
+ const DRIFT = {
196
+ missing: "not there, will be created",
197
+ stopped: "created from this file, but not running",
198
+ changed: "created from an earlier version of this file",
199
+ unrecognised: "not created by redkite, will be recreated",
200
+ };
201
+ // What each run will actually do, in the order it will do it. A step is
202
+ // addressed rather than called, so this is the only place a sequence is visible
203
+ function sayPipeline(config, serves, say) {
204
+ const steps = config.steps ?? [];
205
+ const added = new Set(steps.map((step) => step.point));
206
+ const at = (phase, slot) => steps.filter((step) => {
207
+ const address = addressOf(step.point);
208
+ return address.phase === phase && address.slot === slot && step.point !== phase;
209
+ });
210
+ const checked = config.apps.filter((app) => app.verify).map((app) => app.name);
211
+ // Both refusals live on a step's check, so a run printed here is one this
212
+ // environment can actually be asked for
213
+ const runs = Object.entries(RUNS).filter(([run]) => (run === "verify" ? checked.length > 0 : serves));
214
+ if (runs.length === 0) {
215
+ return say("\nno pipeline. This environment publishes nothing, so it cannot deploy, " +
216
+ "and no app declares verify");
217
+ }
218
+ for (const [run, phases] of runs) {
219
+ say(`\npipeline (${run})`);
220
+ for (const phase of phases) {
221
+ for (const slot of SLOTS) {
222
+ // Redkite's own step leads its phase's slot. A deployment that puts one
223
+ // at the same point replaces it, and this is where that shows
224
+ if (slot === "main") {
225
+ const who = added.has(phase) ? "replaced" : "redkite";
226
+ const what = phase === "verify" ? ` ${checked.join(", ")}` : "";
227
+ say(` ${phase.padEnd(26)}${who}${what}`);
228
+ }
229
+ for (const step of at(phase, slot))
230
+ say(` ${step.point}`);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ // Five presses is a build that has ignored SIGKILL, which is a process nothing
236
+ // here can end. The way out is offered rather than taken, because taking it is
237
+ // the one thing that leaves work running with nothing watching it
238
+ const ASK_AT = 5;
239
+ // The first ask is polite, every one after it is not. What a press does is
240
+ // choose the signal the wait keeps sending, and only the last one leaves
241
+ export function stopper(on) {
242
+ let presses = 0;
243
+ return () => {
244
+ presses += 1;
245
+ if (presses === 1) {
246
+ on.say("Stopping the build (SIGTERM). Press again to kill it");
247
+ on.abort();
248
+ return on.signal("TERM");
249
+ }
250
+ if (presses < ASK_AT) {
251
+ on.say("Killing the build (SIGKILL). Nothing exits until it is gone");
252
+ return on.signal("KILL");
253
+ }
254
+ if (presses === ASK_AT) {
255
+ for (const line of REFUSING)
256
+ on.say(line);
257
+ return on.signal("KILL");
258
+ }
259
+ on.leave();
260
+ };
261
+ }
262
+ // What leaving costs, said before it is offered rather than after it is done
263
+ const REFUSING = [
264
+ "This is not stopping. It has had SIGKILL and is still there.",
265
+ "Press again to leave redkite. That does not stop it: the build keeps running",
266
+ "on the host, may finish and tag an image no deploy is waiting for, and holds",
267
+ "the CPU and disk it is using. Nothing will clean up after it but you.",
268
+ ];
269
+ // A stopped deploy is not over until what it started is gone. The host is asked
270
+ // again and again because the answer is a count, and zero is the only one that
271
+ // ends this
272
+ async function gone(host, hardest, say) {
273
+ let said = 0;
274
+ for (let left = await host.stop(hardest()); left > 0; left = await host.stop(hardest())) {
275
+ if (left !== said) {
276
+ say(`Waiting for ${left} still running`);
277
+ said = left;
278
+ }
279
+ await new Promise((resolve) => setTimeout(resolve, POLL_MS));
280
+ }
281
+ }
282
+ const POLL_MS = 400;
283
+ // --local says it for this run alone, without the config having to change. It
284
+ // lands wherever the environment came from, so an inline one moves too
285
+ export function buildingHere(config, environment) {
286
+ if (config.environment) {
287
+ return { ...config, environment: { ...config.environment, buildOn: "local" } };
288
+ }
289
+ const declared = config.environments?.[environment];
290
+ if (!declared)
291
+ return config;
292
+ return {
293
+ ...config,
294
+ environments: {
295
+ ...config.environments,
296
+ [environment]: { ...declared, buildOn: "local" },
297
+ },
298
+ };
299
+ }
300
+ // Without a bastion the containers are on this machine, and every command the
301
+ // deploy issues is one this process can run itself
302
+ async function hostFor(host, log, signal) {
303
+ if (!host?.bastion)
304
+ return await localHost({ signal });
305
+ const task = log.step(`Opening a connection to ${host.bastion}`);
306
+ try {
307
+ const opened = await sshHost(host.bastion, { signal });
308
+ task.done();
309
+ return opened;
310
+ }
311
+ catch (error) {
312
+ task.fail(`Could not reach ${host.bastion}`);
313
+ throw error;
314
+ }
315
+ }
316
+ // Only the stores the config actually names. A deployment that keeps its
317
+ // environment somewhere else, or nowhere, needs no credentials to deploy
318
+ async function openStores(config, log) {
319
+ // Services name refs too, and a deployment whose only secret is a database
320
+ // password opened no store at all until this counted them
321
+ const refs = [
322
+ ...config.apps.flatMap((app) => [
323
+ ...listRefs(app.secrets),
324
+ ...Object.values(app.files ?? {}),
325
+ ]),
326
+ ...config.services.flatMap((service) => listRefs(service.secrets)),
327
+ ];
328
+ const providers = new Set(refs.map((ref) => ref.provider));
329
+ if (!providers.has("bitwarden"))
330
+ return {};
331
+ const vault = log.step("Reading the vault");
332
+ try {
333
+ const bitwarden = await bitwardenStore({
334
+ detail: vault.detail,
335
+ clientId: required("BW_CLIENT_ID"),
336
+ clientSecret: required("BW_CLIENT_SECRET"),
337
+ password: required("BW_PASSWORD"),
338
+ });
339
+ vault.done();
340
+ return { bitwarden };
341
+ }
342
+ catch (error) {
343
+ vault.fail("Could not read the vault");
344
+ throw error;
345
+ }
346
+ }
347
+ function required(name) {
348
+ const value = process.env[name];
349
+ if (value)
350
+ return value;
351
+ throw new Error(`${name} is not set, and this deployment reads its environment from Bitwarden`);
352
+ }
353
+ async function run(kind, environment, configPath, options) {
354
+ const config = await loadConfig(configPath);
355
+ // Fail on a missing environment before opening anything for it
356
+ const topology = topologyFor(config, environment);
357
+ const deployHost = environmentOf(config, environment)?.host;
358
+ // The host clones the repositories over this, so it has to exist before the
359
+ // connection that forwards it is opened. Before the view too: ssh-add asks
360
+ // for a passphrase on the terminal, and by then the view owns it
361
+ requireAgent((message) => process.stderr.write(`${message}\n`));
362
+ // Whatever is in flight is killed, the pipeline unwinds through its own
363
+ // failure path, and the finally below removes the scratch directory
364
+ const stopping = new AbortController();
365
+ const log = createLog({
366
+ ...options,
367
+ onQuit: () => stop(),
368
+ });
369
+ // Read by the wait below, so a press during it hardens what that is sending
370
+ let hardest = "TERM";
371
+ const stop = stopper({
372
+ say: log.warn,
373
+ abort: () => stopping.abort(),
374
+ signal: (name) => {
375
+ hardest = name;
376
+ // Nothing waits on this: the wait is in the finally, and this is what
377
+ // makes the command in flight answer so the run can get there
378
+ void host?.stop(name);
379
+ },
380
+ leave: () => {
381
+ log.warn("Leaving. What is still running on the host is yours to stop");
382
+ log.close();
383
+ process.exit(130);
384
+ },
385
+ });
386
+ // The viewer reads ctrl+c as a key, because it holds the terminal in raw
387
+ // mode. Everything else arrives here as a signal
388
+ process.on("SIGINT", stop);
389
+ let host;
390
+ try {
391
+ const meter = measured(await hostFor(deployHost, log, stopping.signal), options.verbose ? log : undefined);
392
+ host = meter.host;
393
+ const start = kind === "verify" ? verify : deploy;
394
+ const result = await start({
395
+ config: options.local ? buildingHere(config, environment) : config,
396
+ environment,
397
+ host,
398
+ secrets: await openStores(config, log),
399
+ verbose: options.verbose,
400
+ signal: stopping.signal,
401
+ log,
402
+ });
403
+ log(`Host: ${meter.summary()}`);
404
+ if (kind === "verify") {
405
+ log.done(`Checked ${result.checked.join(", ")} in ${topology.environment}`);
406
+ return;
407
+ }
408
+ if (result.ok) {
409
+ log.done(`Deployed ${result.released.join(", ")} to ${topology.environment}`);
410
+ return;
411
+ }
412
+ log.fail(`Reverted ${result.reverted.join(", ")}`);
413
+ process.exitCode = 1;
414
+ }
415
+ catch (error) {
416
+ // Whatever the command in flight said about being killed is noise: what
417
+ // happened is that somebody asked for it to stop
418
+ if (stopping.signal.aborted) {
419
+ log.fail("Stopped");
420
+ process.exitCode = 130;
421
+ }
422
+ else {
423
+ log.fail(describeFailure(error));
424
+ process.exitCode = 1;
425
+ }
426
+ }
427
+ finally {
428
+ // Nothing leaves while the build is still running. The signal a press
429
+ // chose is resent every time round, so pressing again hardens it
430
+ if (stopping.signal.aborted && host)
431
+ await gone(host, () => hardest, log.warn);
432
+ await host?.close?.();
433
+ // Leaves the alternate screen and writes the run out on the screen the
434
+ // person keeps, which is also what lets the process exit
435
+ log.close();
436
+ }
437
+ }
438
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type Viewer } from "./viewer.js";
2
+ export type LogOptions = {
3
+ verbose?: boolean;
4
+ full?: boolean;
5
+ onQuit?: () => void;
6
+ };
7
+ export declare function createLog(options?: LogOptions): Viewer;
8
+ export declare function describeFailure(error: unknown): string;
9
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/cli/log.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAYxD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF,wBAAgB,SAAS,CAAC,OAAO,GAAE,UAAe,GAAG,MAAM,CAU1D;AAqGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,UAU7C"}
@@ -0,0 +1,128 @@
1
+ import { elapsed as took } from "./screen.js";
2
+ import { createViewer } from "./viewer.js";
3
+ // What a deploy prints. The engine's own trace is a build graph with span ids
4
+ // and manifest resolution in it, which answers a question nobody deploying has.
5
+ const STAMP = 90;
6
+ const WARN = 33;
7
+ const FAIL = 31;
8
+ const DONE = 32;
9
+ const started = Date.now();
10
+ // A terminal gets the step viewer. Anything else, a pipe, a CI log or --full,
11
+ // gets one line per event, because there is nothing there to redraw
12
+ export function createLog(options = {}) {
13
+ if (viewable(process.stdout, process.stdin, options)) {
14
+ return createViewer(process.stdout, process.stdin, { onQuit: options.onQuit });
15
+ }
16
+ // --full is the reason to print a step's own output without asking for the
17
+ // host commands beside it, which is what --verbose adds
18
+ return Object.assign(plainLog(options.verbose === true || options.full === true), {
19
+ close: () => { },
20
+ });
21
+ }
22
+ function viewable(stream, input, options) {
23
+ if (options.full || process.env["REDKITE_PLAIN"])
24
+ return false;
25
+ return stream.isTTY === true && input.isTTY === true;
26
+ }
27
+ function plainLog(lines) {
28
+ const live = { write: (line) => process.stdout.write(line) };
29
+ const write = (stream, message, colour) => {
30
+ const painted = colours(stream);
31
+ const stamp = painted ? paint(elapsed(), STAMP) : elapsed();
32
+ const body = painted && colour ? paint(message, colour) : message;
33
+ const line = `${stamp} ${body}\n`;
34
+ // Both streams share one terminal, so the block has to come down for a
35
+ // failure on stderr just as it does for progress on stdout
36
+ if (stream === process.stdout)
37
+ return live.write(line);
38
+ live.write("");
39
+ stream.write(line);
40
+ };
41
+ const info = (message) => write(process.stdout, message);
42
+ const step = (label) => {
43
+ write(process.stdout, label);
44
+ const started = Date.now();
45
+ let current;
46
+ // A sub-step leaves the block when the next one starts, and lands here with
47
+ // what it cost. The live view stays short without the run losing its record
48
+ const settle = () => {
49
+ if (!current)
50
+ return;
51
+ write(process.stdout, ` ${label}: ${current.text} (${since(current.at)})`);
52
+ current = undefined;
53
+ };
54
+ const trace = (message) => {
55
+ settle();
56
+ current = { text: message, at: Date.now() };
57
+ write(process.stdout, ` ${label}: ${message}`);
58
+ };
59
+ return {
60
+ detail: trace,
61
+ // In full, never clipped: this is the view for reading what a build said
62
+ line: (message) => {
63
+ if (lines)
64
+ write(process.stdout, ` ${label} | ${message}`);
65
+ },
66
+ done: (message) => {
67
+ settle();
68
+ const suffix = message ? `: ${message}` : "";
69
+ write(process.stdout, `${label}${suffix} (${since(started)})`, DONE);
70
+ },
71
+ fail: (message) => {
72
+ settle();
73
+ write(process.stderr, `${message} (${since(started)})`, FAIL);
74
+ },
75
+ };
76
+ };
77
+ return Object.assign(info, {
78
+ warn: (message) => write(process.stdout, message, WARN),
79
+ // Failures go to stderr, so a piped log still carries the progress alone
80
+ fail: (message) => write(process.stderr, message, FAIL),
81
+ done: (message) => write(process.stdout, message, DONE),
82
+ step,
83
+ });
84
+ }
85
+ function paint(text, colour) {
86
+ return `\u001b[${colour}m${text}\u001b[0m`;
87
+ }
88
+ // A file or a pipe takes the text without the escapes, and NO_COLOR is a
89
+ // standing instruction rather than a preference to re-ask about
90
+ function colours(stream) {
91
+ if (process.env["NO_COLOR"])
92
+ return false;
93
+ return stream.isTTY === true;
94
+ }
95
+ function elapsed() {
96
+ return `[${took(Date.now(), started, true)}]`;
97
+ }
98
+ function since(at) {
99
+ return took(Date.now(), at);
100
+ }
101
+ const TAIL = 20;
102
+ // A failure carries the tail of whatever the command wrote, and a build writes
103
+ // a lot. The chain matters because a step wraps the command it ran
104
+ export function describeFailure(error) {
105
+ if (!(error instanceof Error))
106
+ return String(error);
107
+ // A wrapper that already quotes what it wrapped must not say it twice
108
+ const chain = causes(error).map((link) => link.message);
109
+ const said = chain.filter((message, index) => !chain.slice(0, index).some((earlier) => earlier.includes(message)));
110
+ return tail(said.join("\n"));
111
+ }
112
+ const DEPTH = 8;
113
+ function causes(error) {
114
+ const chain = [];
115
+ let current = error;
116
+ while (current instanceof Error && chain.length < DEPTH) {
117
+ chain.push(current);
118
+ current = current.cause;
119
+ }
120
+ return chain;
121
+ }
122
+ function tail(body) {
123
+ const lines = body.split("\n");
124
+ if (lines.length <= TAIL)
125
+ return body;
126
+ return [`... ${lines.length - TAIL} earlier lines`, ...lines.slice(-TAIL)].join("\n");
127
+ }
128
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/cli/log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export type StepState = "running" | "done" | "failed";
2
+ export type Step = {
3
+ label: string;
4
+ started: number;
5
+ ended?: number;
6
+ state: StepState;
7
+ note?: string;
8
+ detail?: string;
9
+ lines: string[];
10
+ expanded: boolean;
11
+ held: boolean;
12
+ offset: number;
13
+ };
14
+ export type Model = {
15
+ steps: Step[];
16
+ messages: string[];
17
+ cursor: number;
18
+ following: boolean;
19
+ minimal: boolean;
20
+ rows: number;
21
+ columns: number;
22
+ started: number;
23
+ now: number;
24
+ };
25
+ export type Key = "up" | "down" | "latest" | "first" | "toggle" | "expand" | "collapse" | "quit";
26
+ export declare function emptyModel(rows: number, columns: number, now: number): Model;
27
+ export declare function keysOf(data: string): Key[];
28
+ export declare function keyOf(data: string): Key | undefined;
29
+ export declare function apply(model: Model, key: Key): Model;
30
+ export declare const HELP = "\u2191\u2193 move \u00B7 enter open \u00B7 shift+\u2191 latest \u00B7 + open \u00B7 - collapse all \u00B7 q quit";
31
+ export declare function render(model: Model, colour?: boolean): string[];
32
+ export declare function clip(text: string, room: number): string;
33
+ export declare function elapsed(now: number, started: number, clock?: boolean): string;
34
+ //# sourceMappingURL=screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/cli/screen.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,GAAG;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IAEjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,IAAI,EAAE,OAAO,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IAEf,SAAS,EAAE,OAAO,CAAC;IAEnB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,GAAG,GACX,IAAI,GACJ,MAAM,GACN,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,MAAM,CAAC;AAEX,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAY5E;AAOD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE,CAe1C;AAID,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAWnD;AAID,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,KAAK,CAgEnD;AA6DD,eAAO,MAAM,IAAI,qHACmG,CAAC;AAErH,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,UAAQ,GAAG,MAAM,EAAE,CAyC7D;AAyDD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAG9C;AAqDD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,UAAQ,UAQlE"}