summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-07-20 13:03:39 -0700
committerElizabeth Hunt <me@liz.coffee>2025-07-20 13:03:39 -0700
commitdc4ac7742690f8f2bd759d57108ac4455e717fe9 (patch)
treef138ba41dd44bf703087eaa8ec43a22fe842923d
parentdccb99505e92685ba8ade7c3be84555f2b539a47 (diff)
downloadci-dc4ac7742690f8f2bd759d57108ac4455e717fe9.tar.gz
ci-dc4ac7742690f8f2bd759d57108ac4455e717fe9.zip
Mount src directory from path on host running worker container
-rwxr-xr-x.ci/ci.cjs23
-rw-r--r--.ci/package-lock.json492
-rw-r--r--.ci/package.json2
-rw-r--r--model/job/jobs.ts1
-rw-r--r--model/pipeline/builder.ts4
-rw-r--r--package-lock.json475
-rw-r--r--u/process/env.ts24
-rw-r--r--u/process/exec.ts (renamed from u/process/run.ts)25
-rw-r--r--u/process/index.ts2
-rw-r--r--u/trace/itrace.ts6
-rw-r--r--u/types/fn/callable.ts2
-rw-r--r--u/types/fn/either.ts56
-rw-r--r--u/types/fn/optional.ts8
-rw-r--r--u/types/index.ts2
-rw-r--r--u/types/misc.ts3
-rw-r--r--worker/executor.ts2
-rwxr-xr-xworker/jobs/ci_pipeline.run11
-rwxr-xr-xworker/scripts/checkout_ci.ts80
18 files changed, 660 insertions, 558 deletions
diff --git a/.ci/ci.cjs b/.ci/ci.cjs
index 0e7ef6d..6560028 100755
--- a/.ci/ci.cjs
+++ b/.ci/ci.cjs
@@ -302,7 +302,7 @@ var EmbeddedMetricsTraceable = class _EmbeddedMetricsTraceable extends Traceable
}
};
-// ../u/process/run.ts
+// ../u/process/exec.ts
var import_node_util = require("node:util");
var import_node_child_process = require("node:child_process");
var exec = (0, import_node_util.promisify)(import_node_child_process.exec);
@@ -369,6 +369,10 @@ var Either = class _Either extends _Tagged2 {
if (isRight(this.self)) return mapper(this.self.ok);
return _Either.left(this.self.err);
}
+ filter(mapper) {
+ if (isLeft(this.self)) return _Either.left(this.self.err);
+ return _Either.fromFailable(() => this.right().filter(mapper).get());
+ }
async flatMapAsync(mapper) {
if (isLeft(this.self)) return Promise.resolve(_Either.left(this.self.err));
return await mapper(this.self.ok).catch((err) => _Either.left(err));
@@ -385,6 +389,15 @@ var Either = class _Either extends _Tagged2 {
if (isRight(this.self)) return Optional.from(this.self.ok);
return Optional.none();
}
+ joinRight(other, mapper) {
+ return this.flatMap((t) => other.mapRight((o) => mapper(o, t)));
+ }
+ joinRightAsync(other, mapper) {
+ return this.flatMapAsync(async (t) => {
+ const o = typeof other === "function" ? other() : other;
+ return o.then((other2) => other2.mapRight((o2) => mapper(o2, t)));
+ });
+ }
static left(e) {
return new _Either({ err: e, _tag: ELeftTag });
}
@@ -429,7 +442,7 @@ var Optional = class _Optional extends _Tagged3 {
return this;
}
get() {
- if (isNone(this.self)) throw new IOptionalEmptyError("empty value");
+ if (isNone(this.self)) throw new IOptionalEmptyError("called get() on None optional");
return this.self.value;
}
filter(mapper) {
@@ -478,10 +491,10 @@ var BasePipelineBuilder = class {
}
};
var DefaultGitHookPipelineBuilder = class extends BasePipelineBuilder {
- constructor(remoteUrl = process.env.remote, rev = process.env.rev, ref = process.env.ref) {
+ constructor(remoteUrl = process.env.remote, rev = process.env.rev, refname = process.env.refname) {
super();
this.remoteUrl = remoteUrl;
- this.ref = ref;
+ this.refname = refname;
this.addStage({
parallelJobs: [
{
@@ -500,7 +513,7 @@ var DefaultGitHookPipelineBuilder = class extends BasePipelineBuilder {
}
getBranch() {
const branchRefPrefix = "refs/heads/";
- return this.ref.split(branchRefPrefix).at(1);
+ return this.refname.split(branchRefPrefix).at(1);
}
};
diff --git a/.ci/package-lock.json b/.ci/package-lock.json
new file mode 100644
index 0000000..b45979e
--- /dev/null
+++ b/.ci/package-lock.json
@@ -0,0 +1,492 @@
+{
+ "name": ".ci",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "@emprespresso/ci_model": "file:../model"
+ },
+ "devDependencies": {
+ "esbuild": "0.25.5"
+ }
+ },
+ "../model": {
+ "name": "@emprespresso/ci_model",
+ "version": "0.1.0",
+ "dependencies": {
+ "@emprespresso/pengueno": "*"
+ }
+ },
+ "node_modules/@emprespresso/ci_model": {
+ "resolved": "../model",
+ "link": true
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
+ "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
+ "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
+ "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
+ "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
+ "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
+ "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
+ "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
+ "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
+ "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
+ "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
+ "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
+ "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
+ "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
+ "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
+ "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
+ "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
+ "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
+ "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
+ "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
+ "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
+ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.5",
+ "@esbuild/android-arm": "0.25.5",
+ "@esbuild/android-arm64": "0.25.5",
+ "@esbuild/android-x64": "0.25.5",
+ "@esbuild/darwin-arm64": "0.25.5",
+ "@esbuild/darwin-x64": "0.25.5",
+ "@esbuild/freebsd-arm64": "0.25.5",
+ "@esbuild/freebsd-x64": "0.25.5",
+ "@esbuild/linux-arm": "0.25.5",
+ "@esbuild/linux-arm64": "0.25.5",
+ "@esbuild/linux-ia32": "0.25.5",
+ "@esbuild/linux-loong64": "0.25.5",
+ "@esbuild/linux-mips64el": "0.25.5",
+ "@esbuild/linux-ppc64": "0.25.5",
+ "@esbuild/linux-riscv64": "0.25.5",
+ "@esbuild/linux-s390x": "0.25.5",
+ "@esbuild/linux-x64": "0.25.5",
+ "@esbuild/netbsd-arm64": "0.25.5",
+ "@esbuild/netbsd-x64": "0.25.5",
+ "@esbuild/openbsd-arm64": "0.25.5",
+ "@esbuild/openbsd-x64": "0.25.5",
+ "@esbuild/sunos-x64": "0.25.5",
+ "@esbuild/win32-arm64": "0.25.5",
+ "@esbuild/win32-ia32": "0.25.5",
+ "@esbuild/win32-x64": "0.25.5"
+ }
+ }
+ }
+}
diff --git a/.ci/package.json b/.ci/package.json
index 9d8bfa7..dc42e26 100644
--- a/.ci/package.json
+++ b/.ci/package.json
@@ -4,7 +4,7 @@
"clean": "rm -rf dist ci.cjs"
},
"dependencies": {
- "@emprespresso/ci_model": "*"
+ "@emprespresso/ci_model": "file:../model"
},
"devDependencies": {
"esbuild": "0.25.5"
diff --git a/model/job/jobs.ts b/model/job/jobs.ts
index dc23070..eb22afd 100644
--- a/model/job/jobs.ts
+++ b/model/job/jobs.ts
@@ -43,6 +43,7 @@ export interface CheckoutCiJobProps extends JobArgT {
readonly rev: string;
readonly run: string;
+ readonly executorLaminarPath: string;
readonly returnPath: string;
}
diff --git a/model/pipeline/builder.ts b/model/pipeline/builder.ts
index 926a97f..b15a044 100644
--- a/model/pipeline/builder.ts
+++ b/model/pipeline/builder.ts
@@ -23,7 +23,7 @@ export class DefaultGitHookPipelineBuilder extends BasePipelineBuilder {
constructor(
private readonly remoteUrl = process.env.remote!,
rev = process.env.rev!,
- private readonly ref = process.env.ref!,
+ private readonly refname = process.env.refname!,
) {
super();
@@ -47,6 +47,6 @@ export class DefaultGitHookPipelineBuilder extends BasePipelineBuilder {
public getBranch(): string | undefined {
const branchRefPrefix = 'refs/heads/';
- return this.ref.split(branchRefPrefix).at(1);
+ return this.refname.split(branchRefPrefix).at(1);
}
}
diff --git a/package-lock.json b/package-lock.json
index 5f6f6ae..a04d81d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,8 +11,7 @@
"u",
"model",
"server",
- "worker",
- ".ci"
+ "worker"
],
"devDependencies": {
"@types/node": "^24.0.3",
@@ -30,7 +29,7 @@
}
},
".ci": {
- "name": "ci.ci",
+ "extraneous": true,
"dependencies": {
"@emprespresso/ci_model": "*"
},
@@ -61,431 +60,6 @@
"resolved": "u",
"link": true
},
- "node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
- "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
- "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
- "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
- "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
- "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
- "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
- "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
- "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
- "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
- "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
- "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
- "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
- "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
- "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
- "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
- "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
- "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
- "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
- "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
- "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
- "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
- "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
- "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
@@ -1089,10 +663,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/ci.ci": {
- "resolved": ".ci",
- "link": true
- },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -1243,47 +813,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/esbuild": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
- "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.5",
- "@esbuild/android-arm": "0.25.5",
- "@esbuild/android-arm64": "0.25.5",
- "@esbuild/android-x64": "0.25.5",
- "@esbuild/darwin-arm64": "0.25.5",
- "@esbuild/darwin-x64": "0.25.5",
- "@esbuild/freebsd-arm64": "0.25.5",
- "@esbuild/freebsd-x64": "0.25.5",
- "@esbuild/linux-arm": "0.25.5",
- "@esbuild/linux-arm64": "0.25.5",
- "@esbuild/linux-ia32": "0.25.5",
- "@esbuild/linux-loong64": "0.25.5",
- "@esbuild/linux-mips64el": "0.25.5",
- "@esbuild/linux-ppc64": "0.25.5",
- "@esbuild/linux-riscv64": "0.25.5",
- "@esbuild/linux-s390x": "0.25.5",
- "@esbuild/linux-x64": "0.25.5",
- "@esbuild/netbsd-arm64": "0.25.5",
- "@esbuild/netbsd-x64": "0.25.5",
- "@esbuild/openbsd-arm64": "0.25.5",
- "@esbuild/openbsd-x64": "0.25.5",
- "@esbuild/sunos-x64": "0.25.5",
- "@esbuild/win32-arm64": "0.25.5",
- "@esbuild/win32-ia32": "0.25.5",
- "@esbuild/win32-x64": "0.25.5"
- }
- },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
diff --git a/u/process/env.ts b/u/process/env.ts
index 88fb490..f59fadf 100644
--- a/u/process/env.ts
+++ b/u/process/env.ts
@@ -1,27 +1,25 @@
-import { IOptional, Either, Optional, type IEither } from '@emprespresso/pengueno';
+import { IOptional, Either, Optional, type IEither, type ObjectFromList } from '@emprespresso/pengueno';
-export const getEnv = <V extends string>(name: string): IOptional<V> => Optional.from(<V>process.env[name]);
+// type safe environment variables
-export const getRequiredEnv = <V extends string>(name: string): IEither<Error, V> =>
- Either.fromFailable(() => getEnv<V>(name).get()).mapLeft(
+export const getEnv = (name: string): IOptional<string> => Optional.from(process.env[name]);
+
+export const getRequiredEnv = <V extends string>(name: V): IEither<Error, string> =>
+ Either.fromFailable(() => getEnv(name).get()).mapLeft(
() => new Error(`environment variable "${name}" is required D:`),
);
-type ObjectFromList<T extends ReadonlyArray<string>, V = string> = {
- [K in T extends ReadonlyArray<infer U> ? U : never]: V;
-};
-
-export const getRequiredEnvVars = <V extends string>(vars: Array<V>) => {
+export const getRequiredEnvVars = <V extends string>(vars: Array<V>): IEither<Error, ObjectFromList<typeof vars>> => {
type Environment = ObjectFromList<typeof vars>;
const emptyEnvironment = Either.right<Error, Environment>(<Environment>{});
- const addTo = (env: Environment, key: V) => (val: string) =>
+ const addTo = (env: Environment, key: V, val: string) =>
<Environment>{
...env,
[key]: val,
};
- return Either.joinRight<V, Error, Environment>(
- vars,
- (envVar: V, environment: Environment) => getRequiredEnv(envVar).mapRight(addTo(environment, envVar)),
+ return vars.reduce(
+ (environment, key) =>
+ environment.joinRight(getRequiredEnv(key), (value, environment) => addTo(environment, key, value)),
emptyEnvironment,
);
};
diff --git a/u/process/run.ts b/u/process/exec.ts
index 1d19129..a2cdbca 100644
--- a/u/process/run.ts
+++ b/u/process/exec.ts
@@ -15,11 +15,13 @@ export type Command = string[] | string;
export type StdStreams = { stdout: string; stderr: string };
export const CmdMetric = Metric.fromName('Exec').asResult();
+type Environment = Record<string, string>;
+type Options = { env?: Environment; clearEnv?: boolean };
export const getStdout = (
- c: ITraceable<Command, LogMetricTraceSupplier>,
- options: { env?: Record<string, string>; clearEnv?: boolean } = {},
+ cmd: ITraceable<Command, LogMetricTraceSupplier>,
+ options: Options = {},
): Promise<IEither<Error, string>> =>
- c
+ cmd
.flatMap(TraceUtil.withFunctionTrace(getStdout))
.flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`))
.map((tCmd) => {
@@ -38,3 +40,20 @@ export const getStdout = (
)
.peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(CmdMetric)))
.get();
+
+export const getStdoutMany = (
+ cmds: ITraceable<Array<Command>, LogMetricTraceSupplier>,
+ options: Options = {},
+): Promise<IEither<Error, Array<string>>> =>
+ cmds
+ .coExtend((t) => t.get())
+ .reduce(
+ async (_result, tCmd) => {
+ const result = await _result;
+ return result.joinRightAsync(
+ () => tCmd.map((cmd) => getStdout(cmd, options)).get(),
+ (stdout, pre) => pre.concat(stdout),
+ );
+ },
+ Promise.resolve(Either.right<Error, Array<string>>([])),
+ );
diff --git a/u/process/index.ts b/u/process/index.ts
index 6945a0f..2d74a5f 100644
--- a/u/process/index.ts
+++ b/u/process/index.ts
@@ -1,5 +1,5 @@
+export * from './exec.js';
export * from './env.js';
-export * from './run.js';
export * from './validate_identifier.js';
export * from './argv.js';
export * from './signals.js';
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts
index 9c33ad2..57c4419 100644
--- a/u/trace/itrace.ts
+++ b/u/trace/itrace.ts
@@ -28,8 +28,8 @@ export interface ITraceable<T, Trace = BaseTraceWith> {
readonly map: <_T>(mapper: ITraceableMapper<T, _T, Trace>) => ITraceable<_T, Trace>;
readonly bimap: <_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) => ITraceable<_T, Trace>;
readonly coExtend: <_T>(
- mapper: ITraceableMapper<T, ReadonlyArray<_T>, Trace>,
- ) => ReadonlyArray<ITraceable<_T, Trace>>;
+ mapper: ITraceableMapper<T, Array<_T>, Trace>,
+ ) => Array<ITraceable<_T, Trace>>;
readonly peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>;
readonly traceScope: (mapper: ITraceableMapper<T, Trace, Trace>) => ITraceable<T, Trace>;
@@ -51,7 +51,7 @@ export class TraceableImpl<T, Trace> implements ITraceable<T, Trace> {
return new TraceableImpl(result, this.trace);
}
- public coExtend<_T>(mapper: ITraceableMapper<T, ReadonlyArray<_T>, Trace>): ReadonlyArray<ITraceable<_T, Trace>> {
+ public coExtend<_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>): Array<ITraceable<_T, Trace>> {
const results = mapper(this);
return Array.from(results).map((result) => this.move(result));
}
diff --git a/u/types/fn/callable.ts b/u/types/fn/callable.ts
index 51756d7..60d747b 100644
--- a/u/types/fn/callable.ts
+++ b/u/types/fn/callable.ts
@@ -10,6 +10,8 @@ export interface Mapper<T, U> extends Callable<U, T> {
(t: T): U;
}
+export interface Predicate<T> extends Mapper<T, boolean> {}
+
export interface BiMapper<T, U, R> extends Callable {
(t: T, u: U): R;
}
diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts
index aa67d41..80f32b4 100644
--- a/u/types/fn/either.ts
+++ b/u/types/fn/either.ts
@@ -1,18 +1,36 @@
-import { BiMapper, IOptional, type Mapper, Optional, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
+import {
+ BiMapper,
+ IOptional,
+ type Mapper,
+ Optional,
+ Predicate,
+ type Supplier,
+ Tagged,
+ isTagged,
+} from '@emprespresso/pengueno';
export const IEitherTag = 'IEither' as const;
export type IEitherTag = typeof IEitherTag;
export const isEither = <E, T>(o: unknown): o is IEither<E, T> => isTagged(o, IEitherTag);
export interface IEither<E, T> extends Tagged<IEitherTag> {
- readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>;
- readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
readonly left: Supplier<IOptional<E>>;
readonly right: Supplier<IOptional<T>>;
- readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
+
readonly mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>;
+ readonly filter: (mapper: Predicate<T>) => IEither<E, T>;
readonly mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>;
+ readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>;
+
readonly flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>;
readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>;
+
+ readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
+ readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
+ readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) => IEither<E, _T>;
+ readonly joinRightAsync: <O, _T>(
+ other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
+ mapper: BiMapper<O, T, _T>,
+ ) => Promise<IEither<E, _T>>;
}
const ELeftTag = 'E.Left' as const;
@@ -62,6 +80,11 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
return Either.left<E, _T>(this.self.err);
}
+ public filter(mapper: Predicate<T>): IEither<E, T> {
+ if (isLeft(this.self)) return Either.left<E, T>(this.self.err);
+ return Either.fromFailable<E, T>(() => this.right().filter(mapper).get());
+ }
+
public async flatMapAsync<_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>): Promise<IEither<E, _T>> {
if (isLeft(this.self)) return Promise.resolve(Either.left(this.self.err));
return await mapper(this.self.ok).catch((err) => Either.left(err));
@@ -82,23 +105,18 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
return Optional.none();
}
- static joinRight<K, E, T>(
- arr: Array<K>,
- mapper: BiMapper<K, T, IEither<E, T>>,
- init: IEither<E, T>,
- ): IEither<E, T> {
- return arr.reduce((acc: IEither<E, T>, x: K) => acc.flatMap((t) => mapper(x, t)), init);
+ public joinRight<O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) {
+ return this.flatMap((t) => other.mapRight((o) => mapper(o, t)));
}
- static joinRightAsync<K, E, T>(
- arr: Array<K>,
- mapper: BiMapper<K, T, Promise<IEither<E, T>>>,
- init: IEither<E, T>,
- ): Promise<IEither<E, T>> {
- return arr.reduce(
- (acc: Promise<IEither<E, T>>, x: K) => acc.then((res) => res.flatMapAsync((t) => mapper(x, t))),
- Promise.resolve(init),
- );
+ public joinRightAsync<O, _T>(
+ other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
+ mapper: BiMapper<O, T, _T>,
+ ) {
+ return this.flatMapAsync(async (t) => {
+ const o = typeof other === 'function' ? other() : other;
+ return o.then((other) => other.mapRight((o) => mapper(o, t)));
+ });
}
static left<E, T>(e: E): IEither<E, T> {
diff --git a/u/types/fn/optional.ts b/u/types/fn/optional.ts
index 3396a45..504e496 100644
--- a/u/types/fn/optional.ts
+++ b/u/types/fn/optional.ts
@@ -1,4 +1,4 @@
-import { type Mapper, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
+import { type Mapper, Predicate, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
export type MaybeGiven<T> = T | undefined | null;
@@ -9,7 +9,7 @@ export class IOptionalEmptyError extends Error {}
export interface IOptional<t, T extends NonNullable<t> = NonNullable<t>> extends Tagged<IOptionalTag>, Iterable<T> {
readonly move: <_T>(t: MaybeGiven<_T>) => IOptional<_T>;
readonly map: <_T>(mapper: Mapper<T, MaybeGiven<_T>>) => IOptional<_T>;
- readonly filter: (mapper: Mapper<T, boolean>) => IOptional<T>;
+ readonly filter: (mapper: Predicate<T>) => IOptional<T>;
readonly flatMap: <_T>(mapper: Mapper<T, MaybeGiven<IOptional<_T>>>) => IOptional<_T>;
readonly orSome: (supplier: Supplier<MaybeGiven<t>>) => IOptional<T>;
readonly get: Supplier<T>;
@@ -48,11 +48,11 @@ export class Optional<t, T extends NonNullable<t> = NonNullable<t>> extends _Tag
}
public get(): T {
- if (isNone(this.self)) throw new IOptionalEmptyError('empty value');
+ if (isNone(this.self)) throw new IOptionalEmptyError('called get() on None optional');
return this.self.value;
}
- public filter(mapper: Mapper<T, boolean>): IOptional<T> {
+ public filter(mapper: Predicate<T>): IOptional<T> {
if (isNone(this.self) || !mapper(this.self.value)) return Optional.none();
return Optional.some(this.self.value);
}
diff --git a/u/types/index.ts b/u/types/index.ts
index c68cedc..fc1b15a 100644
--- a/u/types/index.ts
+++ b/u/types/index.ts
@@ -1,3 +1,5 @@
+export * from './misc.js';
+
export * from './object.js';
export * from './tagged.js';
diff --git a/u/types/misc.ts b/u/types/misc.ts
new file mode 100644
index 0000000..77833c4
--- /dev/null
+++ b/u/types/misc.ts
@@ -0,0 +1,3 @@
+export type ObjectFromList<T extends ReadonlyArray<string | number | symbol>, V = string> = {
+ [K in T extends ReadonlyArray<infer U> ? U : never]: V;
+};
diff --git a/worker/executor.ts b/worker/executor.ts
index 47b337c..11c24f6 100644
--- a/worker/executor.ts
+++ b/worker/executor.ts
@@ -28,7 +28,7 @@ export const executeJob = (tJob: ITraceable<Job, LogMetricTraceSupplier>) => {
.flatMapAsync((args) => getStdout(tJob.move(tJob.get().type), { env: args })),
)
.flatMapAsync(TraceUtil.promiseify(TraceUtil.traceResultingEither(metric)))
- .peek(TraceUtil.promiseify(t => t.traceScope(() => LogLevel.DEBUG).trace.trace(JSON.stringify(t.get()))))
+ .peek(TraceUtil.promiseify((t) => t.traceScope(() => LogLevel.DEBUG).trace.trace(JSON.stringify(t.get()))))
.get();
};
// -- </job.exectuor> --
diff --git a/worker/jobs/ci_pipeline.run b/worker/jobs/ci_pipeline.run
index 87bcc84..6bee929 100755
--- a/worker/jobs/ci_pipeline.run
+++ b/worker/jobs/ci_pipeline.run
@@ -1,5 +1,16 @@
#!/bin/sh
+# add scripts executed by the pipeline
export PATH=$PATH:$PIPELINE_PATH
+containerid=$(cat /etc/hostname)
+isindocker=$(docker ps -q -f "id=$containerid")
+if [ -n "$isindocker" ]; then
+ executorLaminarPath=$(docker inspect "$containerid" | jq -r '.[0].Mounts[] | select(.Destination == "/var/lib/laminar") | .Source')
+else
+ executorLaminarPath=$(pwd)
+fi
+
+export executorLaminarPath
+
checkout_ci.js
diff --git a/worker/scripts/checkout_ci.ts b/worker/scripts/checkout_ci.ts
index d71df6e..cba6a2f 100755
--- a/worker/scripts/checkout_ci.ts
+++ b/worker/scripts/checkout_ci.ts
@@ -5,23 +5,22 @@ import {
Either,
LogTraceable,
getRequiredEnvVars,
- getStdout,
isObject,
LogMetricTraceable,
Metric,
prependWith,
TraceUtil,
- IEither,
+ getStdoutMany,
} from '@emprespresso/pengueno';
import { mkdir, readFile, rm } from 'fs/promises';
-import { basename, join } from 'path';
+import { join } from 'path';
import { type CheckoutCiJob, type FetchCodeJob, PipelineImpl } from '@emprespresso/ci_model';
import { executeJob, executePipeline } from '@emprespresso/ci_worker';
-export interface CiWorkflow {
+interface CiWorkflow {
workflow: string;
}
-export function isCiWorkflow(t: unknown): t is CiWorkflow {
+function isCiWorkflow(t: unknown): t is CiWorkflow {
return isObject(t) && 'workflow' in t && typeof t.workflow === 'string' && !t.workflow.includes('..');
}
@@ -30,8 +29,19 @@ const OCI_REGISTRY = 'oci.liz.coffee';
const PIPELINE_IMAGE = OCI_REGISTRY + '/emprespresso/ci_worker:release';
const READONLY_CREDENTIALS = { username: 'readonly', password: 'readonly' };
-const run = Date.now().toString();
-const eitherJob = getRequiredEnvVars(['remote', 'refname', 'rev']).mapRight(
+// use a different directory per job run
+// even though the Laminar run is unique per job, there's potential for "children" we spawn
+// to be a checkout_ci job as well. in which case, we don't want any conflicts with whatever
+// the "parent" was doing, so we create a unique directory for each.
+// i.e.
+// Laminar Run: 57, CWD=/var/lib/laminar/run/57
+// ci_pipeline (1000.uuidA)
+// -> checkout_ci
+// -> [...children]
+// -> checkout_ci (1000.uuidB)
+const run = `${Date.now()}.${crypto.randomUUID().replaceAll('-', '')}`;
+
+const eitherJob = getRequiredEnvVars(['remote', 'refname', 'rev', 'executorLaminarPath']).mapRight(
(baseArgs) =>
<CheckoutCiJob>{
type: 'checkout_ci.js',
@@ -46,9 +56,9 @@ const afterJob = eitherJob.flatMapAsync((job) =>
Either.fromFailableAsync(() => rm(getWorkingDirectoryForCiJob(job), { recursive: true })),
);
+const logTraceableJob = LogTraceable.of(eitherJob).flatMap(TraceUtil.withTrace(`checkout_ci.run.${run}`));
const ciRunMetric = Metric.fromName('checkout_ci.run');
-const _logJob = LogTraceable.of(eitherJob).flatMap(TraceUtil.withTrace(`checkout_ci.${run}`));
-await LogMetricTraceable.ofLogTraceable(_logJob)
+await LogMetricTraceable.ofLogTraceable(logTraceableJob)
.flatMap(TraceUtil.withMetricTrace(ciRunMetric))
.map((tEitherJob) =>
tEitherJob.get().flatMapAsync((ciJob) => {
@@ -84,32 +94,25 @@ await LogMetricTraceable.ofLogTraceable(_logJob)
),
);
return repoCiFileContents
- .flatMap((fileText) => Either.fromFailable<Error, unknown>(() => JSON.parse(fileText)))
- .flatMap((json) =>
- eitherCiJob.flatMap((ciJob): IEither<Error, { commands: Array<Command>; job: CheckoutCiJob }> => {
- if (!isCiWorkflow(json)) {
- const e = new Error("couldn't find any valid ci configuration (。•́︿•̀。), that's okay~");
- return Either.left(e);
- }
- return Either.right({
- commands: getPipelineGenerationCommand(ciJob, json.workflow),
- job: ciJob,
- });
- }),
- );
+ .flatMap((fileText) =>
+ Either.fromFailable<Error, CiWorkflow>(() => JSON.parse(fileText)).filter((json) => isCiWorkflow(json)),
+ )
+ .joinRight(eitherCiJob, (job: CheckoutCiJob, { workflow }) => ({
+ job,
+ commands: getPipelineGenerationCommand(job, workflow),
+ }));
})
.map(async (tEitherPipelineGenerationCommand) => {
const eitherJobCommand = await tEitherPipelineGenerationCommand.get();
- const pipelineSerialized = await eitherJobCommand.flatMapAsync(({ commands }) => {
- return Either.joinRightAsync(
- commands,
- (command) => tEitherPipelineGenerationCommand.move(command).map(getStdout).get(),
- Either.right<Error, string>(''),
- );
- });
+ const pipelineSerialized = await eitherJobCommand.flatMapAsync(({ commands }) =>
+ getStdoutMany(tEitherPipelineGenerationCommand.move(commands)),
+ );
return pipelineSerialized
- .flatMap((s) => PipelineImpl.from(s))
- .flatMap((pipeline) => eitherJobCommand.mapRight(({ job }) => ({ job, pipeline })));
+ .flatMap((results) => {
+ const pipeline = results.at(-1)!;
+ return PipelineImpl.from(pipeline);
+ })
+ .joinRight(eitherJobCommand, (job, pipeline) => ({ job, pipeline }));
})
.peek(
TraceUtil.promiseify((tEitherPipeline) =>
@@ -147,7 +150,18 @@ function getWorkingDirectoryForCiJob(job: CheckoutCiJob) {
}
function getSrcDirectoryForCiJob(job: CheckoutCiJob) {
- return `${job.arguments.returnPath}/${job.arguments.run}/src`;
+ return `${getWorkingDirectoryForCiJob(job)}/src`;
+}
+
+function getSrcDirectoryForChildContainer(job: CheckoutCiJob) {
+ // the container which runs the pipeline synthesizer (A) might be spawned by another container
+ // (B) ((which should be the one running this job)) by talking to the host's docker daemon
+ // (mounting /var/run/docker.sock) and executing the {@link getPipelineGenerationCommand}.
+ //
+ // so mounting {@link getSrcDirectoryForCiJob} has no meaning as it doesn't exist on the host;
+ // here we replace the path in (B) with the actual volume source on the host, where the src
+ // exists.
+ return getSrcDirectoryForCiJob(job).replace('/var/lib/laminar', job.arguments.executorLaminarPath);
}
function getPipelineGenerationCommand(
@@ -170,7 +184,7 @@ function getPipelineGenerationCommand(
'-e',
),
'-v',
- `${getSrcDirectoryForCiJob(job)}:/src`,
+ `${getSrcDirectoryForChildContainer(job)}:/src`,
image,
`/src/${pipelineGeneratorPath}`,
],