redkite 0.1.9 → 0.1.10
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 +131 -11
- package/dist/build.d.ts +1 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +7 -1
- package/dist/build.js.map +1 -1
- package/dist/cli/agent.js +2 -2
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/config.d.ts +1 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +67 -14
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/dotenv.d.ts +2 -0
- package/dist/cli/dotenv.d.ts.map +1 -0
- package/dist/cli/dotenv.js +30 -0
- package/dist/cli/dotenv.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +11 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/screen.d.ts +10 -3
- package/dist/cli/screen.d.ts.map +1 -1
- package/dist/cli/screen.js +153 -36
- package/dist/cli/screen.js.map +1 -1
- package/dist/cli/viewer.d.ts.map +1 -1
- package/dist/cli/viewer.js +36 -4
- package/dist/cli/viewer.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +12 -2
- package/dist/deploy.js.map +1 -1
- package/dist/docker.d.ts +1 -0
- package/dist/docker.d.ts.map +1 -1
- package/dist/docker.js +3 -0
- package/dist/docker.js.map +1 -1
- package/dist/dockerfile.d.ts +1 -0
- package/dist/dockerfile.d.ts.map +1 -1
- package/dist/dockerfile.js +16 -3
- package/dist/dockerfile.js.map +1 -1
- package/dist/environment.d.ts +2 -0
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +56 -1
- package/dist/environment.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +1 -0
- package/dist/log.js.map +1 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +3 -0
- package/dist/pipeline.js.map +1 -1
- package/dist/plugins/bitwarden.d.ts.map +1 -1
- package/dist/plugins/bitwarden.js +25 -6
- package/dist/plugins/bitwarden.js.map +1 -1
- package/dist/presets/nextApp.d.ts.map +1 -1
- package/dist/presets/nextApp.js +5 -4
- package/dist/presets/nextApp.js.map +1 -1
- package/dist/presets/nodeApp.d.ts.map +1 -1
- package/dist/presets/nodeApp.js +15 -6
- package/dist/presets/nodeApp.js.map +1 -1
- package/dist/secrets/manager.d.ts +9 -0
- package/dist/secrets/manager.d.ts.map +1 -0
- package/dist/secrets/manager.js +130 -0
- package/dist/secrets/manager.js.map +1 -0
- package/dist/secrets/store.d.ts.map +1 -1
- package/dist/secrets/store.js +46 -12
- package/dist/secrets/store.js.map +1 -1
- package/dist/services/ensure.js +1 -1
- package/dist/services/ensure.js.map +1 -1
- package/dist/services/index.d.ts +2 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +11 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/planned.d.ts +0 -1
- package/dist/services/planned.d.ts.map +1 -1
- package/dist/services/planned.js +3 -12
- package/dist/services/planned.js.map +1 -1
- package/dist/services/proxy.d.ts +7 -0
- package/dist/services/proxy.d.ts.map +1 -0
- package/dist/services/proxy.js +103 -0
- package/dist/services/proxy.js.map +1 -0
- package/dist/source.d.ts +1 -0
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +5 -5
- package/dist/source.js.map +1 -1
- package/dist/steps.d.ts +1 -6
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +3 -3
- package/dist/steps.js.map +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/build.ts +10 -1
- package/src/cli/agent.ts +2 -2
- package/src/cli/config.ts +77 -13
- package/src/cli/dotenv.ts +35 -0
- package/src/cli/index.ts +11 -5
- package/src/cli/screen.ts +193 -43
- package/src/cli/viewer.ts +41 -4
- package/src/config.ts +11 -0
- package/src/deploy.ts +14 -2
- package/src/docker.ts +5 -0
- package/src/dockerfile.ts +23 -3
- package/src/environment.ts +71 -1
- package/src/index.ts +2 -1
- package/src/log.ts +4 -0
- package/src/pipeline.ts +4 -0
- package/src/plugins/bitwarden.ts +38 -11
- package/src/presets/nextApp.ts +5 -4
- package/src/presets/nodeApp.ts +15 -6
- package/src/secrets/manager.ts +172 -0
- package/src/secrets/store.ts +51 -16
- package/src/services/ensure.ts +1 -1
- package/src/services/index.ts +13 -1
- package/src/services/planned.ts +3 -13
- package/src/services/proxy.ts +126 -0
- package/src/source.ts +13 -4
- package/src/steps.ts +7 -7
- package/src/types.ts +19 -4
- package/dist/nginx.d.ts +0 -4
- package/dist/nginx.d.ts.map +0 -1
- package/dist/nginx.js +0 -53
- package/dist/nginx.js.map +0 -1
- package/src/nginx.ts +0 -63
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// The proxy every route is resolved by: what it is, and the configuration it
|
|
2
|
+
// runs. Both halves here, because a deployment does not list this service and
|
|
3
|
+
// the only thing that decides either is the app list.
|
|
4
|
+
//
|
|
5
|
+
// Header policy is set once rather than per location, which is what let the two
|
|
6
|
+
// blocks drift apart and lose X-Forwarded-For on one of them.
|
|
7
|
+
const FORWARDING = [
|
|
8
|
+
"proxy_set_header Host $http_host;",
|
|
9
|
+
"proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;",
|
|
10
|
+
"proxy_set_header X-Forwarded-Host $http_host;",
|
|
11
|
+
"proxy_set_header X-Forwarded-Proto $scheme;",
|
|
12
|
+
];
|
|
13
|
+
const FAILOVER = [
|
|
14
|
+
"proxy_connect_timeout 2s;",
|
|
15
|
+
"proxy_read_timeout 30s;",
|
|
16
|
+
"proxy_next_upstream error timeout http_502 http_503;",
|
|
17
|
+
"proxy_next_upstream_tries 2;",
|
|
18
|
+
];
|
|
19
|
+
// The port the proxy listens on inside its container. The published port maps
|
|
20
|
+
// onto this one, so both sides have to agree and only one of them may say it
|
|
21
|
+
export const LISTEN_PORT = 3000;
|
|
22
|
+
// What the derived proxy is called. A service by this name would be a second
|
|
23
|
+
// container claiming the first one's, so the config surface refuses it
|
|
24
|
+
export const PROXY = "nginx";
|
|
25
|
+
// Not something a deployment lists. Apps carry routes, routes need something
|
|
26
|
+
// to resolve them, and this says what that something is
|
|
27
|
+
export function proxyService(config) {
|
|
28
|
+
return {
|
|
29
|
+
name: PROXY,
|
|
30
|
+
image: config.proxy?.image ?? "nginx:stable",
|
|
31
|
+
restart: "always",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function renderProxy(topology, proxy = {}) {
|
|
35
|
+
const upstreams = topology.apps.map((app) => upstream(app)).join("\n\n");
|
|
36
|
+
// Longest route first, so "/api/" is not shadowed by the "/" catch-all
|
|
37
|
+
const ordered = [...topology.apps].sort((a, b) => b.route.length - a.route.length);
|
|
38
|
+
const locations = ordered.map((app) => location(app, proxy.location ?? [])).join("\n\n");
|
|
39
|
+
assertNotDerived(proxy.server ?? []);
|
|
40
|
+
const server = settled([
|
|
41
|
+
`merge_slashes off;`,
|
|
42
|
+
`client_max_body_size ${proxy.maxBodySize ?? "1M"};`,
|
|
43
|
+
...(proxy.server ?? []),
|
|
44
|
+
]);
|
|
45
|
+
return `resolver 127.0.0.1 valid=5s;
|
|
46
|
+
|
|
47
|
+
${upstreams}
|
|
48
|
+
|
|
49
|
+
server {
|
|
50
|
+
listen ${LISTEN_PORT};
|
|
51
|
+
${indented(server, 4)}
|
|
52
|
+
${locations}
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
// nginx refuses a second proxy_read_timeout but expects several
|
|
57
|
+
// proxy_set_header, so what identifies a line is the directive and, for the
|
|
58
|
+
// ones that carry a name, the name after it
|
|
59
|
+
const NAMED = new Set(["add_header", "proxy_set_header", "proxy_hide_header", "set"]);
|
|
60
|
+
function directive(line) {
|
|
61
|
+
const [name = "", argument = ""] = line.trim().split(/\s+/);
|
|
62
|
+
return NAMED.has(name) ? `${name} ${argument}` : name;
|
|
63
|
+
}
|
|
64
|
+
// The last of each wins. A line written by hand replaces the one redkite would
|
|
65
|
+
// have put there rather than repeating it, which nginx would refuse outright
|
|
66
|
+
function settled(lines) {
|
|
67
|
+
const kept = new Map();
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
if (!line.trim())
|
|
70
|
+
continue;
|
|
71
|
+
kept.set(directive(line), line.trim());
|
|
72
|
+
}
|
|
73
|
+
return [...kept.values()];
|
|
74
|
+
}
|
|
75
|
+
// The published port maps onto this one, so both sides have to agree and only
|
|
76
|
+
// one of them may say it
|
|
77
|
+
function assertNotDerived(lines) {
|
|
78
|
+
const listening = lines.find((line) => directive(line) === "listen");
|
|
79
|
+
if (!listening)
|
|
80
|
+
return;
|
|
81
|
+
throw new Error(`The proxy's server block says ${listening.trim()}, and the port it listens ` +
|
|
82
|
+
"on inside its container is what publicPort is published onto");
|
|
83
|
+
}
|
|
84
|
+
function indented(lines, by) {
|
|
85
|
+
return lines.map((line) => " ".repeat(by) + line).join("\n");
|
|
86
|
+
}
|
|
87
|
+
function upstream(app) {
|
|
88
|
+
return `upstream ${app.name} {
|
|
89
|
+
server ${app.container}:${app.port} max_fails=1 fail_timeout=2s;
|
|
90
|
+
server ${app.retired}:${app.port} backup;
|
|
91
|
+
}`;
|
|
92
|
+
}
|
|
93
|
+
function location(app, added) {
|
|
94
|
+
// A trailing slash on proxy_pass strips the location prefix. The catch-all
|
|
95
|
+
// must not carry one, a mounted route must
|
|
96
|
+
const target = app.route === "/" ? `http://${app.name}` : `http://${app.name}/`;
|
|
97
|
+
// Last, so one of these replaces what redkite set rather than repeating it
|
|
98
|
+
const body = settled([`proxy_pass ${target};`, ...FAILOVER, ...FORWARDING, ...added]);
|
|
99
|
+
return ` location ${app.route} {
|
|
100
|
+
${indented(body, 8)}
|
|
101
|
+
}`;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/services/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/source.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type SourceRequest = {
|
|
|
16
16
|
ref: Ref;
|
|
17
17
|
submodules: boolean;
|
|
18
18
|
detail?: (message: string) => void;
|
|
19
|
+
output?: (line: string) => void;
|
|
19
20
|
};
|
|
20
21
|
export declare function prepareSource(host: Host, request: SourceRequest): Promise<Source>;
|
|
21
22
|
//# sourceMappingURL=source.d.ts.map
|
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;AAOtC,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;
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOtC,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;AAaF,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAKjB"}
|
package/dist/source.js
CHANGED
|
@@ -73,7 +73,7 @@ async function clonedSource(host, repo, request) {
|
|
|
73
73
|
` mkdir -p '${host.cache}/mirrors'`,
|
|
74
74
|
` git clone --mirror '${repo}' '${mirror}'`,
|
|
75
75
|
"fi",
|
|
76
|
-
]);
|
|
76
|
+
], request.output);
|
|
77
77
|
const resolved = await run(host, `resolving ${name}`, [
|
|
78
78
|
`git -C '${mirror}' rev-parse '${REVISION[kind](name)}'`,
|
|
79
79
|
]);
|
|
@@ -95,7 +95,7 @@ async function clonedSource(host, repo, request) {
|
|
|
95
95
|
// Leaves the submodules alone: they are tracked, and clean only removes
|
|
96
96
|
// what is not
|
|
97
97
|
`git -C '${path}' clean -ffdx`,
|
|
98
|
-
]);
|
|
98
|
+
], request.output);
|
|
99
99
|
if (request.submodules) {
|
|
100
100
|
// --remote follows the branch named in .gitmodules rather than the commit
|
|
101
101
|
// the parent recorded, which is what the pipeline has always done
|
|
@@ -103,12 +103,12 @@ async function clonedSource(host, repo, request) {
|
|
|
103
103
|
await run(host, "updating submodules", [
|
|
104
104
|
`git -C '${path}' submodule sync --recursive`,
|
|
105
105
|
`git -C '${path}' submodule update --init --remote --recursive`,
|
|
106
|
-
]);
|
|
106
|
+
], request.output);
|
|
107
107
|
}
|
|
108
108
|
return { release, tree: path };
|
|
109
109
|
}
|
|
110
|
-
async function run(host, what, script) {
|
|
111
|
-
const result = await host.sh([`export GIT_SSH_COMMAND='${GIT_SSH}'`, "set -e", ...script].join("\n"));
|
|
110
|
+
async function run(host, what, script, output) {
|
|
111
|
+
const result = await host.sh([`export GIT_SSH_COMMAND='${GIT_SSH}'`, "set -e", ...script].join("\n"), output);
|
|
112
112
|
if (result.code === 0)
|
|
113
113
|
return result;
|
|
114
114
|
throw new Error(`Failed ${what}: ${result.stderr || result.stdout}`);
|
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":"AAuCA,+EAA+E;AAC/E,sDAAsD;AACtD,MAAM,QAAQ,GAA8C;IAC1D,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,IAAI,EAAE;IACtC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,IAAI,WAAW;IAC3C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,WAAW;CACrC,CAAC;AAEF,6EAA6E;AAC7E,MAAM,OAAO,GAAG,yCAAyC,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAU,EACV,OAAsB;IAEtB,IAAI,OAAO,CAAC,IAAI;QAAE,OAAO,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,IAAI;QAAE,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEzE,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,gDAAgD,CAAC,CAAC;AACnF,CAAC;AAED,2EAA2E;AAC3E,6DAA6D;AAC7D,KAAK,UAAU,WAAW,CACxB,IAAU,EACV,IAAY,EACZ,OAAsB;IAEtB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAE1B,MAAM,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,CAAC,cAAc,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,2EAA2E;AAC3E,+EAA+E;AAC/E,iDAAiD;AACjD,KAAK,UAAU,cAAc,CAAC,IAAU,EAAE,IAAY,EAAE,OAAkB;IACxE,IAAI,OAAO;QAAE,OAAO;IAEpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,IAAI,mCAAmC,CAAC,CAAC;IACjF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO;IAEjE,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,qEAAqE;QAC1E,wEAAwE;QACxE,gEAAgE,CACnE,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,6EAA6E;AAC7E,sBAAsB;AACtB,KAAK,UAAU,MAAM,CAAC,IAAU,EAAE,IAAY,EAAE,OAAkB;IAChE,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEpF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAC3B;QACE,sBAAsB;QACtB,mCAAmC;QACnC,gDAAgD,IAAI,mCAAmC;QACvF,WAAW,KAAK,EAAE;QAClB,gBAAgB;QAChB,mBAAmB;KACpB,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAEnD,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,KAAK,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,IAAU,EACV,IAAY,EACZ,OAAsB;IAEtB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,IAAI,MAAM,CAAC;IAC3D,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,WAAW,OAAO,CAAC,IAAI,EAAE,CAAC;IACpD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAEnC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC3B,MAAM,GAAG,CAAC,IAAI,EAAE,0BAA0B,IAAI,EAAE,EAAE;QAChD,YAAY,MAAM,WAAW;QAC7B,aAAa,MAAM,4BAA4B,IAAI,GAAG;QACtD,aAAa,MAAM,yBAAyB;QAC5C,MAAM;QACN,eAAe,IAAI,CAAC,KAAK,WAAW;QACpC,yBAAyB,IAAI,MAAM,MAAM,GAAG;QAC5C,IAAI;KACL,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,EAAE;QACpD,WAAW,MAAM,gBAAgB,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG;KACzD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,gBAAgB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;QACrD,yEAAyE;QACzE,2EAA2E;QAC3E,cAAc,IAAI,gBAAgB;QAClC,aAAa,IAAI,GAAG;QACpB,eAAe,IAAI,CAAC,KAAK,UAAU;QACnC,uCAAuC,MAAM,MAAM,IAAI,GAAG;QAC1D,IAAI;QACJ,WAAW,IAAI,wBAAwB;QACvC,WAAW,IAAI,gCAAgC,OAAO,GAAG;QACzD,wEAAwE;QACxE,cAAc;QACd,WAAW,IAAI,eAAe;KAC/B,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,0EAA0E;QAC1E,kEAAkE;QAClE,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAC9B,MAAM,GAAG,CAAC,IAAI,EAAE,qBAAqB,EAAE;YACrC,WAAW,IAAI,8BAA8B;YAC7C,WAAW,IAAI,gDAAgD;SAChE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,GAAG,CAChB,IAAU,EACV,IAAY,EACZ,MAAgB,EAChB,MAA+B;IAE/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAC1B,CAAC,2BAA2B,OAAO,GAAG,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EACvE,MAAM,CACP,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAErC,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACvE,CAAC"}
|
package/dist/steps.d.ts
CHANGED
|
@@ -6,12 +6,7 @@ type MigrateOptions = {
|
|
|
6
6
|
app: string;
|
|
7
7
|
command: string;
|
|
8
8
|
network?: StepNetwork;
|
|
9
|
-
|
|
10
|
-
bastion: string;
|
|
11
|
-
from: string;
|
|
12
|
-
alias?: string;
|
|
13
|
-
port?: number;
|
|
14
|
-
};
|
|
9
|
+
through?: string;
|
|
15
10
|
};
|
|
16
11
|
export declare function migrate(options: MigrateOptions): Step<`swap:before:${string}`>;
|
|
17
12
|
export declare function builderOf(input: Built, name: string): string;
|
package/dist/steps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAQ,IAAI,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKvD,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAY7E;AAED,KAAK,cAAc,GAAG;IAGpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAIhB,OAAO,CAAC,EAAE,WAAW,CAAC;IAItB,
|
|
1
|
+
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAQ,IAAI,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKvD,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAY7E;AAED,KAAK,cAAc,GAAG;IAGpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAIhB,OAAO,CAAC,EAAE,WAAW,CAAC;IAItB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC,eAAe,MAAM,EAAE,CAAC,CA+B9E;AAqBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAKnD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,UAEnC"}
|
package/dist/steps.js
CHANGED
|
@@ -51,10 +51,10 @@ function assertReachable(plan, options) {
|
|
|
51
51
|
if (!app)
|
|
52
52
|
throw new Error(`${options.app} names no app in this deployment`);
|
|
53
53
|
const bastion = environmentOf(plan.config, plan.environment)?.host?.bastion;
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
54
|
+
const expected = options.through;
|
|
55
|
+
if (!expected || expected === bastion)
|
|
56
56
|
return;
|
|
57
|
-
throw new Error(`${options.app}
|
|
57
|
+
throw new Error(`${options.app} migrates through ${expected}, ` +
|
|
58
58
|
`but ${plan.environment} deploys to ${bastion ?? "this machine"}. ` +
|
|
59
59
|
"The step runs on the deploy host, so they have to be the same");
|
|
60
60
|
}
|
package/dist/steps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK5C,6EAA6E;AAC7E,+EAA+E;AAC/E,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,QAAkB;IACjE,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,YAAY;QAAE,OAAO,CAAC,aAAa,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAEpE,OAAO;QACL,0EAA0E;QAC1E,2EAA2E;QAC3E,6CAA6C;QAC7C,aAAa,QAAQ,CAAC,OAAO,EAAE;QAC/B,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,IAAI,IAAI,EAAE,EAAE,CAAC;KACvF,CAAC;AACJ,CAAC;AAiBD,6EAA6E;AAC7E,oEAAoE;AACpE,MAAM,UAAU,OAAO,CAAC,OAAuB;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE3C,OAAO;QACL,KAAK,EAAE,uBAAuB,OAAO,CAAC,GAAG,EAAE;QAC3C,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC;QAE/C,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;YAE1D,mEAAmE;YACnE,wEAAwE;YACxE,wBAAwB;YACxB,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;YAE1E,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B;gBACE,UAAU;gBACV,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;gBAC1D,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5C,gBAAgB;gBAChB,KAAK;gBACL,GAAG,OAAO;aACX,CAAC,IAAI,CAAC,GAAG,CAAC,EACX,GAAG,OAAO,CAAC,GAAG,oBAAoB,CACnC,CAAC;YAEF,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,gDAAgD;AAChD,SAAS,eAAe,CAAC,IAAU,EAAE,OAAuB;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACvE,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,kCAAkC,CAAC,CAAC;IAE5E,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC;IAC5E,MAAM,
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export type SecretRef = {
|
|
|
22
22
|
id: string;
|
|
23
23
|
};
|
|
24
24
|
export type SecretRefs = SecretRef | SecretRef[];
|
|
25
|
+
export type ProxySpec = {
|
|
26
|
+
image?: string;
|
|
27
|
+
maxBodySize?: string;
|
|
28
|
+
server?: string[];
|
|
29
|
+
location?: string[];
|
|
30
|
+
};
|
|
25
31
|
export type ServiceSpec = {
|
|
26
32
|
name: string;
|
|
27
33
|
image: string;
|
|
@@ -92,8 +98,7 @@ export type Deployment = {
|
|
|
92
98
|
project: string;
|
|
93
99
|
environment?: Environment;
|
|
94
100
|
environments?: Record<string, Environment>;
|
|
95
|
-
|
|
96
|
-
proxyImage?: string;
|
|
101
|
+
proxy?: ProxySpec;
|
|
97
102
|
services: ServiceSpec[];
|
|
98
103
|
apps: AppSpec[];
|
|
99
104
|
steps?: AnyStep[];
|
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;CACrC,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;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/build.ts
CHANGED
|
@@ -25,6 +25,9 @@ export type BuildContext = {
|
|
|
25
25
|
files: Record<string, string>;
|
|
26
26
|
branch: string;
|
|
27
27
|
environment: string;
|
|
28
|
+
// Whether an agent is there to forward into the build. A dependency fetched
|
|
29
|
+
// over ssh needs one, and asking for a mount nothing is behind fails outright
|
|
30
|
+
agent?: boolean;
|
|
28
31
|
detail?: (message: string) => void;
|
|
29
32
|
// Prints what the build itself wrote, line by line as it runs
|
|
30
33
|
output?: (line: string) => void;
|
|
@@ -33,7 +36,7 @@ export type BuildContext = {
|
|
|
33
36
|
// Bumped when the pipeline changes shape without the config changing. The tag
|
|
34
37
|
// below is what tells a host it already holds an image, and a host that trusts
|
|
35
38
|
// the commit alone serves the last pipeline's output forever
|
|
36
|
-
const PIPELINE = "
|
|
39
|
+
const PIPELINE = "6";
|
|
37
40
|
|
|
38
41
|
export type BuildResult = {
|
|
39
42
|
release: string;
|
|
@@ -76,6 +79,7 @@ export async function build(
|
|
|
76
79
|
path: app.path && resolve(app.path),
|
|
77
80
|
include: app.include,
|
|
78
81
|
ref: refOf(app, context.branch),
|
|
82
|
+
output: context.output,
|
|
79
83
|
submodules: spec.submodules,
|
|
80
84
|
detail,
|
|
81
85
|
});
|
|
@@ -115,6 +119,7 @@ export async function build(
|
|
|
115
119
|
secrets.files.map((file) => [file.path, file.id]),
|
|
116
120
|
),
|
|
117
121
|
dir: app.dir,
|
|
122
|
+
agent: context.agent,
|
|
118
123
|
}),
|
|
119
124
|
);
|
|
120
125
|
|
|
@@ -127,6 +132,7 @@ export async function build(
|
|
|
127
132
|
);
|
|
128
133
|
|
|
129
134
|
const invocation = {
|
|
135
|
+
ssh: context.agent,
|
|
130
136
|
context: source.tree,
|
|
131
137
|
dockerfile,
|
|
132
138
|
secrets: Object.fromEntries(
|
|
@@ -239,6 +245,9 @@ function fingerprintOf(app: AppSpec, context: BuildContext, release: string) {
|
|
|
239
245
|
.update(PIPELINE)
|
|
240
246
|
.update(release)
|
|
241
247
|
.update(app.dir ?? "")
|
|
248
|
+
// It changes the Dockerfile, so an image built without one is not the
|
|
249
|
+
// image a build with one would produce
|
|
250
|
+
.update(String(context.agent ?? false))
|
|
242
251
|
.update(JSON.stringify(app.build))
|
|
243
252
|
.update(context.env)
|
|
244
253
|
.update(JSON.stringify(Object.entries(context.files).sort()))
|
package/src/cli/agent.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { execFileSync } from "node:child_process";
|
|
|
3
3
|
import { environmentOf } from "../config.js";
|
|
4
4
|
import type { Deployment } from "../types.js";
|
|
5
5
|
|
|
6
|
-
// Cloning private repositories and
|
|
7
|
-
// agent, so a deploy without one fails halfway rather than at the start
|
|
6
|
+
// Cloning private repositories and reaching the deploy host both go through
|
|
7
|
+
// the agent, so a deploy without one fails halfway rather than at the start
|
|
8
8
|
|
|
9
9
|
// Asked before one is demanded. A runner has no keys and no way to be prompted
|
|
10
10
|
// for one, and a deployment that reaches no other machine and clones nothing
|
package/src/cli/config.ts
CHANGED
|
@@ -42,26 +42,46 @@ export async function loadConfig(explicit?: string): Promise<Deployment> {
|
|
|
42
42
|
const path = explicit ? resolve(explicit) : discover(process.cwd());
|
|
43
43
|
const config = defaultOf(await load(path), path) as Deployment;
|
|
44
44
|
|
|
45
|
+
const manifest = manifestOf(explicit ? dirname(path) : process.cwd());
|
|
45
46
|
const beside = await loadEnvironments(dirname(path));
|
|
46
|
-
const named = await loadNamed(manifestOf(explicit ? dirname(path) : process.cwd()));
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
// The directory package.json names is read whether or not the deployment
|
|
49
|
+
// turned out to be in it, so environments may sit together under one roof
|
|
50
|
+
// with the deployment at the root above them
|
|
51
|
+
const declared = directoryOf(manifest);
|
|
52
|
+
const under = declared && declared !== dirname(path) ? await loadEnvironments(declared) : {};
|
|
53
|
+
|
|
54
|
+
const named = await loadNamed(manifest);
|
|
55
|
+
const found = { ...beside, ...under };
|
|
56
|
+
|
|
57
|
+
for (const name of Object.keys(under)) {
|
|
49
58
|
if (!beside[name]) continue;
|
|
50
59
|
|
|
60
|
+
throw new Error(
|
|
61
|
+
`${name} sits both beside the deployment and in ${declared}, ` +
|
|
62
|
+
"and an environment comes from one place or the other",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const name of Object.keys(named)) {
|
|
67
|
+
if (!found[name]) continue;
|
|
68
|
+
|
|
51
69
|
throw new Error(
|
|
52
70
|
`${name} is named by package.json and also sits beside the deployment. ` +
|
|
53
71
|
"An environment comes from one place or the other",
|
|
54
72
|
);
|
|
55
73
|
}
|
|
56
74
|
|
|
57
|
-
return { ...rooted(config, dirname(path)), environments: { ...
|
|
75
|
+
return { ...rooted(config, dirname(path)), environments: { ...found, ...named } };
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
// A source path belongs to the file that named it, not to wherever the command
|
|
61
79
|
// was run. Resolving it here is what lets a deploy from a workspace and one
|
|
62
80
|
// from the root build the same tree
|
|
63
81
|
function rooted(config: Deployment, directory: string): Deployment {
|
|
64
|
-
|
|
82
|
+
// A file that never called defineDeployment can export anything, and the
|
|
83
|
+
// message worth getting is the one topologyFor gives rather than a TypeError
|
|
84
|
+
if (!(config.apps ?? []).some((app) => app.path)) return config;
|
|
65
85
|
|
|
66
86
|
return {
|
|
67
87
|
...config,
|
|
@@ -99,23 +119,43 @@ async function loadNamed(manifest: Manifest | undefined) {
|
|
|
99
119
|
// likely to be run from a workspace inside it as from there
|
|
100
120
|
export function discover(from: string): string {
|
|
101
121
|
let directory = from;
|
|
122
|
+
// Where something addressed to redkite was seen but no deployment. Naming it
|
|
123
|
+
// is the difference between "there is nothing here" and "the file you have
|
|
124
|
+
// is an environment, and an environment is not a deployment"
|
|
125
|
+
const nearby: string[] = [];
|
|
102
126
|
|
|
103
127
|
for (;;) {
|
|
104
128
|
const declared = directoryFrom(directory);
|
|
105
129
|
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
|
|
130
|
+
// Naming a directory that is not there is a mistake worth stopping for.
|
|
131
|
+
// One that is there and holds no deployment is not: it may hold only the
|
|
132
|
+
// environments, and the deployment may sit at the root above them
|
|
133
|
+
if (declared && !existsSync(declared)) missing(declared, directory);
|
|
134
|
+
|
|
135
|
+
const there = declared && found(declared);
|
|
136
|
+
if (there) return there;
|
|
109
137
|
|
|
110
138
|
const here = found(directory);
|
|
111
139
|
if (here) return here;
|
|
112
140
|
|
|
141
|
+
for (const place of declared ? [declared, directory] : [directory]) {
|
|
142
|
+
for (const entry of environmentsAt(place)) nearby.push(join(place, entry));
|
|
143
|
+
}
|
|
144
|
+
|
|
113
145
|
const parent = dirname(directory);
|
|
114
146
|
if (parent === directory) break;
|
|
115
147
|
|
|
116
148
|
directory = parent;
|
|
117
149
|
}
|
|
118
150
|
|
|
151
|
+
if (nearby.length > 0) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`No deployment found, but ${nearby.join(" and ")} reads as an environment. ` +
|
|
154
|
+
"An environment says which branch and which subnet; the deployment says " +
|
|
155
|
+
"the project, the apps and the services, and is redkite.config.ts",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
119
159
|
throw new Error(
|
|
120
160
|
`No redkite.config.ts found in ${from} or any directory above it. A deployment ` +
|
|
121
161
|
'is one file at the root of the project, or wherever package.json\'s ' +
|
|
@@ -123,6 +163,17 @@ export function discover(from: string): string {
|
|
|
123
163
|
);
|
|
124
164
|
}
|
|
125
165
|
|
|
166
|
+
// The names beside a deployment that would be read as environments, for a
|
|
167
|
+
// message that can say what was there instead of what was not
|
|
168
|
+
function environmentsAt(directory: string) {
|
|
169
|
+
if (!existsSync(directory)) return [];
|
|
170
|
+
|
|
171
|
+
return readdirSync(directory)
|
|
172
|
+
.filter((entry) => !CANDIDATES.includes(entry))
|
|
173
|
+
.filter((entry) => PER_ENVIRONMENT.test(entry))
|
|
174
|
+
.sort();
|
|
175
|
+
}
|
|
176
|
+
|
|
126
177
|
// Every environment that lives in a file of its own, keyed by the name in it
|
|
127
178
|
export async function loadEnvironments(directory: string) {
|
|
128
179
|
const environments: Record<string, Environment> = {};
|
|
@@ -165,8 +216,7 @@ function found(directory: string) {
|
|
|
165
216
|
|
|
166
217
|
function missing(declared: string, from: string): never {
|
|
167
218
|
throw new Error(
|
|
168
|
-
`${join(from, "package.json")} points redkite at ${declared}, which
|
|
169
|
-
`redkite.config.${EXTENSIONS.join(", redkite.config.")}`,
|
|
219
|
+
`${join(from, "package.json")} points redkite at ${declared}, which is not there`,
|
|
170
220
|
);
|
|
171
221
|
}
|
|
172
222
|
|
|
@@ -193,6 +243,14 @@ function manifestAt(directory: string): Manifest | undefined {
|
|
|
193
243
|
}
|
|
194
244
|
}
|
|
195
245
|
|
|
246
|
+
// Where the project starts, which is where a .env belongs. The nearest
|
|
247
|
+
// package.json above wherever this was run, and the directory itself when
|
|
248
|
+
// there is none
|
|
249
|
+
export function projectRoot(explicit?: string) {
|
|
250
|
+
const from = explicit ? dirname(resolve(explicit)) : process.cwd();
|
|
251
|
+
return manifestOf(from)?.root ?? from;
|
|
252
|
+
}
|
|
253
|
+
|
|
196
254
|
// The nearest one above wherever this was run, which is the same walk the
|
|
197
255
|
// config itself is found by
|
|
198
256
|
function manifestOf(from: string) {
|
|
@@ -209,11 +267,17 @@ function manifestOf(from: string) {
|
|
|
209
267
|
}
|
|
210
268
|
}
|
|
211
269
|
|
|
212
|
-
// package.json says where
|
|
213
|
-
//
|
|
270
|
+
// package.json says where redkite's files live, for a repository that would
|
|
271
|
+
// rather not keep them at its root
|
|
214
272
|
function directoryFrom(directory: string) {
|
|
215
|
-
|
|
216
|
-
|
|
273
|
+
return directoryOf(manifestAt(directory));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function directoryOf(manifest: Manifest | undefined) {
|
|
277
|
+
if (!manifest) return undefined;
|
|
278
|
+
|
|
279
|
+
const declared = manifest.redkite.directory;
|
|
280
|
+
return typeof declared === "string" ? resolve(manifest.root, declared) : undefined;
|
|
217
281
|
}
|
|
218
282
|
|
|
219
283
|
function defaultOf(module: unknown, path: string) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { parseEnv } from "../environment.js";
|
|
5
|
+
|
|
6
|
+
// The credentials a deploy needs are the one thing that cannot live in the
|
|
7
|
+
// config, so they live beside it. Read here rather than by a plugin, because
|
|
8
|
+
// which file answers depends on the environment being deployed and a plugin
|
|
9
|
+
// is handed neither the directory nor the name.
|
|
10
|
+
|
|
11
|
+
// Most specific first. A deploy file is for what only a deploy needs, and it
|
|
12
|
+
// wins over the one the application itself reads
|
|
13
|
+
const NAMES = (environment: string) => [
|
|
14
|
+
`.env.${environment}.deploy`,
|
|
15
|
+
`.env.${environment}`,
|
|
16
|
+
".env",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// Only what is missing. Anything already in the environment was set by the
|
|
20
|
+
// person running this or by the job, and neither should be talked over
|
|
21
|
+
export function loadDotenv(directory: string, environment: string) {
|
|
22
|
+
const read: string[] = [];
|
|
23
|
+
|
|
24
|
+
for (const name of NAMES(environment)) {
|
|
25
|
+
const path = join(directory, name);
|
|
26
|
+
if (!existsSync(path)) continue;
|
|
27
|
+
|
|
28
|
+
read.push(name);
|
|
29
|
+
for (const [key, value] of Object.entries(parseEnv(readFileSync(path, "utf8")))) {
|
|
30
|
+
process.env[key] ??= value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return read;
|
|
35
|
+
}
|
package/src/cli/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Docker } from "../docker.js";
|
|
|
4
4
|
import type { Host } from "../host.js";
|
|
5
5
|
import { localHost } from "../localHost.js";
|
|
6
6
|
import { silent, type Log } from "../log.js";
|
|
7
|
-
import {
|
|
7
|
+
import { renderProxy } from "../services/proxy.js";
|
|
8
8
|
import { addressOf, RUNS, SLOTS, type Run } from "../pipeline.js";
|
|
9
9
|
import { listRefs, type SecretStores } from "../secrets/refs.js";
|
|
10
10
|
import { pluginSteps, storeFor } from "../plugin.js";
|
|
@@ -15,7 +15,8 @@ import { topologyFor, type Topology } from "../topology.js";
|
|
|
15
15
|
import type { Deployment, DeployHost } from "../types.js";
|
|
16
16
|
|
|
17
17
|
import { needsAgent, requireAgent } from "./agent.js";
|
|
18
|
-
import { loadConfig } from "./config.js";
|
|
18
|
+
import { loadConfig, projectRoot } from "./config.js";
|
|
19
|
+
import { loadDotenv } from "./dotenv.js";
|
|
19
20
|
import { createLog, describeFailure } from "./log.js";
|
|
20
21
|
|
|
21
22
|
// One command that reads the config and does everything under it: the agent,
|
|
@@ -146,7 +147,11 @@ async function dispatch(argv: string[]) {
|
|
|
146
147
|
|
|
147
148
|
const configPath = flag(argv, "--config");
|
|
148
149
|
|
|
149
|
-
|
|
150
|
+
// Before anything reads a credential out of the environment, and only where
|
|
151
|
+
// the environment does not already say. What the job set wins over a file
|
|
152
|
+
const read = loadDotenv(projectRoot(configPath), environment);
|
|
153
|
+
|
|
154
|
+
if (command === "plan") return await plan(environment, configPath, read);
|
|
150
155
|
if (command === "rollback" || command === "down") {
|
|
151
156
|
return await recover(command, environment, configPath);
|
|
152
157
|
}
|
|
@@ -205,13 +210,14 @@ function asLog(say: (message: string) => void): Log {
|
|
|
205
210
|
return Object.assign(say, { warn: say, fail: say, done: say, step: () => silent.step("") });
|
|
206
211
|
}
|
|
207
212
|
|
|
208
|
-
async function plan(environment: string, configPath?: string) {
|
|
213
|
+
async function plan(environment: string, configPath?: string, read: string[] = []) {
|
|
209
214
|
const config = await loadConfig(configPath);
|
|
210
215
|
const topology = topologyFor(config, environment);
|
|
211
216
|
|
|
212
217
|
const say = (message = "") => process.stdout.write(`${message}\n`);
|
|
213
218
|
|
|
214
219
|
say(`# ${config.project} · ${environment}\n`);
|
|
220
|
+
if (read.length > 0) say(`read ${read.join(", ")}`);
|
|
215
221
|
say(`network ${topology.network} ${topology.cidr}`);
|
|
216
222
|
say(`branch ${topology.branch}`);
|
|
217
223
|
// A verify environment publishes nothing, because nothing in one serves
|
|
@@ -260,7 +266,7 @@ async function plan(environment: string, configPath?: string) {
|
|
|
260
266
|
if (!serves) return;
|
|
261
267
|
|
|
262
268
|
say(`\n# rendered nginx ${"-".repeat(44)}\n`);
|
|
263
|
-
say(
|
|
269
|
+
say(renderProxy(topology, config.proxy));
|
|
264
270
|
}
|
|
265
271
|
|
|
266
272
|
// What is running against what this file says should be. Services outlive a
|