@olivervea/pipelines 2.0.0-beta.18 → 2.0.0-beta.19
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/package.json +4 -2
- package/src/assets.d.ts +2 -2
- package/src/build/build.ts +111 -43
- package/src/build/cli.ts +28 -21
- package/src/build/elf.ts +8 -7
- package/src/build/hashes.ts +61 -28
- package/src/build/project.ts +69 -30
- package/src/builder/pipeline.ts +274 -102
- package/src/builder/refs.ts +12 -6
- package/src/core/brands.ts +6 -6
- package/src/core/config-refs.ts +46 -20
- package/src/core/config.ts +110 -33
- package/src/core/external.ts +30 -12
- package/src/core/handlers.ts +54 -14
- package/src/core/models.ts +29 -14
- package/src/core/origin.ts +7 -4
- package/src/core/secrets.ts +2 -2
- package/src/core/steps.ts +39 -23
- package/src/core/types.ts +5 -1
- package/src/core/webhooks.ts +21 -7
- package/src/ctx/files.ts +111 -40
- package/src/ctx/index.ts +75 -34
- package/src/ctx/sh.ts +104 -44
- package/src/ctx/types.ts +4 -4
- package/src/describe/describe.ts +550 -196
- package/src/describe/manifest-schema.ts +210 -80
- package/src/describe/mapper-source.ts +249 -104
- package/src/describe/record.ts +67 -37
- package/src/dev/cli.ts +64 -34
- package/src/harness/env.ts +33 -27
- package/src/harness/execute.ts +55 -29
- package/src/harness/index.ts +21 -8
- package/src/harness/main.ts +197 -74
- package/src/harness/result.ts +38 -22
- package/src/harness/validate.ts +62 -19
- package/src/index.ts +123 -14
- package/src/library/checks.ts +11 -6
- package/src/library/compose-deploy.ts +40 -23
- package/src/library/github-source.ts +69 -39
- package/src/library/helm-deploy-ssh.ts +213 -76
- package/src/library/helm-deploy.ts +263 -85
- package/src/library/http-health.ts +7 -5
- package/src/library/image-build.ts +293 -117
- package/src/library/index.ts +47 -15
- package/src/library/models.ts +17 -9
- package/src/library/ssh.ts +31 -14
- package/src/testing/index.ts +63 -24
- package/src/util/canonical.ts +7 -4
- package/src/util/handler-hash.ts +15 -5
- package/src/util/hash.ts +5 -5
- package/src/util/tar.ts +74 -37
package/src/build/project.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Layout of a pipeline directory and the identity of the SDK building it.
|
|
2
|
-
import { existsSync, readdirSync, readFileSync, statSync } from
|
|
3
|
-
import { dirname, join, relative, resolve } from
|
|
4
|
-
import { isImplementation } from
|
|
5
|
-
import { sha256Hex } from
|
|
6
|
-
import type { HarnessInfo } from
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
4
|
+
import { isImplementation } from '../core/handlers.ts';
|
|
5
|
+
import { sha256Hex } from '../util/hash.ts';
|
|
6
|
+
import type { HarnessInfo } from '../util/handler-hash.ts';
|
|
7
7
|
|
|
8
|
-
export const SDK_ROOT = resolve(import.meta.dir,
|
|
8
|
+
export const SDK_ROOT = resolve(import.meta.dir, '../..');
|
|
9
9
|
|
|
10
10
|
export interface Project {
|
|
11
11
|
dir: string;
|
|
@@ -17,33 +17,56 @@ export interface Project {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export class ProjectError extends Error {
|
|
20
|
-
override name =
|
|
20
|
+
override name = 'ProjectError';
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export async function loadProject(dirArg: string): Promise<Project> {
|
|
24
24
|
const dir = resolve(dirArg);
|
|
25
|
-
if (!existsSync(dir) || !statSync(dir).isDirectory())
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory())
|
|
26
|
+
throw new ProjectError(`${dirArg} is not a directory`);
|
|
27
|
+
const pipelineFile = join(dir, 'pipeline.ts');
|
|
28
|
+
if (!existsSync(pipelineFile))
|
|
29
|
+
throw new ProjectError(
|
|
30
|
+
`${join(dirArg, 'pipeline.ts')} not found (it must default-export pipeline({...}))`,
|
|
31
|
+
);
|
|
32
|
+
const contractFiles = ['pipeline.ts', 'models.ts']
|
|
33
|
+
.map((f) => join(dir, f))
|
|
34
|
+
.filter((f) => existsSync(f));
|
|
35
|
+
const hdir = join(dir, 'handlers');
|
|
30
36
|
const files = existsSync(hdir)
|
|
31
37
|
? readdirSync(hdir)
|
|
32
|
-
.filter(
|
|
38
|
+
.filter(
|
|
39
|
+
(f) =>
|
|
40
|
+
f.endsWith('.ts') &&
|
|
41
|
+
!f.endsWith('.test.ts') &&
|
|
42
|
+
!f.endsWith('.d.ts') &&
|
|
43
|
+
statSync(join(hdir, f)).isFile(),
|
|
44
|
+
)
|
|
33
45
|
.sort()
|
|
34
46
|
: [];
|
|
35
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
dir,
|
|
49
|
+
pipelineFile,
|
|
50
|
+
contractFiles,
|
|
51
|
+
handlers: await resolveHandlers(hdir, files),
|
|
52
|
+
};
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
/** The default export of pipeline.ts. */
|
|
39
56
|
export async function loadPipeline(project: Project): Promise<unknown> {
|
|
40
57
|
const mod = (await import(project.pipelineFile)) as { default?: unknown };
|
|
41
|
-
if (!mod.default)
|
|
58
|
+
if (!mod.default)
|
|
59
|
+
throw new ProjectError(
|
|
60
|
+
`${project.pipelineFile} has no default export (export default pipeline({...})...)`,
|
|
61
|
+
);
|
|
42
62
|
return mod.default;
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
/** Pairs each handler file with the step its default export implements (file names don't matter). */
|
|
46
|
-
async function resolveHandlers(
|
|
66
|
+
async function resolveHandlers(
|
|
67
|
+
hdir: string,
|
|
68
|
+
files: string[],
|
|
69
|
+
): Promise<[string, string][]> {
|
|
47
70
|
const byStep = new Map<string, string>();
|
|
48
71
|
for (const f of files) {
|
|
49
72
|
const file = join(hdir, f);
|
|
@@ -51,13 +74,20 @@ async function resolveHandlers(hdir: string, files: string[]): Promise<[string,
|
|
|
51
74
|
try {
|
|
52
75
|
impl = ((await import(file)) as { default?: unknown }).default;
|
|
53
76
|
} catch (e) {
|
|
54
|
-
throw new ProjectError(
|
|
77
|
+
throw new ProjectError(
|
|
78
|
+
`handlers/${f} failed to load: ${(e as Error)?.message ?? String(e)}`,
|
|
79
|
+
);
|
|
55
80
|
}
|
|
56
81
|
if (!isImplementation(impl))
|
|
57
|
-
throw new ProjectError(
|
|
82
|
+
throw new ProjectError(
|
|
83
|
+
`handlers/${f} must default-export implement(<step>, …); put shared code in a subfolder such as handlers/lib/`,
|
|
84
|
+
);
|
|
58
85
|
const step = (impl.step as { name: string }).name;
|
|
59
86
|
const other = byStep.get(step);
|
|
60
|
-
if (other)
|
|
87
|
+
if (other)
|
|
88
|
+
throw new ProjectError(
|
|
89
|
+
`handlers/${other.slice(hdir.length + 1)} and handlers/${f} both implement step '${step}'`,
|
|
90
|
+
);
|
|
61
91
|
byStep.set(step, file);
|
|
62
92
|
}
|
|
63
93
|
return [...byStep].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
@@ -80,28 +110,37 @@ let cached: HarnessInfo | undefined;
|
|
|
80
110
|
*/
|
|
81
111
|
export function harnessInfo(): HarnessInfo {
|
|
82
112
|
if (cached) return cached;
|
|
83
|
-
const pkg = JSON.parse(readFileSync(join(SDK_ROOT,
|
|
84
|
-
|
|
113
|
+
const pkg = JSON.parse(readFileSync(join(SDK_ROOT, 'package.json'), 'utf8')) as {
|
|
114
|
+
version: string;
|
|
115
|
+
};
|
|
116
|
+
const src = join(SDK_ROOT, 'src');
|
|
85
117
|
const files = listFiles(src)
|
|
86
|
-
.map((f) => relative(src, f).split(
|
|
87
|
-
.filter(
|
|
118
|
+
.map((f) => relative(src, f).split('\\').join('/'))
|
|
119
|
+
.filter(
|
|
120
|
+
(f) =>
|
|
121
|
+
!f.startsWith('build/') &&
|
|
122
|
+
!f.startsWith('dev/') &&
|
|
123
|
+
!f.startsWith('testing/') &&
|
|
124
|
+
f.endsWith('.ts'),
|
|
125
|
+
)
|
|
88
126
|
.sort();
|
|
89
|
-
const h = new Bun.CryptoHasher(
|
|
127
|
+
const h = new Bun.CryptoHasher('sha256');
|
|
90
128
|
for (const f of files) h.update(`${f}\0${sha256Hex(readFileSync(join(src, f)))}\n`);
|
|
91
|
-
let zodVersion =
|
|
129
|
+
let zodVersion = 'unknown';
|
|
92
130
|
try {
|
|
93
|
-
const zodPkg = Bun.resolveSync(
|
|
94
|
-
zodVersion = (JSON.parse(readFileSync(zodPkg,
|
|
131
|
+
const zodPkg = Bun.resolveSync('zod/package.json', SDK_ROOT);
|
|
132
|
+
zodVersion = (JSON.parse(readFileSync(zodPkg, 'utf8')) as { version: string })
|
|
133
|
+
.version;
|
|
95
134
|
} catch {
|
|
96
135
|
/* keep unknown */
|
|
97
136
|
}
|
|
98
137
|
h.update(`zod@${zodVersion}\n`);
|
|
99
|
-
cached = { bun: Bun.version, sdk: pkg.version, sdkHash:
|
|
138
|
+
cached = { bun: Bun.version, sdk: pkg.version, sdkHash: 'sha256:' + h.digest('hex') };
|
|
100
139
|
return cached;
|
|
101
140
|
}
|
|
102
141
|
|
|
103
142
|
export const relPosix = (from: string, to: string) => {
|
|
104
|
-
const r = relative(from, to).split(
|
|
105
|
-
return r.startsWith(
|
|
143
|
+
const r = relative(from, to).split('\\').join('/');
|
|
144
|
+
return r.startsWith('.') ? r : `./${r}`;
|
|
106
145
|
};
|
|
107
146
|
export { dirname };
|