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.
- package/LICENSE +21 -0
- package/README.md +819 -0
- package/bin/redkite.mjs +12 -0
- package/dist/build.d.ts +27 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +132 -0
- package/dist/build.js.map +1 -0
- package/dist/checks.d.ts +4 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +49 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli/agent.d.ts +2 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +24 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +217 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +438 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/log.d.ts +9 -0
- package/dist/cli/log.d.ts.map +1 -0
- package/dist/cli/log.js +128 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/screen.d.ts +34 -0
- package/dist/cli/screen.d.ts.map +1 -0
- package/dist/cli/screen.js +298 -0
- package/dist/cli/screen.js.map +1 -0
- package/dist/cli/viewer.d.ts +9 -0
- package/dist/cli/viewer.d.ts.map +1 -0
- package/dist/cli/viewer.js +139 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +79 -0
- package/dist/config.js.map +1 -0
- package/dist/deploy.d.ts +19 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +275 -0
- package/dist/deploy.js.map +1 -0
- package/dist/docker.d.ts +96 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +325 -0
- package/dist/docker.js.map +1 -0
- package/dist/dockerfile.d.ts +14 -0
- package/dist/dockerfile.d.ts.map +1 -0
- package/dist/dockerfile.js +160 -0
- package/dist/dockerfile.js.map +1 -0
- package/dist/health.d.ts +13 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +54 -0
- package/dist/health.js.map +1 -0
- package/dist/host.d.ts +21 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +27 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +5 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +45 -0
- package/dist/layout.js.map +1 -0
- package/dist/localHost.d.ts +7 -0
- package/dist/localHost.d.ts.map +1 -0
- package/dist/localHost.js +32 -0
- package/dist/localHost.js.map +1 -0
- package/dist/log.d.ts +14 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +15 -0
- package/dist/log.js.map +1 -0
- package/dist/nginx.d.ts +4 -0
- package/dist/nginx.d.ts.map +1 -0
- package/dist/nginx.js +53 -0
- package/dist/nginx.js.map +1 -0
- package/dist/pipeline.d.ts +103 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +142 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/presets/index.d.ts +3 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/nextApp.d.ts +15 -0
- package/dist/presets/nextApp.d.ts.map +1 -0
- package/dist/presets/nextApp.js +53 -0
- package/dist/presets/nextApp.js.map +1 -0
- package/dist/presets/nodeApp.d.ts +19 -0
- package/dist/presets/nodeApp.d.ts.map +1 -0
- package/dist/presets/nodeApp.js +29 -0
- package/dist/presets/nodeApp.js.map +1 -0
- package/dist/secrets/bitwarden.d.ts +3 -0
- package/dist/secrets/bitwarden.d.ts.map +1 -0
- package/dist/secrets/bitwarden.js +6 -0
- package/dist/secrets/bitwarden.js.map +1 -0
- package/dist/secrets/refs.d.ts +9 -0
- package/dist/secrets/refs.d.ts.map +1 -0
- package/dist/secrets/refs.js +20 -0
- package/dist/secrets/refs.js.map +1 -0
- package/dist/secrets/store.d.ts +9 -0
- package/dist/secrets/store.d.ts.map +1 -0
- package/dist/secrets/store.js +104 -0
- package/dist/secrets/store.js.map +1 -0
- package/dist/services/ensure.d.ts +18 -0
- package/dist/services/ensure.d.ts.map +1 -0
- package/dist/services/ensure.js +93 -0
- package/dist/services/ensure.js.map +1 -0
- package/dist/services/index.d.ts +19 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +27 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/planned.d.ts +20 -0
- package/dist/services/planned.d.ts.map +1 -0
- package/dist/services/planned.js +77 -0
- package/dist/services/planned.js.map +1 -0
- package/dist/shell.d.ts +11 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +65 -0
- package/dist/shell.js.map +1 -0
- package/dist/source.d.ts +16 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +108 -0
- package/dist/source.js.map +1 -0
- package/dist/sshHost.d.ts +15 -0
- package/dist/sshHost.d.ts.map +1 -0
- package/dist/sshHost.js +91 -0
- package/dist/sshHost.js.map +1 -0
- package/dist/steps.d.ts +27 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +69 -0
- package/dist/steps.js.map +1 -0
- package/dist/topology.d.ts +40 -0
- package/dist/topology.d.ts.map +1 -0
- package/dist/topology.js +113 -0
- package/dist/topology.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
- package/src/build.ts +236 -0
- package/src/checks.ts +65 -0
- package/src/cli/agent.ts +28 -0
- package/src/cli/config.ts +275 -0
- package/src/cli/index.ts +559 -0
- package/src/cli/log.ts +168 -0
- package/src/cli/screen.ts +409 -0
- package/src/cli/viewer.ts +192 -0
- package/src/config.ts +90 -0
- package/src/deploy.ts +409 -0
- package/src/docker.ts +433 -0
- package/src/dockerfile.ts +228 -0
- package/src/health.ts +83 -0
- package/src/host.ts +54 -0
- package/src/index.ts +25 -0
- package/src/layout.ts +41 -0
- package/src/localHost.ts +50 -0
- package/src/log.ts +38 -0
- package/src/nginx.ts +63 -0
- package/src/pipeline.ts +335 -0
- package/src/presets/index.ts +2 -0
- package/src/presets/nextApp.ts +70 -0
- package/src/presets/nodeApp.ts +46 -0
- package/src/secrets/bitwarden.ts +7 -0
- package/src/secrets/refs.ts +32 -0
- package/src/secrets/store.ts +147 -0
- package/src/services/ensure.ts +160 -0
- package/src/services/index.ts +48 -0
- package/src/services/planned.ts +119 -0
- package/src/shell.ts +95 -0
- package/src/source.ts +171 -0
- package/src/sshHost.ts +145 -0
- package/src/steps.ts +101 -0
- package/src/topology.ts +199 -0
- package/src/types.ts +243 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// The deploy as a list of collapsibles. A step is a title and the lines it
|
|
2
|
+
// produced; the one running is open, the ones finished are shut, and the person
|
|
3
|
+
// watching moves between them. The model and the renderer are pure, so what the
|
|
4
|
+
// terminal shows is asserted on rather than driven.
|
|
5
|
+
export function emptyModel(rows, columns, now) {
|
|
6
|
+
return {
|
|
7
|
+
steps: [],
|
|
8
|
+
messages: [],
|
|
9
|
+
cursor: 0,
|
|
10
|
+
following: true,
|
|
11
|
+
minimal: false,
|
|
12
|
+
rows,
|
|
13
|
+
columns,
|
|
14
|
+
started: now,
|
|
15
|
+
now,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const ESCAPE = "\u001b";
|
|
19
|
+
const INTERRUPT = "\u0003";
|
|
20
|
+
// A terminal delivers whatever arrived since the last read, so two arrow keys
|
|
21
|
+
// pressed quickly land as one chunk. Reading only the whole chunk drops both
|
|
22
|
+
export function keysOf(data) {
|
|
23
|
+
const keys = [];
|
|
24
|
+
let rest = data;
|
|
25
|
+
while (rest.length > 0) {
|
|
26
|
+
const sequence = rest.startsWith(ESCAPE) ? CSI.exec(rest)?.[0] : undefined;
|
|
27
|
+
const token = sequence ?? rest.slice(0, 1);
|
|
28
|
+
const key = keyOf(token);
|
|
29
|
+
if (key)
|
|
30
|
+
keys.push(key);
|
|
31
|
+
rest = rest.slice(token.length);
|
|
32
|
+
}
|
|
33
|
+
return keys;
|
|
34
|
+
}
|
|
35
|
+
const CSI = /^\u001b\[[0-9;]*[A-Za-z]/;
|
|
36
|
+
export function keyOf(data) {
|
|
37
|
+
if (data === `${ESCAPE}[A`)
|
|
38
|
+
return "up";
|
|
39
|
+
if (data === `${ESCAPE}[B`)
|
|
40
|
+
return "down";
|
|
41
|
+
if (data === `${ESCAPE}[1;2A`)
|
|
42
|
+
return "latest";
|
|
43
|
+
if (data === `${ESCAPE}[1;2B`)
|
|
44
|
+
return "first";
|
|
45
|
+
if (data === "\r" || data === "\n")
|
|
46
|
+
return "toggle";
|
|
47
|
+
if (data === "+" || data === "=")
|
|
48
|
+
return "expand";
|
|
49
|
+
if (data === "-" || data === "_")
|
|
50
|
+
return "collapse";
|
|
51
|
+
if (data === "q" || data === INTERRUPT)
|
|
52
|
+
return "quit";
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
// Moving up runs out of log before it runs out of steps: the window climbs to
|
|
56
|
+
// the top of what this step printed, and only then does the cursor leave it
|
|
57
|
+
export function apply(model, key) {
|
|
58
|
+
const step = model.steps[model.cursor];
|
|
59
|
+
if (key === "latest") {
|
|
60
|
+
return { ...model, cursor: Math.max(0, model.steps.length - 1), following: true };
|
|
61
|
+
}
|
|
62
|
+
if (key === "first")
|
|
63
|
+
return { ...model, cursor: 0, following: false };
|
|
64
|
+
if (key === "up") {
|
|
65
|
+
if (step?.expanded && step.offset < Math.max(0, step.lines.length - 1)) {
|
|
66
|
+
return scrolled(model, step.offset + 1);
|
|
67
|
+
}
|
|
68
|
+
return { ...model, cursor: Math.max(0, model.cursor - 1), following: false };
|
|
69
|
+
}
|
|
70
|
+
if (key === "down") {
|
|
71
|
+
if (step?.expanded && step.offset > 0)
|
|
72
|
+
return scrolled(model, step.offset - 1);
|
|
73
|
+
const last = model.steps.length - 1;
|
|
74
|
+
const cursor = Math.max(0, Math.min(last, model.cursor + 1));
|
|
75
|
+
return { ...model, cursor, following: cursor === last };
|
|
76
|
+
}
|
|
77
|
+
if (key === "collapse") {
|
|
78
|
+
return {
|
|
79
|
+
...model,
|
|
80
|
+
minimal: true,
|
|
81
|
+
steps: model.steps.map((item) => ({ ...item, expanded: false, held: false })),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Anywhere, so a reader who collapsed everything does not have to find the
|
|
85
|
+
// running step before opening it again
|
|
86
|
+
if (key === "expand") {
|
|
87
|
+
const current = model.steps.length - 1;
|
|
88
|
+
return {
|
|
89
|
+
...model,
|
|
90
|
+
minimal: false,
|
|
91
|
+
steps: model.steps.map((item, index) => index === current ? { ...item, expanded: true, held: true, offset: 0 } : item),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (key === "toggle" && step) {
|
|
95
|
+
const opening = !step.expanded;
|
|
96
|
+
return {
|
|
97
|
+
...model,
|
|
98
|
+
// Opening the running step is the same instruction as pressing plus
|
|
99
|
+
minimal: opening && model.cursor === model.steps.length - 1 ? false : model.minimal,
|
|
100
|
+
steps: model.steps.map((item, index) => index === model.cursor
|
|
101
|
+
? { ...item, expanded: opening, held: opening, offset: 0 }
|
|
102
|
+
: item),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return model;
|
|
106
|
+
}
|
|
107
|
+
function scrolled(model, offset) {
|
|
108
|
+
return {
|
|
109
|
+
...model,
|
|
110
|
+
steps: model.steps.map((item, index) => index === model.cursor ? { ...item, offset } : item),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Colours are put on after every width is measured, because an escape is zero
|
|
114
|
+
// columns wide and a row measured with one in it is a row that wraps
|
|
115
|
+
const DIM = 90;
|
|
116
|
+
const CURSOR = 96;
|
|
117
|
+
const RUNNING = 93;
|
|
118
|
+
const DONE = 32;
|
|
119
|
+
const FAILED = 91;
|
|
120
|
+
const WARN = 33;
|
|
121
|
+
function paint(text, colour, on) {
|
|
122
|
+
if (!on || colour === undefined || text === "")
|
|
123
|
+
return text;
|
|
124
|
+
return `\u001b[${colour}m${text}\u001b[0m`;
|
|
125
|
+
}
|
|
126
|
+
function widthOf(pieces) {
|
|
127
|
+
return pieces.reduce((total, piece) => total + piece.text.length, 0);
|
|
128
|
+
}
|
|
129
|
+
// Clips the row as one string would clip, then hands each surviving piece its
|
|
130
|
+
// colour. The ellipsis belongs to whichever piece was cut
|
|
131
|
+
function clipped(pieces, room, on) {
|
|
132
|
+
if (widthOf(pieces) <= room) {
|
|
133
|
+
return pieces.map((piece) => paint(piece.text, piece.colour, on)).join("");
|
|
134
|
+
}
|
|
135
|
+
const kept = [];
|
|
136
|
+
let left = room - 1;
|
|
137
|
+
for (const piece of pieces) {
|
|
138
|
+
if (left <= 0)
|
|
139
|
+
break;
|
|
140
|
+
const text = piece.text.slice(0, left);
|
|
141
|
+
kept.push(paint(text, piece.colour, on));
|
|
142
|
+
left -= text.length;
|
|
143
|
+
}
|
|
144
|
+
return `${kept.join("")}\u2026`;
|
|
145
|
+
}
|
|
146
|
+
const FOOTER = 2;
|
|
147
|
+
// A step that is open but not the one being read shows this much of itself
|
|
148
|
+
const GLANCE = 6;
|
|
149
|
+
// What the focused step keeps even when everything else wants the room
|
|
150
|
+
const FLOOR = 3;
|
|
151
|
+
// How many of them the frame carries. Every message is written out again when
|
|
152
|
+
// the view closes, and a list that only grows crowds every log off the screen
|
|
153
|
+
const MESSAGES = 6;
|
|
154
|
+
export const HELP = "\u2191\u2193 move \u00b7 enter open \u00b7 shift+\u2191 latest \u00b7 + open \u00b7 - collapse all \u00b7 q quit";
|
|
155
|
+
export function render(model, colour = false) {
|
|
156
|
+
const body = Math.max(1, model.rows - FOOTER);
|
|
157
|
+
const rows = [];
|
|
158
|
+
const messages = model.messages.slice(-MESSAGES);
|
|
159
|
+
// More titles than the terminal has lines, so nothing can be open and the
|
|
160
|
+
// list itself is what scrolls
|
|
161
|
+
if (model.steps.length + messages.length > body) {
|
|
162
|
+
const start = Math.max(0, Math.min(model.cursor, model.steps.length - body));
|
|
163
|
+
for (const [index, step] of model.steps.entries()) {
|
|
164
|
+
if (index >= start && rows.length < body) {
|
|
165
|
+
rows.push(title(model, step, index, colour));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return finish(rows, body, colour);
|
|
169
|
+
}
|
|
170
|
+
const shown = share(model, body - model.steps.length - messages.length);
|
|
171
|
+
for (const [index, step] of model.steps.entries()) {
|
|
172
|
+
rows.push(title(model, step, index, colour));
|
|
173
|
+
rows.push(...logs(model, step, shown.get(index) ?? 0, colour));
|
|
174
|
+
}
|
|
175
|
+
for (const message of messages) {
|
|
176
|
+
rows.push(clipped([
|
|
177
|
+
{ text: gutter(model), colour: DIM },
|
|
178
|
+
{ text: " " },
|
|
179
|
+
{ text: message, colour: WARN },
|
|
180
|
+
], Math.max(24, model.columns), colour));
|
|
181
|
+
}
|
|
182
|
+
return finish(rows, body, colour);
|
|
183
|
+
}
|
|
184
|
+
// The focused step is the one being read, so it is served first and every other
|
|
185
|
+
// open one gets a glance out of what it did not need
|
|
186
|
+
function share(model, budget) {
|
|
187
|
+
const shown = new Map();
|
|
188
|
+
const open = model.steps
|
|
189
|
+
.map((step, index) => ({ step, index }))
|
|
190
|
+
.filter((item) => item.step.expanded);
|
|
191
|
+
const focused = open.find((item) => item.index === model.cursor);
|
|
192
|
+
const others = open.filter((item) => item.index !== model.cursor);
|
|
193
|
+
let left = Math.max(0, budget);
|
|
194
|
+
if (focused) {
|
|
195
|
+
// What the glances would actually cost, not what they could: a step that
|
|
196
|
+
// printed nothing reserves nothing, and served last the focused step used
|
|
197
|
+
// to be left with whatever the others happened not to want
|
|
198
|
+
const glances = others.reduce((total, item) => total + Math.min(GLANCE, item.step.lines.length), 0);
|
|
199
|
+
const reserve = Math.min(glances, Math.max(0, left - FLOOR));
|
|
200
|
+
const take = Math.min(left - reserve, focused.step.lines.length);
|
|
201
|
+
shown.set(focused.index, take);
|
|
202
|
+
left -= take;
|
|
203
|
+
}
|
|
204
|
+
for (const item of others) {
|
|
205
|
+
const take = Math.min(GLANCE, item.step.lines.length, Math.max(0, left));
|
|
206
|
+
shown.set(item.index, take);
|
|
207
|
+
left -= take;
|
|
208
|
+
}
|
|
209
|
+
return shown;
|
|
210
|
+
}
|
|
211
|
+
const RULE = " \u2502 ";
|
|
212
|
+
// The newest lines, less whatever the reader has scrolled back past. One line
|
|
213
|
+
// each: a wrapped line would push the rows below it off a frame sized in rows
|
|
214
|
+
function logs(model, step, take, colour) {
|
|
215
|
+
if (take <= 0)
|
|
216
|
+
return [];
|
|
217
|
+
const end = Math.max(1, step.lines.length - step.offset);
|
|
218
|
+
const room = Math.max(8, model.columns - RULE.length);
|
|
219
|
+
return step.lines
|
|
220
|
+
.slice(Math.max(0, end - take), end)
|
|
221
|
+
.map((line) => `${paint(RULE, DIM, colour)}${clip(line, room)}`);
|
|
222
|
+
}
|
|
223
|
+
// The ellipsis is the whole point: a line that was cut has to say so
|
|
224
|
+
export function clip(text, room) {
|
|
225
|
+
if (text.length <= room)
|
|
226
|
+
return text;
|
|
227
|
+
return `${text.slice(0, room - 1)}\u2026`;
|
|
228
|
+
}
|
|
229
|
+
function finish(rows, body, colour) {
|
|
230
|
+
const filled = rows.slice(0, body);
|
|
231
|
+
while (filled.length < body)
|
|
232
|
+
filled.push("");
|
|
233
|
+
return [...filled, "", paint(HELP, DIM, colour)];
|
|
234
|
+
}
|
|
235
|
+
function title(model, step, index, colour) {
|
|
236
|
+
const selected = index === model.cursor;
|
|
237
|
+
const caret = selected ? "\u276f" : " ";
|
|
238
|
+
const arrow = step.expanded ? "\u25be" : "\u25b8";
|
|
239
|
+
const glyph = step.state === "done" ? "\u2714" : step.state === "failed" ? "\u2718" : arrow;
|
|
240
|
+
const said = step.note ? `: ${step.note}` : step.detail ? ` ${step.detail}` : "";
|
|
241
|
+
const head = [
|
|
242
|
+
{ text: gutter(model), colour: DIM },
|
|
243
|
+
{ text: " " },
|
|
244
|
+
{ text: caret, colour: selected ? CURSOR : undefined },
|
|
245
|
+
{ text: " " },
|
|
246
|
+
{ text: glyph, colour: stateColour(step) },
|
|
247
|
+
{ text: " " },
|
|
248
|
+
{ text: step.label, colour: labelColour(step, selected) },
|
|
249
|
+
{ text: said, colour: DIM },
|
|
250
|
+
];
|
|
251
|
+
// Frozen at what it cost the moment it finished, still counting until then
|
|
252
|
+
return fit(model, head, elapsed(step.ended ?? model.now, step.started), colour);
|
|
253
|
+
}
|
|
254
|
+
function stateColour(step) {
|
|
255
|
+
if (step.state === "done")
|
|
256
|
+
return DONE;
|
|
257
|
+
if (step.state === "failed")
|
|
258
|
+
return FAILED;
|
|
259
|
+
return RUNNING;
|
|
260
|
+
}
|
|
261
|
+
// A failure outranks everything: it is the row the reader is looking for. Then
|
|
262
|
+
// where the cursor is, then what is still running
|
|
263
|
+
function labelColour(step, selected) {
|
|
264
|
+
if (step.state === "failed")
|
|
265
|
+
return FAILED;
|
|
266
|
+
if (selected)
|
|
267
|
+
return CURSOR;
|
|
268
|
+
if (step.state === "running")
|
|
269
|
+
return RUNNING;
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
// The stamp is the whole run, and it keeps counting for every row a step adds
|
|
273
|
+
function gutter(model) {
|
|
274
|
+
return `[${elapsed(model.now, model.started, true)}]`;
|
|
275
|
+
}
|
|
276
|
+
export function elapsed(now, started, clock = false) {
|
|
277
|
+
const seconds = Math.max(0, Math.floor((now - started) / 1000));
|
|
278
|
+
const minutes = Math.floor(seconds / 60);
|
|
279
|
+
if (clock)
|
|
280
|
+
return `${pad(minutes)}:${pad(seconds % 60)}`;
|
|
281
|
+
if (seconds < 60)
|
|
282
|
+
return `${seconds}s`;
|
|
283
|
+
return `${minutes}m${pad(seconds % 60)}s`;
|
|
284
|
+
}
|
|
285
|
+
function pad(value) {
|
|
286
|
+
return String(value).padStart(2, "0");
|
|
287
|
+
}
|
|
288
|
+
// The timer is pushed to the right edge, and the label is what gives way when
|
|
289
|
+
// there is not room for both. One space between them always, which is a row
|
|
290
|
+
// wider than the terminal when the label is allowed to fill the gap
|
|
291
|
+
function fit(model, head, timer, colour) {
|
|
292
|
+
const width = Math.max(24, model.columns);
|
|
293
|
+
const room = width - timer.length - 1;
|
|
294
|
+
const shown = Math.min(widthOf(head), room - 1);
|
|
295
|
+
return (`${clipped(head, room - 1, colour)}` +
|
|
296
|
+
`${" ".repeat(Math.max(1, room - shown))} ${paint(timer, DIM, colour)}`);
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=screen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/cli/screen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Log } from "../log.js";
|
|
2
|
+
export type Viewer = Log & {
|
|
3
|
+
close(): void;
|
|
4
|
+
};
|
|
5
|
+
export type ViewerOptions = {
|
|
6
|
+
onQuit?: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function createViewer(stream: NodeJS.WriteStream, input: NodeJS.ReadStream, options?: ViewerOptions): Viewer;
|
|
9
|
+
//# sourceMappingURL=viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAQ,MAAM,WAAW,CAAC;AAyB3C,MAAM,MAAM,MAAM,GAAG,GAAG,GAAG;IAGzB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAYF,MAAM,MAAM,aAAa,GAAG;IAG1B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,CAAC,WAAW,EAC1B,KAAK,EAAE,MAAM,CAAC,UAAU,EACxB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CA8HR"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { apply, elapsed, emptyModel, keysOf, render, } from "./screen.js";
|
|
2
|
+
// The terminal half: raw keys in, a frame out on a timer. Everything it decides
|
|
3
|
+
// lives in screen.ts, so this file is only the parts a test cannot run.
|
|
4
|
+
const FRAME_MS = 100;
|
|
5
|
+
const ALTERNATE_ON = "\u001b[?1049h\u001b[?25l";
|
|
6
|
+
const ALTERNATE_OFF = "\u001b[?25h\u001b[?1049l";
|
|
7
|
+
const HOME = "\u001b[H";
|
|
8
|
+
const CLEAR_LINE = "\u001b[K";
|
|
9
|
+
const CLEAR_BELOW = "\u001b[J";
|
|
10
|
+
// A build prints tens of thousands of lines and only the tail is ever read
|
|
11
|
+
const KEPT = 2000;
|
|
12
|
+
// A pty whose size nobody set answers 0 rather than nothing, and a view one row
|
|
13
|
+
// tall can only ever show the step the cursor is on
|
|
14
|
+
const ROWS = 24;
|
|
15
|
+
const COLUMNS = 80;
|
|
16
|
+
const sizeOf = (stream) => ({
|
|
17
|
+
rows: stream.rows && stream.rows > 4 ? stream.rows : ROWS,
|
|
18
|
+
columns: stream.columns && stream.columns > 20 ? stream.columns : COLUMNS,
|
|
19
|
+
});
|
|
20
|
+
export function createViewer(stream, input, options = {}) {
|
|
21
|
+
// NO_COLOR is a standing instruction rather than a preference to re-ask
|
|
22
|
+
// about, and a terminal that took the alternate screen still may not paint
|
|
23
|
+
const colour = !process.env["NO_COLOR"] && stream.isTTY === true;
|
|
24
|
+
const size = sizeOf(stream);
|
|
25
|
+
let model = emptyModel(size.rows, size.columns, Date.now());
|
|
26
|
+
let open = true;
|
|
27
|
+
const draw = () => {
|
|
28
|
+
if (!open)
|
|
29
|
+
return;
|
|
30
|
+
model = { ...model, now: Date.now(), ...sizeOf(stream) };
|
|
31
|
+
const rows = render(model, colour).map((row) => `${row}${CLEAR_LINE}`);
|
|
32
|
+
stream.write(`${HOME}${rows.join("\n")}${CLEAR_BELOW}`);
|
|
33
|
+
};
|
|
34
|
+
const change = (next) => {
|
|
35
|
+
model = next(model);
|
|
36
|
+
draw();
|
|
37
|
+
};
|
|
38
|
+
const timer = setInterval(draw, FRAME_MS);
|
|
39
|
+
timer.unref();
|
|
40
|
+
stream.write(ALTERNATE_ON);
|
|
41
|
+
if (input.isTTY)
|
|
42
|
+
input.setRawMode(true);
|
|
43
|
+
input.resume();
|
|
44
|
+
input.setEncoding("utf8");
|
|
45
|
+
const say = (message) => change((current) => ({ ...current, messages: [...current.messages, message] }));
|
|
46
|
+
const onKey = (data) => {
|
|
47
|
+
for (const key of keysOf(data)) {
|
|
48
|
+
// Not a return: two presses in one read are two asks, and the second one
|
|
49
|
+
// is what hardens the signal the first one sent
|
|
50
|
+
if (key === "quit")
|
|
51
|
+
quit();
|
|
52
|
+
else
|
|
53
|
+
change((current) => apply(current, key));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
input.on("data", onKey);
|
|
57
|
+
const onResize = () => draw();
|
|
58
|
+
stream.on("resize", onResize);
|
|
59
|
+
const close = () => {
|
|
60
|
+
if (!open)
|
|
61
|
+
return;
|
|
62
|
+
open = false;
|
|
63
|
+
clearInterval(timer);
|
|
64
|
+
input.off("data", onKey);
|
|
65
|
+
stream.off("resize", onResize);
|
|
66
|
+
if (input.isTTY)
|
|
67
|
+
input.setRawMode(false);
|
|
68
|
+
input.pause();
|
|
69
|
+
stream.write(ALTERNATE_OFF);
|
|
70
|
+
// The alternate screen takes every frame with it, so the run has to be
|
|
71
|
+
// written again on the screen the person keeps
|
|
72
|
+
for (const line of summary(model))
|
|
73
|
+
stream.write(`${line}\n`);
|
|
74
|
+
};
|
|
75
|
+
// What a second press means is not the view's to decide: the same key
|
|
76
|
+
// arrives as a signal when there is no view, and one answer serves both
|
|
77
|
+
const quit = () => options.onQuit?.();
|
|
78
|
+
process.once("exit", () => open && stream.write(ALTERNATE_OFF));
|
|
79
|
+
const step = (label) => {
|
|
80
|
+
let index = 0;
|
|
81
|
+
change((current) => {
|
|
82
|
+
index = current.steps.length;
|
|
83
|
+
const started = {
|
|
84
|
+
label,
|
|
85
|
+
started: Date.now(),
|
|
86
|
+
state: "running",
|
|
87
|
+
lines: [],
|
|
88
|
+
// The one running is the one being read, unless the reader said no
|
|
89
|
+
expanded: !current.minimal,
|
|
90
|
+
held: false,
|
|
91
|
+
offset: 0,
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
...current,
|
|
95
|
+
steps: [...current.steps, started],
|
|
96
|
+
cursor: current.following ? index : current.cursor,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
const edit = (change_) => change((current) => ({
|
|
100
|
+
...current,
|
|
101
|
+
steps: current.steps.map((item, at) => (at === index ? change_(item) : item)),
|
|
102
|
+
}));
|
|
103
|
+
// A finished step shuts, so the list stays a list. One the reader opened by
|
|
104
|
+
// hand stays open: it is being read, and closing it would move the screen
|
|
105
|
+
const settle = (state, note) => edit((item) => ({
|
|
106
|
+
...item,
|
|
107
|
+
state,
|
|
108
|
+
note,
|
|
109
|
+
detail: undefined,
|
|
110
|
+
ended: Date.now(),
|
|
111
|
+
expanded: item.held,
|
|
112
|
+
}));
|
|
113
|
+
return {
|
|
114
|
+
detail: (message) => edit((item) => ({ ...item, detail: message })),
|
|
115
|
+
line: (message) => edit((item) => ({ ...item, lines: [...item.lines, message].slice(-KEPT) })),
|
|
116
|
+
done: (message) => settle("done", message),
|
|
117
|
+
fail: (message) => settle("failed", message),
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
return Object.assign(say, {
|
|
121
|
+
warn: say,
|
|
122
|
+
fail: say,
|
|
123
|
+
done: say,
|
|
124
|
+
step,
|
|
125
|
+
close,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// One line per step and whatever was said outside them, which is the record a
|
|
129
|
+
// person scrolls back to after the deploy is over
|
|
130
|
+
function summary(model) {
|
|
131
|
+
const rows = model.steps.map((step) => {
|
|
132
|
+
const glyph = step.state === "done" ? "✔" : step.state === "failed" ? "✘" : "·";
|
|
133
|
+
const said = step.note ? `: ${step.note}` : "";
|
|
134
|
+
const took = elapsed(step.ended ?? model.now, step.started);
|
|
135
|
+
return `${glyph} ${step.label}${said} (${took})`;
|
|
136
|
+
});
|
|
137
|
+
return [...rows, ...model.messages];
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=viewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer.js","sourceRoot":"","sources":["../../src/cli/viewer.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Deployment, Environment } from "./types.js";
|
|
2
|
+
export declare function environmentOf(config: Deployment, name: string): Environment | undefined;
|
|
3
|
+
export declare function defineDeployment<const T extends Deployment & {
|
|
4
|
+
environments?: never;
|
|
5
|
+
}>(config: T): T;
|
|
6
|
+
export declare function defineEnvironment<const T extends Environment>(environment: T): T;
|
|
7
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK1D,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,2BAE7D;AAMD,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,UAAU,GAAG;IAAE,YAAY,CAAC,EAAE,KAAK,CAAA;CAAE,EACpF,MAAM,EAAE,CAAC,GACR,CAAC,CAOH;AAID,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,CAEhF"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { assertSteps } from "./pipeline.js";
|
|
2
|
+
// The one selected, from the one place worth looking. A deployment that carries
|
|
3
|
+
// its own overrides every file, which is what makes it an override rather than
|
|
4
|
+
// a default nobody can displace
|
|
5
|
+
export function environmentOf(config, name) {
|
|
6
|
+
return config.environment ?? config.environments?.[name];
|
|
7
|
+
}
|
|
8
|
+
// Identity, but it pins the type so a missing health predicate fails to
|
|
9
|
+
// compile. Environments are excluded rather than merely unused: each lives in
|
|
10
|
+
// a redkite.<name>.config.ts of its own, and a second place to put one is a
|
|
11
|
+
// second place for them to disagree
|
|
12
|
+
export function defineDeployment(config) {
|
|
13
|
+
assertUniqueNames(config);
|
|
14
|
+
assertOneSource(config);
|
|
15
|
+
assertRoutesResolvable(config);
|
|
16
|
+
assertDirsRelative(config);
|
|
17
|
+
assertSteps(config.steps ?? []);
|
|
18
|
+
return config;
|
|
19
|
+
}
|
|
20
|
+
// Identity, for the environment a redkite.<name>.config.ts holds. It pins the
|
|
21
|
+
// type the same way defineDeployment does, so a missing subnet fails to compile
|
|
22
|
+
export function defineEnvironment(environment) {
|
|
23
|
+
return environment;
|
|
24
|
+
}
|
|
25
|
+
// Cloned or already here, and the two are built differently enough that
|
|
26
|
+
// guessing between them is worse than being told
|
|
27
|
+
function assertOneSource(config) {
|
|
28
|
+
for (const app of config.apps) {
|
|
29
|
+
if (app.repo && app.path) {
|
|
30
|
+
throw new Error(`${app.name} names both a repo and a path, and is built from one of them`);
|
|
31
|
+
}
|
|
32
|
+
if (!app.repo && !app.path) {
|
|
33
|
+
throw new Error(`${app.name} names no source, so give it a repo to clone or a path to build`);
|
|
34
|
+
}
|
|
35
|
+
// A clone is whatever the repository holds, so there is nothing here to
|
|
36
|
+
// narrow and an include would quietly do nothing
|
|
37
|
+
if (app.include && !app.path) {
|
|
38
|
+
throw new Error(`${app.name} says what to include, but is cloned rather than built from a path`);
|
|
39
|
+
}
|
|
40
|
+
if (app.include?.length === 0) {
|
|
41
|
+
throw new Error(`${app.name} includes nothing, so there would be no build context`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// A dir is joined onto /app inside the image, so an absolute one would render
|
|
46
|
+
// a path with two slashes and a climbing one would leave the checkout
|
|
47
|
+
function assertDirsRelative(config) {
|
|
48
|
+
for (const app of config.apps) {
|
|
49
|
+
const dir = app.dir;
|
|
50
|
+
if (dir === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
if (!dir || dir.startsWith("/") || dir.endsWith("/")) {
|
|
53
|
+
throw new Error(`dir for ${app.name} must be a path inside the repository`);
|
|
54
|
+
}
|
|
55
|
+
if (dir.split("/").includes("..")) {
|
|
56
|
+
throw new Error(`dir for ${app.name} must not climb out of the repository`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function assertUniqueNames(config) {
|
|
61
|
+
const names = [...config.apps, ...config.services].map((item) => item.name);
|
|
62
|
+
const duplicate = names.find((name, i) => names.indexOf(name) !== i);
|
|
63
|
+
if (duplicate)
|
|
64
|
+
throw new Error(`Duplicate name in deployment: ${duplicate}`);
|
|
65
|
+
}
|
|
66
|
+
// Two apps on the same route means one of them is unreachable, and which one
|
|
67
|
+
// depends on nginx location precedence rather than on anything written here
|
|
68
|
+
function assertRoutesResolvable(config) {
|
|
69
|
+
const routes = config.apps.map((app) => app.route);
|
|
70
|
+
const duplicate = routes.find((route, i) => routes.indexOf(route) !== i);
|
|
71
|
+
if (duplicate)
|
|
72
|
+
throw new Error(`Two apps share the route ${duplicate}`);
|
|
73
|
+
for (const app of config.apps) {
|
|
74
|
+
if (app.route.startsWith("/"))
|
|
75
|
+
continue;
|
|
76
|
+
throw new Error(`Route for ${app.name} must start with a slash`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/deploy.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type HealthDeps } from "./health.js";
|
|
2
|
+
import type { Host } from "./host.js";
|
|
3
|
+
import { type Log } from "./log.js";
|
|
4
|
+
import { type Finished } from "./pipeline.js";
|
|
5
|
+
import { type SecretStores } from "./secrets/refs.js";
|
|
6
|
+
import type { Deployment } from "./types.js";
|
|
7
|
+
export type DeployOptions = {
|
|
8
|
+
config: Deployment;
|
|
9
|
+
environment: string;
|
|
10
|
+
host: Host;
|
|
11
|
+
secrets: SecretStores;
|
|
12
|
+
health?: Omit<HealthDeps, "probe">;
|
|
13
|
+
log?: Log;
|
|
14
|
+
verbose?: boolean;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
};
|
|
17
|
+
export declare function deploy(options: DeployOptions): Promise<Finished>;
|
|
18
|
+
export declare function verify(options: DeployOptions): Promise<Finished>;
|
|
19
|
+
//# sourceMappingURL=deploy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAU,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAQL,KAAK,QAAQ,EAMd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIxE,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,YAAY,CAAC;AAWtD,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,IAAI,EAAE,IAAI,CAAC;IAEX,OAAO,EAAE,YAAY,CAAC;IAGtB,MAAM,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEtE;AAID,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEtE"}
|