redkite 0.1.12 → 0.1.14
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/README.md +62 -8
- package/dist/cli/agent.d.ts +5 -1
- package/dist/cli/agent.d.ts.map +1 -1
- package/dist/cli/agent.js +7 -7
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/crash.js +4 -2
- package/dist/cli/crash.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +18 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/log.d.ts.map +1 -1
- package/dist/cli/log.js +3 -2
- package/dist/cli/log.js.map +1 -1
- package/dist/cli/screen.d.ts +3 -0
- package/dist/cli/screen.d.ts.map +1 -1
- package/dist/cli/screen.js +32 -6
- package/dist/cli/screen.js.map +1 -1
- package/dist/cli/viewer.d.ts.map +1 -1
- package/dist/cli/viewer.js +5 -5
- package/dist/cli/viewer.js.map +1 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +6 -3
- package/dist/deploy.js.map +1 -1
- package/dist/health.d.ts +2 -2
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +17 -9
- package/dist/health.js.map +1 -1
- package/dist/log.d.ts +3 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +13 -0
- package/dist/log.js.map +1 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/proxy.d.ts +5 -0
- package/dist/services/proxy.d.ts.map +1 -1
- package/dist/services/proxy.js +56 -2
- package/dist/services/proxy.js.map +1 -1
- package/dist/source.d.ts +2 -0
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +20 -0
- package/dist/source.js.map +1 -1
- package/dist/topology.d.ts.map +1 -1
- package/dist/topology.js +8 -1
- package/dist/topology.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/agent.ts +8 -8
- package/src/cli/crash.ts +4 -3
- package/src/cli/index.ts +21 -9
- package/src/cli/log.ts +3 -2
- package/src/cli/screen.ts +45 -4
- package/src/cli/viewer.ts +5 -4
- package/src/deploy.ts +7 -4
- package/src/health.ts +23 -16
- package/src/log.ts +19 -1
- package/src/services/index.ts +3 -0
- package/src/services/proxy.ts +71 -3
- package/src/source.ts +24 -0
- package/src/topology.ts +9 -1
- package/src/types.ts +18 -0
package/dist/source.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQtC,MAAM,MAAM,MAAM,GAAG;IAGnB,OAAO,EAAE,MAAM,CAAC;IAEhB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAIF,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC;AAElD,MAAM,MAAM,GAAG,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG;IAG1B,IAAI,EAAE,MAAM,CAAC;IAEb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,GAAG,CAAC;IACT,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAGnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAmBF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,UAMxC;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,UAEnC;AAKD,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAKjB"}
|
package/dist/source.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tag } from "./log.js";
|
|
1
2
|
// Where each kind lives. A tag is peeled, so an annotated one answers with the
|
|
2
3
|
// commit it points at rather than with the tag object
|
|
3
4
|
const REVISION = {
|
|
@@ -5,6 +6,25 @@ const REVISION = {
|
|
|
5
6
|
tag: (name) => `refs/tags/${name}^{commit}`,
|
|
6
7
|
commit: (name) => `${name}^{commit}`,
|
|
7
8
|
};
|
|
9
|
+
// Hosts common enough to be worth a tag in place of their name
|
|
10
|
+
const HOSTS = { "github.com": "GH" };
|
|
11
|
+
// user@host:path, or scheme://user@host/path, with the .git every clone URL ends
|
|
12
|
+
// in. Anything that is not one of those, a directory for instance, has no host
|
|
13
|
+
const REMOTE = /^(?:[a-z][a-z0-9+.-]*:\/\/)?(?:[^@/]+@)?([^:/]+)[:/](.+?)(?:\.git)?\/?$/;
|
|
14
|
+
// How a repository is named on screen: the host as a tag where it is a known
|
|
15
|
+
// one, and the path without the .git that says nothing a person needs
|
|
16
|
+
export function describeRepo(repo) {
|
|
17
|
+
const match = REMOTE.exec(repo);
|
|
18
|
+
if (!match?.[1] || !match[2])
|
|
19
|
+
return repo.replace(/\.git$/, "");
|
|
20
|
+
const known = HOSTS[match[1]];
|
|
21
|
+
return known ? `${tag(known)} ${match[2]}` : `${match[1]}:${match[2]}`;
|
|
22
|
+
}
|
|
23
|
+
// A branch is what is tracked nearly always, so it goes by its name alone. A tag
|
|
24
|
+
// or a commit is a pin, and says which kind it is
|
|
25
|
+
export function describeRef(ref) {
|
|
26
|
+
return ref.kind === "branch" ? ref.name : `${ref.kind} ${ref.name}`;
|
|
27
|
+
}
|
|
8
28
|
// accept-new rather than no: a host key that changes is still worth refusing
|
|
9
29
|
const GIT_SSH = "ssh -o StrictHostKeyChecking=accept-new";
|
|
10
30
|
export async function prepareSource(host, request) {
|
package/dist/source.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.js","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"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"}
|
package/dist/topology.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topology.d.ts","sourceRoot":"","sources":["../src/topology.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,UAAU,EAAe,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"topology.d.ts","sourceRoot":"","sources":["../src/topology.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,UAAU,EAAe,MAAM,YAAY,CAAC;AAenE,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IAEb,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAE5B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAkD7E"}
|
package/dist/topology.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { environmentOf } from "./config.js";
|
|
2
2
|
import { mountFor } from "./layout.js";
|
|
3
|
+
import { logMount } from "./services/proxy.js";
|
|
3
4
|
// Every name and address the deployment uses, derived from the app list. This
|
|
4
5
|
// is the file that replaces the constants block: nothing is chosen by hand, so
|
|
5
6
|
// adding an app cannot collide with an address somebody already picked.
|
|
@@ -34,7 +35,9 @@ export function topologyFor(config, environment) {
|
|
|
34
35
|
name: "nginx",
|
|
35
36
|
container: `${prefix}-nginx`,
|
|
36
37
|
address: address(NGINX_OCTET),
|
|
37
|
-
|
|
38
|
+
// Only a directory the deployment named. Nothing mounted otherwise, so a
|
|
39
|
+
// proxy that says nothing about its logs is the container it always was
|
|
40
|
+
volumes: routerVolumes(config),
|
|
38
41
|
},
|
|
39
42
|
apps,
|
|
40
43
|
services,
|
|
@@ -88,6 +91,10 @@ function serviceTopology(service, prefix, address, index) {
|
|
|
88
91
|
})),
|
|
89
92
|
};
|
|
90
93
|
}
|
|
94
|
+
function routerVolumes(config) {
|
|
95
|
+
const logs = logMount(config.proxy);
|
|
96
|
+
return logs ? [logs] : [];
|
|
97
|
+
}
|
|
91
98
|
// Nginx resolves upstreams by container name, apps reach services by alias
|
|
92
99
|
function extraHosts(apps, services, declared = {}) {
|
|
93
100
|
const hosts = {};
|
package/dist/topology.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topology.js","sourceRoot":"","sources":["../src/topology.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"topology.js","sourceRoot":"","sources":["../src/topology.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -30,6 +30,13 @@ export type ProxySpec = {
|
|
|
30
30
|
maxBodySize?: string;
|
|
31
31
|
server?: string[];
|
|
32
32
|
location?: string[];
|
|
33
|
+
locations?: Record<string, string[]>;
|
|
34
|
+
logs?: false | ProxyLogs;
|
|
35
|
+
};
|
|
36
|
+
export type ProxyLogs = {
|
|
37
|
+
directory?: string;
|
|
38
|
+
access?: boolean;
|
|
39
|
+
errors?: "debug" | "info" | "notice" | "warn" | "error" | "crit" | "alert" | "emerg";
|
|
33
40
|
};
|
|
34
41
|
export type ServiceSpec = {
|
|
35
42
|
name: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,MAAM,MAAM,WAAW,GAAG;IAKxB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,EAAE,MAAM,CAAC;IAIf,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAIlB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAIpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAErC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAIlD,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAMF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAI7E,MAAM,MAAM,QAAQ,GAGhB,YAAY,GAGZ,QAAQ,GAGR,KAAK,CAAC;AAEV,MAAM,MAAM,UAAU,GAAG;IAEvB,OAAO,EAAE,MAAM,CAAC;IAEhB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAIF,MAAM,MAAM,SAAS,GAAG;IAEtB,QAAQ,EAAE,MAAM,CAAC;IAEjB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;AAKjD,MAAM,MAAM,SAAS,GAAG;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAGlB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli/agent.ts
CHANGED
|
@@ -21,14 +21,14 @@ function overSsh(repo: string) {
|
|
|
21
21
|
return !/^(https?|git|file):\/\//.test(repo);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
// ssh-add may ask for a passphrase, and it cannot ask through a screen
|
|
26
|
-
// something else is drawing
|
|
27
|
-
export function requireAgent(warn: (message: string) => void) {
|
|
28
|
-
const existing = process.env["SSH_AUTH_SOCK"];
|
|
29
|
-
if (existing) return existing;
|
|
24
|
+
export const AGENT_STARTED = "no SSH agent was running, so one was started";
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
// Runs before the view opens, because ssh-add may ask for a passphrase and it
|
|
27
|
+
// cannot ask through a screen something else is drawing. Whether one was started
|
|
28
|
+
// is answered rather than said, so the step that opens the connection says it
|
|
29
|
+
export function requireAgent() {
|
|
30
|
+
const existing = process.env["SSH_AUTH_SOCK"];
|
|
31
|
+
if (existing) return { socket: existing, started: false };
|
|
32
32
|
|
|
33
33
|
const output = execFileSync("ssh-agent", ["-s"], { encoding: "utf8" });
|
|
34
34
|
const socket = output.match(/SSH_AUTH_SOCK=([^;]+);/)?.[1];
|
|
@@ -51,5 +51,5 @@ export function requireAgent(warn: (message: string) => void) {
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
return socket;
|
|
54
|
+
return { socket, started: true };
|
|
55
55
|
}
|
package/src/cli/crash.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
|
|
4
|
-
import type
|
|
4
|
+
import { untagged, type Task } from "../log.js";
|
|
5
5
|
import type { Deployment } from "../types.js";
|
|
6
6
|
import { elapsed } from "./screen.js";
|
|
7
7
|
import { causes } from "./log.js";
|
|
@@ -259,9 +259,10 @@ function lines(rows: string[]) {
|
|
|
259
259
|
return `${rows.join("\n")}\n`;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
// Continuation lines line up under the text rather than under the timestamp
|
|
262
|
+
// Continuation lines line up under the text rather than under the timestamp. A
|
|
263
|
+
// file cannot draw a tag, so it gets the bracketed word
|
|
263
264
|
function indent(text: string) {
|
|
264
|
-
return text.replaceAll("\n", "\n ");
|
|
265
|
+
return untagged(text).replaceAll("\n", "\n ");
|
|
265
266
|
}
|
|
266
267
|
|
|
267
268
|
function slug(text: string) {
|
package/src/cli/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { sshHost } from "../sshHost.js";
|
|
|
14
14
|
import { topologyFor, type Topology } from "../topology.js";
|
|
15
15
|
import type { Deployment, DeployHost } from "../types.js";
|
|
16
16
|
|
|
17
|
-
import { needsAgent, requireAgent } from "./agent.js";
|
|
17
|
+
import { AGENT_STARTED, needsAgent, requireAgent } from "./agent.js";
|
|
18
18
|
import { loadConfig, projectRoot } from "./config.js";
|
|
19
19
|
import { loadDotenv } from "./dotenv.js";
|
|
20
20
|
import { dumpCrash, recording } from "./crash.js";
|
|
@@ -181,7 +181,9 @@ async function recover(
|
|
|
181
181
|
const deployHost = environmentOf(config, environment)?.host;
|
|
182
182
|
|
|
183
183
|
const say = (message = "") => process.stdout.write(`${message}\n`);
|
|
184
|
-
|
|
184
|
+
// Printed rather than drawn: a recovery has no view, and its connection
|
|
185
|
+
// step is silent
|
|
186
|
+
if (needsAgent(config, environment) && requireAgent().started) say(AGENT_STARTED);
|
|
185
187
|
|
|
186
188
|
const host = await hostFor(deployHost, silent);
|
|
187
189
|
|
|
@@ -485,14 +487,26 @@ export function buildingHere(config: Deployment, environment: string): Deploymen
|
|
|
485
487
|
|
|
486
488
|
// Without a bastion the containers are on this machine, and every command the
|
|
487
489
|
// deploy issues is one this process can run itself
|
|
488
|
-
async function hostFor(
|
|
489
|
-
|
|
490
|
+
async function hostFor(
|
|
491
|
+
host: DeployHost | undefined,
|
|
492
|
+
log: Log,
|
|
493
|
+
signal?: AbortSignal,
|
|
494
|
+
startedAgent = false,
|
|
495
|
+
) {
|
|
496
|
+
if (!host?.bastion) {
|
|
497
|
+
// No connection to say it in. A run on this machine that clones over ssh
|
|
498
|
+
// still started one, and that is still worth knowing
|
|
499
|
+
if (startedAgent) log.warn(AGENT_STARTED);
|
|
500
|
+
return await localHost({ signal });
|
|
501
|
+
}
|
|
490
502
|
|
|
491
503
|
const task = log.step(`Opening a connection to ${host.bastion}`);
|
|
504
|
+
if (startedAgent) task.detail(AGENT_STARTED);
|
|
492
505
|
|
|
493
506
|
try {
|
|
494
507
|
const opened = await sshHost(host.bastion, { signal, hostKeys: host.hostKeys });
|
|
495
|
-
|
|
508
|
+
// Kept on the row once the connection is open, not only while it opens
|
|
509
|
+
task.done(startedAgent ? AGENT_STARTED : undefined);
|
|
496
510
|
return opened;
|
|
497
511
|
} catch (error) {
|
|
498
512
|
task.fail(`Could not reach ${host.bastion}`);
|
|
@@ -561,9 +575,7 @@ async function run(
|
|
|
561
575
|
// The host clones the repositories over this, so it has to exist before the
|
|
562
576
|
// connection that forwards it is opened. Before the view too: ssh-add asks
|
|
563
577
|
// for a passphrase on the terminal, and by then the view owns it
|
|
564
|
-
|
|
565
|
-
requireAgent((message) => process.stderr.write(`${message}\n`));
|
|
566
|
-
}
|
|
578
|
+
const agent = needsAgent(config, environment) ? requireAgent() : undefined;
|
|
567
579
|
|
|
568
580
|
// Whatever is in flight is killed, the pipeline unwinds through its own
|
|
569
581
|
// failure path, and the finally below removes the scratch directory
|
|
@@ -629,7 +641,7 @@ async function run(
|
|
|
629
641
|
|
|
630
642
|
try {
|
|
631
643
|
const meter = measured(
|
|
632
|
-
await hostFor(deployHost, log, stopping.signal),
|
|
644
|
+
await hostFor(deployHost, log, stopping.signal, agent?.started),
|
|
633
645
|
options.verbose ? log : recorder.command,
|
|
634
646
|
);
|
|
635
647
|
|
package/src/cli/log.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Task } from "../log.js";
|
|
2
2
|
|
|
3
|
-
import { elapsed as took } from "./screen.js";
|
|
3
|
+
import { paintTags, elapsed as took } from "./screen.js";
|
|
4
4
|
import { createViewer, type Viewer } from "./viewer.js";
|
|
5
5
|
|
|
6
6
|
// What a deploy prints. The engine's own trace is a build graph with span ids
|
|
@@ -48,7 +48,8 @@ function plainLog(lines: boolean) {
|
|
|
48
48
|
const write = (stream: NodeJS.WriteStream, message: string, colour?: number) => {
|
|
49
49
|
const painted = colours(stream);
|
|
50
50
|
const stamp = painted ? paint(elapsed(), STAMP) : elapsed();
|
|
51
|
-
|
|
51
|
+
// A tag is drawn where there is colour and bracketed where there is not
|
|
52
|
+
const body = paintTags(message, painted, colour);
|
|
52
53
|
const line = `${stamp} ${body}\n`;
|
|
53
54
|
|
|
54
55
|
// Both streams share one terminal, so the block has to come down for a
|
package/src/cli/screen.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TAGS, untagged } from "../log.js";
|
|
2
|
+
|
|
1
3
|
// The deploy as a list of collapsibles. A step is a title and the lines it
|
|
2
4
|
// produced; the one running is open, the ones finished are shut, and the person
|
|
3
5
|
// watching moves between them. The model and the renderer are pure, so what the
|
|
@@ -199,14 +201,53 @@ const RUNNING = 93;
|
|
|
199
201
|
const DONE = 32;
|
|
200
202
|
const FAILED = 91;
|
|
201
203
|
const WARN = 33;
|
|
204
|
+
// A tag is a blue label with rounded ends: the ends in blue on the terminal's own
|
|
205
|
+
// ground, and the word white on blue between them
|
|
206
|
+
const TAG_EDGE = 34;
|
|
207
|
+
const TAG_BODY = "97;44";
|
|
208
|
+
|
|
209
|
+
type Colour = number | string;
|
|
202
210
|
|
|
203
|
-
type Piece = { text: string; colour?:
|
|
211
|
+
type Piece = { text: string; colour?: Colour };
|
|
204
212
|
|
|
205
|
-
function paint(text: string, colour:
|
|
213
|
+
function paint(text: string, colour: Colour | undefined, on: boolean) {
|
|
206
214
|
if (!on || colour === undefined || text === "") return text;
|
|
207
215
|
return `\u001b[${colour}m${text}\u001b[0m`;
|
|
208
216
|
}
|
|
209
217
|
|
|
218
|
+
// Text that may carry a tag, as pieces, so the row is measured before any escape
|
|
219
|
+
// is added. The rounded ends are a column each, the same as the brackets drawn
|
|
220
|
+
// in their place without colour, so a row is the same width either way
|
|
221
|
+
function tagged(text: string, colour: Colour | undefined, on: boolean): Piece[] {
|
|
222
|
+
if (!on) return [{ text: untagged(text), colour }];
|
|
223
|
+
|
|
224
|
+
const pieces: Piece[] = [];
|
|
225
|
+
let at = 0;
|
|
226
|
+
|
|
227
|
+
for (const match of text.matchAll(TAGS)) {
|
|
228
|
+
if (match.index > at) pieces.push({ text: text.slice(at, match.index), colour });
|
|
229
|
+
|
|
230
|
+
pieces.push(
|
|
231
|
+
{ text: "\u25d6", colour: TAG_EDGE },
|
|
232
|
+
{ text: match[1] ?? "", colour: TAG_BODY },
|
|
233
|
+
{ text: "\u25d7", colour: TAG_EDGE },
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
at = match.index + match[0].length;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (at < text.length) pieces.push({ text: text.slice(at), colour });
|
|
240
|
+
return pieces;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// For what is written as a whole line rather than drawn into a row: the summary
|
|
244
|
+
// left on the screen, and the plain log. The line's own colour resumes after
|
|
245
|
+
export function paintTags(text: string, on: boolean, colour?: Colour) {
|
|
246
|
+
return tagged(text, colour, on)
|
|
247
|
+
.map((piece) => paint(piece.text, piece.colour, on))
|
|
248
|
+
.join("");
|
|
249
|
+
}
|
|
250
|
+
|
|
210
251
|
function widthOf(pieces: Piece[]) {
|
|
211
252
|
return pieces.reduce((total, piece) => total + piece.text.length, 0);
|
|
212
253
|
}
|
|
@@ -362,7 +403,7 @@ function said(model: Model, message: Message, colour: boolean) {
|
|
|
362
403
|
[
|
|
363
404
|
{ text: gutter(model, message.at), colour: DIM },
|
|
364
405
|
{ text: " " },
|
|
365
|
-
|
|
406
|
+
...tagged(message.text, WARN, colour),
|
|
366
407
|
],
|
|
367
408
|
Math.max(24, model.columns),
|
|
368
409
|
colour,
|
|
@@ -485,7 +526,7 @@ function title(model: Model, step: Step, index: number, colour: boolean) {
|
|
|
485
526
|
{ text: glyph, colour: stateColour(step) },
|
|
486
527
|
{ text: " " },
|
|
487
528
|
{ text: step.label, colour: labelColour(step, selected) },
|
|
488
|
-
|
|
529
|
+
...tagged(said, DIM, colour),
|
|
489
530
|
{ text: quiet(model, step), colour: WARN },
|
|
490
531
|
];
|
|
491
532
|
|
package/src/cli/viewer.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
elapsed,
|
|
6
6
|
emptyModel,
|
|
7
7
|
keysOf,
|
|
8
|
+
paintTags,
|
|
8
9
|
render,
|
|
9
10
|
type Model,
|
|
10
11
|
type Step,
|
|
@@ -113,7 +114,7 @@ export function createViewer(
|
|
|
113
114
|
stream.write(ALTERNATE_OFF);
|
|
114
115
|
// The alternate screen takes every frame with it, so the run has to be
|
|
115
116
|
// written again on the screen the person keeps
|
|
116
|
-
for (const line of summary(model)) stream.write(`${line}\n`);
|
|
117
|
+
for (const line of summary(model, colour)) stream.write(`${line}\n`);
|
|
117
118
|
};
|
|
118
119
|
|
|
119
120
|
// What a second press means is not the view's to decide: the same key
|
|
@@ -191,18 +192,18 @@ export function createViewer(
|
|
|
191
192
|
|
|
192
193
|
// One line per step and whatever was said outside them, which is the record a
|
|
193
194
|
// person scrolls back to after the deploy is over
|
|
194
|
-
function summary(model: Model): string[] {
|
|
195
|
+
function summary(model: Model, colour: boolean): string[] {
|
|
195
196
|
const rows = model.steps.map((step) => {
|
|
196
197
|
const glyph = step.state === "done" ? "✔" : step.state === "failed" ? "✘" : "·";
|
|
197
198
|
const said = step.note ? `: ${step.note}` : "";
|
|
198
199
|
const took = elapsed(step.ended ?? model.now, step.started);
|
|
199
200
|
|
|
200
|
-
return `${glyph} ${step.label}${said} (${took})
|
|
201
|
+
return paintTags(`${glyph} ${step.label}${said} (${took})`, colour);
|
|
201
202
|
});
|
|
202
203
|
|
|
203
204
|
return [
|
|
204
205
|
...rows,
|
|
205
|
-
...model.messages.map((message) => message.text),
|
|
206
|
+
...model.messages.map((message) => paintTags(message.text, colour)),
|
|
206
207
|
...whatFailed(model),
|
|
207
208
|
];
|
|
208
209
|
}
|
package/src/deploy.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { pluginSteps } from "./plugin.js";
|
|
|
26
26
|
import { readEnv, readRef, type SecretStores } from "./secrets/refs.js";
|
|
27
27
|
import { ensureService } from "./services/ensure.js";
|
|
28
28
|
import { plannedServices } from "./services/planned.js";
|
|
29
|
-
import type
|
|
29
|
+
import { describeRef, describeRepo, type Source } from "./source.js";
|
|
30
30
|
import { topologyFor, type AppTopology, type Topology } from "./topology.js";
|
|
31
31
|
import type { AppSpec, Deployment } from "./types.js";
|
|
32
32
|
|
|
@@ -305,13 +305,16 @@ async function checkAll(context: Context, health: Omit<HealthDeps, "probe">) {
|
|
|
305
305
|
const results = await Promise.all(
|
|
306
306
|
context.config.apps.map(async (app) => {
|
|
307
307
|
const target = appOf(topology, app.name);
|
|
308
|
+
|
|
309
|
+
// A step of its own for each app, rather than lines said beside the swap:
|
|
310
|
+
// every attempt lands on it, and a crash log gives it a file
|
|
308
311
|
const deps: HealthDeps = {
|
|
309
312
|
...health,
|
|
310
313
|
probe: async (container, url) => {
|
|
311
314
|
const result = await docker.run(`exec ${container} curl -s ${url}`);
|
|
312
315
|
return { code: result.code, output: result.stdout };
|
|
313
316
|
},
|
|
314
|
-
log,
|
|
317
|
+
task: log.step(`Health check of ${app.name}`),
|
|
315
318
|
};
|
|
316
319
|
|
|
317
320
|
const healthy = await healthcheck(target.container, target.port, app.health, deps);
|
|
@@ -444,7 +447,7 @@ async function clone(
|
|
|
444
447
|
if (!app.repo) return undefined;
|
|
445
448
|
|
|
446
449
|
const ref = refOf(app, branch);
|
|
447
|
-
const what = `${app.repo}
|
|
450
|
+
const what = `${describeRepo(app.repo)} ${describeRef(ref)}`;
|
|
448
451
|
const task = log.step(`Cloning ${app.name}`);
|
|
449
452
|
|
|
450
453
|
try {
|
|
@@ -457,7 +460,7 @@ async function clone(
|
|
|
457
460
|
});
|
|
458
461
|
|
|
459
462
|
// Said again at the end, where it outlasts the details that replaced it
|
|
460
|
-
task.done(`${what}
|
|
463
|
+
task.done(`${what} -> ${source.release.slice(0, 7)}`);
|
|
461
464
|
return source;
|
|
462
465
|
} catch (error) {
|
|
463
466
|
task.fail(`${app.name} could not clone ${what}`);
|
package/src/health.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { silent, type
|
|
1
|
+
import { silent, type Task } from "./log.js";
|
|
2
2
|
import type { HealthSpec } from "./types.js";
|
|
3
3
|
|
|
4
4
|
const RETRIES = 10;
|
|
@@ -16,7 +16,9 @@ export type Probe = (
|
|
|
16
16
|
export type HealthDeps = {
|
|
17
17
|
probe: Probe;
|
|
18
18
|
sleep: (ms: number) => Promise<void>;
|
|
19
|
-
|
|
19
|
+
// The step the check reports on. Every attempt is said on it, so a check that
|
|
20
|
+
// gave up shows what the container answered each time rather than only that
|
|
21
|
+
task?: Task;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
// One loop for every app. The two copies it replaces had already drifted: the
|
|
@@ -30,22 +32,28 @@ export async function healthcheck(
|
|
|
30
32
|
): Promise<boolean> {
|
|
31
33
|
const retries = spec.retries ?? RETRIES;
|
|
32
34
|
const ceiling = spec.intervalMs ?? INTERVAL_MS;
|
|
33
|
-
const
|
|
35
|
+
const task = deps.task ?? silent.step("");
|
|
34
36
|
const delay = spec.delayMs ?? DELAY_MS;
|
|
37
|
+
const url = `localhost:${port}${spec.path}`;
|
|
35
38
|
|
|
39
|
+
task.detail(`probing ${container} at ${url}`);
|
|
36
40
|
if (delay > 0) await deps.sleep(delay);
|
|
37
41
|
|
|
38
42
|
let backoff = FIRST_BACKOFF_MS;
|
|
39
43
|
|
|
40
44
|
for (let attempt = 1; attempt <= retries; attempt += 1) {
|
|
41
|
-
const url = `localhost:${port}${spec.path}`;
|
|
42
45
|
const { code, output } = await deps.probe(container, url);
|
|
46
|
+
const said = (message: string) => task.detail(`attempt ${attempt} of ${retries}: ${message}`);
|
|
43
47
|
|
|
44
|
-
if (code === 0 && passes(spec, output,
|
|
45
|
-
|
|
48
|
+
if (code === 0 && passes(spec, output, said)) {
|
|
49
|
+
task.done(`${container} healthy after ${attempt} ${attempt === 1 ? "attempt" : "attempts"}`);
|
|
46
50
|
return true;
|
|
47
51
|
}
|
|
48
52
|
|
|
53
|
+
// Nothing answered at all, which is a container still starting or one that
|
|
54
|
+
// is listening somewhere other than where the check asks
|
|
55
|
+
if (code !== 0) said(`no answer on ${url}`);
|
|
56
|
+
|
|
49
57
|
if (attempt === retries) break;
|
|
50
58
|
|
|
51
59
|
// Doubling from a quarter second means a container that starts quickly
|
|
@@ -54,30 +62,29 @@ export async function healthcheck(
|
|
|
54
62
|
backoff = Math.min(backoff * 2, ceiling);
|
|
55
63
|
}
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
task.fail(`${container} unhealthy after ${retries} attempts`);
|
|
58
66
|
return false;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
// A body that parses but fails the predicate is a retry, not a verdict. The
|
|
62
70
|
// container may still be warming up, and the caller has a retry budget for it
|
|
63
|
-
function passes(
|
|
64
|
-
spec: HealthSpec,
|
|
65
|
-
output: string,
|
|
66
|
-
log: Log,
|
|
67
|
-
container: string,
|
|
68
|
-
) {
|
|
71
|
+
function passes(spec: HealthSpec, output: string, said: (message: string) => void) {
|
|
69
72
|
let body: unknown;
|
|
70
73
|
|
|
71
74
|
try {
|
|
72
75
|
body = JSON.parse(output);
|
|
73
76
|
} catch {
|
|
74
|
-
|
|
77
|
+
said(`answered with something that is not JSON: ${output}`);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (typeof body !== "object" || body === null) {
|
|
82
|
+
said(`answered with JSON that is not an object: ${output}`);
|
|
75
83
|
return false;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
if (typeof body !== "object" || body === null) return false;
|
|
79
86
|
if (spec.expect(body as Record<string, unknown>)) return true;
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
said(`not healthy yet: ${output}`);
|
|
82
89
|
return false;
|
|
83
90
|
}
|
package/src/log.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
// The shape progress is reported through. The library only knows this much, so
|
|
2
2
|
// a deploy driven from somewhere without a terminal supplies its own.
|
|
3
3
|
|
|
4
|
+
// A short label a terminal can draw as a tag, such as the host a repository
|
|
5
|
+
// lives on. Marked with private-use characters, which nothing a command prints
|
|
6
|
+
// uses, so a log finds one without guessing at brackets somebody typed
|
|
7
|
+
const TAG_OPEN = "\uE000";
|
|
8
|
+
const TAG_CLOSE = "\uE001";
|
|
9
|
+
|
|
10
|
+
export const TAGS = /\uE000([^\uE000\uE001]*)\uE001/g;
|
|
11
|
+
|
|
12
|
+
export function tag(label: string) {
|
|
13
|
+
return `${TAG_OPEN}${label}${TAG_CLOSE}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// For a log that has no way to draw one: a file, a pipe, a CI log
|
|
17
|
+
export function untagged(text: string) {
|
|
18
|
+
return text.replaceAll(TAGS, "[$1]");
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
// Work that is still running. Announced when it starts, because the thing worth
|
|
5
|
-
// knowing during a four minute build is which step is the four minutes
|
|
22
|
+
// knowing during a four minute build is which step is the four minutes. What it
|
|
23
|
+
// says may carry a tag, which a log that draws plain text passes through untagged
|
|
6
24
|
export type Task = {
|
|
7
25
|
// What the step is doing right now, replacing whatever it said before
|
|
8
26
|
detail(message: string): void;
|
package/src/services/index.ts
CHANGED
|
@@ -9,6 +9,9 @@ export function nginx(options: ProxySpec = {}): ProxySpec {
|
|
|
9
9
|
maxBodySize: options.maxBodySize ?? "1M",
|
|
10
10
|
server: options.server ?? [],
|
|
11
11
|
location: options.location ?? [],
|
|
12
|
+
locations: options.locations ?? {},
|
|
13
|
+
// Carried as given: absent and false mean different things
|
|
14
|
+
logs: options.logs,
|
|
12
15
|
};
|
|
13
16
|
}
|
|
14
17
|
|