@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/dev/cli.ts
CHANGED
|
@@ -4,27 +4,48 @@
|
|
|
4
4
|
// olve-dev run <dir> <step> [--input-file f] [--config-file f] [--olve-dir d] [--secret NAME=value]...
|
|
5
5
|
// olve-dev map-trigger <dir> <trigger> --event-file f [--olve-dir d]
|
|
6
6
|
// $OLVE_DIR defaults to <dir>/.olve; outputs land in <dir>/.olve/work/.
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import {
|
|
8
|
+
copyFileSync,
|
|
9
|
+
existsSync,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from 'node:fs';
|
|
14
|
+
import { join, resolve } from 'node:path';
|
|
15
|
+
import { parseArgs } from 'node:util';
|
|
16
|
+
import { runHarness, type HarnessConfig } from '../harness/main.ts';
|
|
17
|
+
import { EXIT } from '../harness/exit.ts';
|
|
18
|
+
import { handlerHashes, kindHashes } from '../build/hashes.ts';
|
|
19
|
+
import {
|
|
20
|
+
harnessInfo,
|
|
21
|
+
loadPipeline,
|
|
22
|
+
loadProject,
|
|
23
|
+
ProjectError,
|
|
24
|
+
} from '../build/project.ts';
|
|
14
25
|
|
|
15
26
|
const USAGE = `usage: olve-dev describe <dir> [--sentinels]
|
|
16
27
|
olve-dev run <dir> <step> [--input-file f] [--config-file f] [--olve-dir d] [--secret NAME=value]...
|
|
17
28
|
olve-dev map-trigger <dir> <trigger> --event-file f [--olve-dir d]`;
|
|
18
29
|
|
|
19
|
-
export async function devConfig(
|
|
30
|
+
export async function devConfig(
|
|
31
|
+
dir: string,
|
|
32
|
+
withHashes: boolean,
|
|
33
|
+
): Promise<HarnessConfig> {
|
|
20
34
|
const project = await loadProject(dir);
|
|
21
35
|
const pipeline = await loadPipeline(project);
|
|
22
36
|
const harness = harnessInfo();
|
|
23
37
|
const hashes = withHashes ? await handlerHashes(project, harness) : {};
|
|
24
38
|
return {
|
|
25
39
|
pipeline,
|
|
26
|
-
handlers: Object.fromEntries(
|
|
27
|
-
|
|
40
|
+
handlers: Object.fromEntries(
|
|
41
|
+
project.handlers.map(([name, file]) => [
|
|
42
|
+
name,
|
|
43
|
+
() => import(file) as Promise<{ default: unknown }>,
|
|
44
|
+
]),
|
|
45
|
+
),
|
|
46
|
+
handlerHashes: Object.fromEntries(
|
|
47
|
+
Object.entries(hashes).map(([k, v]) => [k, v.handlerHash]),
|
|
48
|
+
),
|
|
28
49
|
...(withHashes ? { kindHashes: await kindHashes(project, pipeline) } : {}),
|
|
29
50
|
harness,
|
|
30
51
|
};
|
|
@@ -37,13 +58,13 @@ export async function devMain(argv: string[]): Promise<number> {
|
|
|
37
58
|
args: argv,
|
|
38
59
|
allowPositionals: true,
|
|
39
60
|
options: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
secret: { type:
|
|
45
|
-
sentinels: { type:
|
|
46
|
-
help: { type:
|
|
61
|
+
'input-file': { type: 'string' },
|
|
62
|
+
'config-file': { type: 'string' },
|
|
63
|
+
'event-file': { type: 'string' },
|
|
64
|
+
'olve-dir': { type: 'string' },
|
|
65
|
+
secret: { type: 'string', multiple: true },
|
|
66
|
+
sentinels: { type: 'boolean', default: false },
|
|
67
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
47
68
|
},
|
|
48
69
|
});
|
|
49
70
|
} catch (e) {
|
|
@@ -51,34 +72,43 @@ export async function devMain(argv: string[]): Promise<number> {
|
|
|
51
72
|
return EXIT.usage;
|
|
52
73
|
}
|
|
53
74
|
const { values, positionals } = parsed;
|
|
54
|
-
if (values.help) return console.log(USAGE), 0;
|
|
75
|
+
if (values.help) return (console.log(USAGE), 0);
|
|
55
76
|
const [mode, dir, name] = positionals;
|
|
56
|
-
if (!mode || !dir) return console.error(USAGE), EXIT.usage;
|
|
77
|
+
if (!mode || !dir) return (console.error(USAGE), EXIT.usage);
|
|
57
78
|
try {
|
|
58
|
-
if (mode ===
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
if (mode === 'describe')
|
|
80
|
+
return await runHarness(await devConfig(dir, true), [
|
|
81
|
+
'describe',
|
|
82
|
+
...(values.sentinels ? ['--sentinels'] : []),
|
|
83
|
+
]);
|
|
84
|
+
if (mode !== 'run' && mode !== 'map-trigger')
|
|
85
|
+
return (console.error(USAGE), EXIT.usage);
|
|
86
|
+
if (!name) return (console.error(USAGE), EXIT.usage);
|
|
87
|
+
const file = mode === 'run' ? values['input-file'] : values['event-file'];
|
|
88
|
+
if (mode === 'map-trigger' && !file)
|
|
89
|
+
return (console.error('--event-file is required'), EXIT.usage);
|
|
90
|
+
const olveDir = resolve(values['olve-dir'] ?? join(dir, '.olve'));
|
|
64
91
|
mkdirSync(olveDir, { recursive: true });
|
|
65
92
|
process.env.OLVE_DIR = olveDir;
|
|
66
|
-
process.env.TMPDIR ??= join(olveDir,
|
|
93
|
+
process.env.TMPDIR ??= join(olveDir, 'tmp');
|
|
67
94
|
for (const s of values.secret ?? []) {
|
|
68
|
-
const i = s.indexOf(
|
|
69
|
-
if (i <= 0)
|
|
95
|
+
const i = s.indexOf('=');
|
|
96
|
+
if (i <= 0)
|
|
97
|
+
return (console.error(`--secret expects NAME=value, got '${s}'`), EXIT.usage);
|
|
70
98
|
process.env[s.slice(0, i)] = s.slice(i + 1);
|
|
71
99
|
}
|
|
72
|
-
if (file) copyFileSync(resolve(file), join(olveDir,
|
|
73
|
-
if (mode ===
|
|
74
|
-
const inputFile = join(olveDir,
|
|
75
|
-
const input = (
|
|
76
|
-
|
|
100
|
+
if (file) copyFileSync(resolve(file), join(olveDir, 'input.json'));
|
|
101
|
+
if (mode === 'run' && values['config-file']) {
|
|
102
|
+
const inputFile = join(olveDir, 'input.json');
|
|
103
|
+
const input = (
|
|
104
|
+
existsSync(inputFile) ? JSON.parse(readFileSync(inputFile, 'utf8')) : {}
|
|
105
|
+
) as Record<string, unknown>;
|
|
106
|
+
input.$config = JSON.parse(readFileSync(resolve(values['config-file']), 'utf8'));
|
|
77
107
|
writeFileSync(inputFile, JSON.stringify(input));
|
|
78
108
|
}
|
|
79
109
|
return await runHarness(await devConfig(dir, false), [mode, name]);
|
|
80
110
|
} catch (e) {
|
|
81
|
-
if (e instanceof ProjectError) return console.error(e.message), EXIT.configInvalid;
|
|
111
|
+
if (e instanceof ProjectError) return (console.error(e.message), EXIT.configInvalid);
|
|
82
112
|
console.error((e as Error)?.stack ?? String(e));
|
|
83
113
|
return EXIT.configInvalid;
|
|
84
114
|
}
|
package/src/harness/env.ts
CHANGED
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
// The environment contract between the service and the harness. Documented in README.md.
|
|
2
|
-
import { join } from
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
|
|
4
4
|
export const ENV = {
|
|
5
5
|
/** Root of the harness IO directory (default /olve). */
|
|
6
|
-
dir:
|
|
7
|
-
pipeline:
|
|
8
|
-
runId:
|
|
9
|
-
run:
|
|
10
|
-
attempt:
|
|
11
|
-
versionStamp:
|
|
6
|
+
dir: 'OLVE_DIR',
|
|
7
|
+
pipeline: 'OLVE_PIPELINE',
|
|
8
|
+
runId: 'OLVE_RUN_ID',
|
|
9
|
+
run: 'OLVE_RUN',
|
|
10
|
+
attempt: 'OLVE_ATTEMPT',
|
|
11
|
+
versionStamp: 'OLVE_VERSION_STAMP',
|
|
12
12
|
/** Pre-signed PUT for result.tar.gz (run / map-trigger). Optional. */
|
|
13
|
-
resultUrl:
|
|
13
|
+
resultUrl: 'OLVE_RESULT_URL',
|
|
14
14
|
/** JSON object: file key (`<run>/<step>/<attempt>/<path>`) → pre-signed GET URL. Optional. */
|
|
15
|
-
fileUrls:
|
|
15
|
+
fileUrls: 'OLVE_FILE_URLS',
|
|
16
16
|
/** JSON object: `<step>/<input>` → callback URL of that external input in this run (`ctx.inputUrl`). Optional. */
|
|
17
|
-
callbackUrls:
|
|
17
|
+
callbackUrls: 'OLVE_CALLBACK_URLS',
|
|
18
18
|
/** Base URL for file downloads: GET `<base>/<run>/<step>/<attempt>/<object path>`. Optional. */
|
|
19
|
-
filesBaseUrl:
|
|
19
|
+
filesBaseUrl: 'OLVE_FILES_BASE_URL',
|
|
20
20
|
/** Bearer token sent with OLVE_FILES_BASE_URL requests. Optional. */
|
|
21
|
-
filesToken:
|
|
21
|
+
filesToken: 'OLVE_FILES_TOKEN',
|
|
22
22
|
/** Local directory laid out as `<run>/<step>/<attempt>/files/<object path>` (dev). Optional. */
|
|
23
|
-
filesDir:
|
|
23
|
+
filesDir: 'OLVE_FILES_DIR',
|
|
24
24
|
} as const;
|
|
25
25
|
|
|
26
26
|
/** Env vars never passed to child processes (they carry credentials for the harness only). */
|
|
27
|
-
export const PRIVATE_ENV: readonly string[] = [
|
|
27
|
+
export const PRIVATE_ENV: readonly string[] = [
|
|
28
|
+
ENV.resultUrl,
|
|
29
|
+
ENV.fileUrls,
|
|
30
|
+
ENV.filesToken,
|
|
31
|
+
ENV.callbackUrls,
|
|
32
|
+
];
|
|
28
33
|
|
|
29
34
|
/** `OLVE_CALLBACK_URLS`, parsed; empty when unset or malformed. */
|
|
30
35
|
export function callbackUrlsFromEnv(): Record<string, string> {
|
|
@@ -32,41 +37,42 @@ export function callbackUrlsFromEnv(): Record<string, string> {
|
|
|
32
37
|
if (!raw) return {};
|
|
33
38
|
try {
|
|
34
39
|
const parsed: unknown = JSON.parse(raw);
|
|
35
|
-
return parsed && typeof parsed ===
|
|
40
|
+
return parsed && typeof parsed === 'object' ? (parsed as Record<string, string>) : {};
|
|
36
41
|
} catch {
|
|
37
42
|
return {};
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
export const olveDir = () => process.env[ENV.dir] ||
|
|
46
|
+
export const olveDir = () => process.env[ENV.dir] || '/olve';
|
|
42
47
|
export const paths = () => {
|
|
43
48
|
const root = olveDir();
|
|
44
49
|
return {
|
|
45
50
|
root,
|
|
46
|
-
input: join(root,
|
|
47
|
-
work: join(root,
|
|
48
|
-
output: join(root,
|
|
49
|
-
files: join(root,
|
|
50
|
-
tmp: join(root,
|
|
51
|
-
fileUrls: join(root,
|
|
51
|
+
input: join(root, 'input.json'),
|
|
52
|
+
work: join(root, 'work'),
|
|
53
|
+
output: join(root, 'work', 'output.json'),
|
|
54
|
+
files: join(root, 'work', 'files'),
|
|
55
|
+
tmp: join(root, 'tmp'),
|
|
56
|
+
fileUrls: join(root, 'files.json'),
|
|
52
57
|
};
|
|
53
58
|
};
|
|
54
59
|
|
|
55
60
|
function int(name: string, fallback: number): number {
|
|
56
61
|
const v = process.env[name];
|
|
57
|
-
if (v === undefined || v ===
|
|
62
|
+
if (v === undefined || v === '') return fallback;
|
|
58
63
|
const n = Number(v);
|
|
59
|
-
if (!Number.isInteger(n) || n < 0)
|
|
64
|
+
if (!Number.isInteger(n) || n < 0)
|
|
65
|
+
throw new Error(`${name} must be a non-negative integer, got '${v}'`);
|
|
60
66
|
return n;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
export function runInfoFromEnv(step: string) {
|
|
64
70
|
return {
|
|
65
|
-
pipeline: process.env[ENV.pipeline] ??
|
|
66
|
-
id: process.env[ENV.runId] ??
|
|
71
|
+
pipeline: process.env[ENV.pipeline] ?? 'local',
|
|
72
|
+
id: process.env[ENV.runId] ?? 'local',
|
|
67
73
|
number: int(ENV.run, 0),
|
|
68
74
|
attempt: Math.max(1, int(ENV.attempt, 1)),
|
|
69
75
|
step,
|
|
70
|
-
version: process.env[ENV.versionStamp] ??
|
|
76
|
+
version: process.env[ENV.versionStamp] ?? '0.0.0-local',
|
|
71
77
|
};
|
|
72
78
|
}
|
package/src/harness/execute.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// The shared execution path: validate input → handler → validate output → envelope.
|
|
2
2
|
// Used by the compiled harness (`run`), the dev runner and testHandler.
|
|
3
|
-
import { existsSync } from
|
|
4
|
-
import { join } from
|
|
5
|
-
import { isSkipped } from
|
|
6
|
-
import type { AnyStep } from
|
|
7
|
-
import type { Ctx, RunInfo } from
|
|
8
|
-
import { objectPath } from
|
|
9
|
-
import { sha256File } from
|
|
10
|
-
import { EXIT } from
|
|
11
|
-
import { validateConfig, validateInput, validateOutput } from
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { isSkipped } from '../core/handlers.ts';
|
|
6
|
+
import type { AnyStep } from '../core/steps.ts';
|
|
7
|
+
import type { Ctx, RunInfo } from '../ctx/types.ts';
|
|
8
|
+
import { objectPath } from '../ctx/files.ts';
|
|
9
|
+
import { sha256File } from '../util/hash.ts';
|
|
10
|
+
import { EXIT } from './exit.ts';
|
|
11
|
+
import { validateConfig, validateInput, validateOutput } from './validate.ts';
|
|
12
12
|
|
|
13
|
-
export type FailureKind =
|
|
13
|
+
export type FailureKind = 'handler' | 'input' | 'output';
|
|
14
14
|
export type Envelope =
|
|
15
|
-
| { status:
|
|
16
|
-
| { status:
|
|
17
|
-
| { status:
|
|
15
|
+
| { status: 'succeeded'; output: unknown }
|
|
16
|
+
| { status: 'skipped'; reason: string }
|
|
17
|
+
| { status: 'failed'; error: { kind: FailureKind; message: string } };
|
|
18
18
|
|
|
19
19
|
export interface Execution {
|
|
20
20
|
envelope: Envelope;
|
|
@@ -26,7 +26,7 @@ export type StepFunction = (input: Record<string, unknown>, ctx: Ctx) => unknown
|
|
|
26
26
|
/** Signal → exit code, when the handler failed after a cancellation. */
|
|
27
27
|
export function cancelExitCode(signal: AbortSignal): number | undefined {
|
|
28
28
|
if (!signal.aborted) return undefined;
|
|
29
|
-
return signal.reason ===
|
|
29
|
+
return signal.reason === 'SIGINT' ? EXIT.sigint : EXIT.sigterm;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const errorMessage = (e: unknown): string => (e instanceof Error ? e.message : String(e));
|
|
@@ -36,17 +36,29 @@ function checkOwnFileRefs(value: unknown, run: RunInfo, workFiles: string): stri
|
|
|
36
36
|
const problems: string[] = [];
|
|
37
37
|
const walk = (v: unknown, at: string) => {
|
|
38
38
|
if (Array.isArray(v)) return v.forEach((x, i) => walk(x, `${at}[${i}]`));
|
|
39
|
-
if (typeof v !==
|
|
39
|
+
if (typeof v !== 'object' || v === null) return;
|
|
40
40
|
const o = v as Record<string, unknown>;
|
|
41
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
typeof o.path === 'string' &&
|
|
43
|
+
typeof o.sha256 === 'string' &&
|
|
44
|
+
o.run === run.number &&
|
|
45
|
+
o.step === run.step &&
|
|
46
|
+
o.attempt === run.attempt
|
|
47
|
+
) {
|
|
42
48
|
const file = join(workFiles, objectPath(o.path));
|
|
43
|
-
if (!existsSync(file))
|
|
44
|
-
|
|
49
|
+
if (!existsSync(file))
|
|
50
|
+
problems.push(
|
|
51
|
+
`${at}: file reference '${o.path}' points to this attempt but no such output file was produced`,
|
|
52
|
+
);
|
|
53
|
+
else if (sha256File(file) !== o.sha256)
|
|
54
|
+
problems.push(
|
|
55
|
+
`${at}: file reference '${o.path}' has the wrong sha256 (the file changed after it was referenced)`,
|
|
56
|
+
);
|
|
45
57
|
return;
|
|
46
58
|
}
|
|
47
59
|
for (const [k, x] of Object.entries(o)) walk(x, `${at}.${k}`);
|
|
48
60
|
};
|
|
49
|
-
walk(value,
|
|
61
|
+
walk(value, 'output');
|
|
50
62
|
return problems;
|
|
51
63
|
}
|
|
52
64
|
|
|
@@ -62,12 +74,18 @@ export async function executeStep(args: {
|
|
|
62
74
|
const input = validateInput(step, args.rawInput);
|
|
63
75
|
const config = validateConfig(step, args.rawInput);
|
|
64
76
|
if (!input.ok || !config.ok) {
|
|
65
|
-
const issues = [
|
|
66
|
-
|
|
77
|
+
const issues = [
|
|
78
|
+
...(input.ok ? [] : input.issues),
|
|
79
|
+
...(config.ok ? [] : config.issues),
|
|
80
|
+
];
|
|
81
|
+
const message = `step '${step.name}': input does not match the step's inputs:\n ${issues.join('\n ')}`;
|
|
67
82
|
log(message);
|
|
68
|
-
return {
|
|
83
|
+
return {
|
|
84
|
+
envelope: { status: 'failed', error: { kind: 'input', message } },
|
|
85
|
+
exitCode: EXIT.inputInvalid,
|
|
86
|
+
};
|
|
69
87
|
}
|
|
70
|
-
const ctx: Ctx = { ...args.ctx, config: Object.freeze(config.value) as Ctx[
|
|
88
|
+
const ctx: Ctx = { ...args.ctx, config: Object.freeze(config.value) as Ctx['config'] };
|
|
71
89
|
|
|
72
90
|
let value: unknown;
|
|
73
91
|
try {
|
|
@@ -79,19 +97,27 @@ export async function executeStep(args: {
|
|
|
79
97
|
: `step '${step.name}' failed: ${errorMessage(e)}`;
|
|
80
98
|
log(message);
|
|
81
99
|
if (e instanceof Error && e.stack && !cancelled) log(e.stack);
|
|
82
|
-
return {
|
|
100
|
+
return {
|
|
101
|
+
envelope: { status: 'failed', error: { kind: 'handler', message } },
|
|
102
|
+
exitCode: cancelled ?? EXIT.handlerFailed,
|
|
103
|
+
};
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
if (isSkipped(value)) {
|
|
86
107
|
log(`step '${step.name}' skipped: ${value.reason}`);
|
|
87
|
-
return { envelope: { status:
|
|
108
|
+
return { envelope: { status: 'skipped', reason: value.reason }, exitCode: EXIT.ok };
|
|
88
109
|
}
|
|
89
110
|
const out = validateOutput(step, value);
|
|
90
|
-
const problems = out.ok
|
|
111
|
+
const problems = out.ok
|
|
112
|
+
? checkOwnFileRefs(out.value, ctx.run, args.workFiles)
|
|
113
|
+
: out.issues;
|
|
91
114
|
if (!out.ok || problems.length) {
|
|
92
|
-
const message = `step '${step.name}': returned value does not match ${step.output?.name ??
|
|
115
|
+
const message = `step '${step.name}': returned value does not match ${step.output?.name ?? 'its (absent) output model'}:\n ${problems.join('\n ')}`;
|
|
93
116
|
log(message);
|
|
94
|
-
return {
|
|
117
|
+
return {
|
|
118
|
+
envelope: { status: 'failed', error: { kind: 'output', message } },
|
|
119
|
+
exitCode: EXIT.outputInvalid,
|
|
120
|
+
};
|
|
95
121
|
}
|
|
96
|
-
return { envelope: { status:
|
|
122
|
+
return { envelope: { status: 'succeeded', output: out.value }, exitCode: EXIT.ok };
|
|
97
123
|
}
|
package/src/harness/index.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
// @olivervea/pipelines/harness — the runtime the build tool compiles into the step binary.
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
export {
|
|
3
|
+
runHarness,
|
|
4
|
+
defaultIO,
|
|
5
|
+
allSteps,
|
|
6
|
+
resolveStepFunction,
|
|
7
|
+
type HarnessConfig,
|
|
8
|
+
type HandlerRegistry,
|
|
9
|
+
type HarnessIO,
|
|
10
|
+
} from './main.ts';
|
|
11
|
+
export { EXIT } from './exit.ts';
|
|
12
|
+
export { ENV, paths, runInfoFromEnv } from './env.ts';
|
|
13
|
+
export {
|
|
14
|
+
executeStep,
|
|
15
|
+
type Envelope,
|
|
16
|
+
type Execution,
|
|
17
|
+
type FailureKind,
|
|
18
|
+
} from './execute.ts';
|
|
19
|
+
export { RESULT_BEGIN, RESULT_END, MANIFEST_BEGIN, MANIFEST_END } from './result.ts';
|
|
20
|
+
export { describePipeline, DescribeError, manifestText } from '../describe/describe.ts';
|
|
21
|
+
export type { ManifestT as Manifest } from '../describe/manifest-schema.ts';
|
|
22
|
+
export type { HarnessInfo } from '../util/handler-hash.ts';
|