summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-07-20 16:03:44 -0700
committerElizabeth Hunt <me@liz.coffee>2025-07-20 16:17:48 -0700
commit9e220eca4545982df83ffcaa66a9b050a3d6f24e (patch)
treea735fed0f50dec0083dac9284f45db73af1afea8
parent2e10e9172f8528868b70886335dbbe20f932f702 (diff)
downloadci-9e220eca4545982df83ffcaa66a9b050a3d6f24e.tar.gz
ci-9e220eca4545982df83ffcaa66a9b050a3d6f24e.zip
Fixes silent failures
-rw-r--r--.ci/ci.ts2
-rw-r--r--u/types/fn/either.ts2
-rw-r--r--worker/executor.ts6
-rwxr-xr-xworker/scripts/ansible_playbook.ts7
-rwxr-xr-xworker/scripts/build_docker_image.ts73
-rwxr-xr-xworker/scripts/checkout_ci.ts10
6 files changed, 70 insertions, 30 deletions
diff --git a/.ci/ci.ts b/.ci/ci.ts
index 39844d5..e2e375b 100644
--- a/.ci/ci.ts
+++ b/.ci/ci.ts
@@ -18,6 +18,7 @@ const getPipeline = () => {
if (!branch) return gitHookPipeline.build();
const commonBuildArgs = {
+ context: gitHookPipeline.getSourceDestination(),
registry: REGISTRY,
namespace: NAMESPACE,
imageTag: branch,
@@ -27,7 +28,6 @@ const getPipeline = () => {
type: 'build_docker_image.js',
arguments: {
...commonBuildArgs,
- context: gitHookPipeline.getSourceDestination(),
repository: IMG + '_base',
buildTarget: IMG + '_base',
dockerfile: 'Dockerfile',
diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts
index 80f32b4..5e2dca0 100644
--- a/u/types/fn/either.ts
+++ b/u/types/fn/either.ts
@@ -26,7 +26,7 @@ export interface IEither<E, T> extends Tagged<IEitherTag> {
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 joinRight: <O, _T>(other: IEither<E, O>, mapper: (a: O, b: T) => _T) => IEither<E, _T>;
readonly joinRightAsync: <O, _T>(
other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
mapper: BiMapper<O, T, _T>,
diff --git a/worker/executor.ts b/worker/executor.ts
index f9fbf29..fe3a688 100644
--- a/worker/executor.ts
+++ b/worker/executor.ts
@@ -22,7 +22,7 @@ export const executeJob = (tJob: ITraceable<Job, LogMetricTraceSupplier>) => {
.map((tJob) =>
validateExecutionEntries(tJob.get().arguments)
.mapLeft((badEntries) => {
- tJob.trace.traceScope(LogLevel.ERROR).trace(badEntries.toString());
+ tJob.trace.traceScope(LogLevel.ERROR).trace(JSON.stringify(badEntries));
return new Error('invalid job arguments');
})
.flatMapAsync((args) => getStdout(tJob.move(tJob.get().type), { env: args })),
@@ -44,9 +44,9 @@ export const executePipeline = (
.flatMap(TraceUtil.withMetricTrace(pipelinesMetric))
.map(async (_tPipeline): Promise<IEither<Error, void>> => {
for (const [i, serialStage] of tPipeline.get().serialJobs.entries()) {
- const tPipeline = _tPipeline.flatMap(TraceUtil.withTrace(`Stage = ${i}`));
+ const tPipeline = _tPipeline.traceScope(() => `Stage = ${i}`);
const parallelJobs = tPipeline
- .peek((t) => t.trace.trace(`do your best little stage :> ${serialStage}`))
+ .peek((t) => t.trace.trace(`do your best little stage :> ${JSON.stringify(serialStage)}`))
.move(serialStage.parallelJobs)
.coExtend((jobs) =>
jobs.get().map((job) => <Job>{ ...job, arguments: { ...baseEnv, ...job.arguments } }),
diff --git a/worker/scripts/ansible_playbook.ts b/worker/scripts/ansible_playbook.ts
index 4ec3ffa..6eb4d47 100755
--- a/worker/scripts/ansible_playbook.ts
+++ b/worker/scripts/ansible_playbook.ts
@@ -88,6 +88,13 @@ await LogMetricTraceable.ofLogTraceable(_logJob)
return tEitherJobAndSecrets.move(deployCmd).map(getStdout).get();
});
})
+ .map(async (tEitherJob) => {
+ const eitherJob = await tEitherJob.get();
+ return eitherJob.fold(
+ (e) => Promise.reject(e),
+ () => Promise.resolve(0),
+ );
+ })
.get();
function saveToTempFile(text: string): Promise<IEither<Error, string>> {
diff --git a/worker/scripts/build_docker_image.ts b/worker/scripts/build_docker_image.ts
index 1783e7c..f29bd61 100755
--- a/worker/scripts/build_docker_image.ts
+++ b/worker/scripts/build_docker_image.ts
@@ -11,8 +11,9 @@ import {
} from '@emprespresso/pengueno';
import type { BuildDockerImageJob, BuildDockerImageJobProps } from '@emprespresso/ci_model';
import { Bitwarden, type LoginItem } from '@emprespresso/ci_worker';
+import path from 'path';
-const eitherJob = getRequiredEnvVars([
+const job = getRequiredEnvVars([
'registry',
'namespace',
'repository',
@@ -20,36 +21,39 @@ const eitherJob = getRequiredEnvVars([
'context',
'dockerfile',
'buildTarget',
-]).mapRight(
- (baseArgs) =>
- <BuildDockerImageJob>{
- type: 'build_docker_image.js',
- arguments: baseArgs,
+])
+ .mapRight(
+ (baseArgs) =>
+ <BuildDockerImageJob>{
+ type: 'build_docker_image.js',
+ arguments: baseArgs,
+ },
+ )
+ .fold(
+ (err) => {
+ throw err;
},
-);
+ (x) => x,
+ );
const eitherVault = Bitwarden.getConfigFromEnvironment().mapRight((config) => new Bitwarden(config));
const buildImageMetric = Metric.fromName('dockerImage.build').asResult();
const loginMetric = Metric.fromName('dockerRegistry.login').asResult();
-const _logJob = LogTraceable.of(eitherJob).flatMap((tEitherJob) => {
- const trace = tEitherJob.get().fold(
- () => 'NO_BUILD_TARGET',
- ({ arguments: { buildTarget } }) => buildTarget,
- );
- return tEitherJob.traceScope(() => `build_docker_image.${trace}`);
+const _logJob = LogTraceable.of(job).flatMap((tJob) => {
+ const trace = tJob.get().arguments.buildTarget;
+ return tJob.traceScope(() => `build_docker_image.${trace}`);
});
await LogMetricTraceable.ofLogTraceable(_logJob)
.flatMap(TraceUtil.withMetricTrace(buildImageMetric))
.flatMap(TraceUtil.withMetricTrace(loginMetric))
- .peek((tEitherJob) => tEitherJob.trace.trace('starting docker image build job! (⑅˘꒳˘)'))
- .map((tEitherJob) =>
- tEitherJob.get().flatMapAsync((job) =>
- eitherVault.flatMapAsync(async (vault) => {
- const eitherKey = await vault.unlock(tEitherJob);
- return eitherKey.mapRight((key) => ({ job, key, vault }));
- }),
- ),
+ .peek((tJob) => tJob.trace.trace('starting docker image build job! (⑅˘꒳˘)'))
+ .map((tJob) =>
+ eitherVault.flatMapAsync(async (vault) => {
+ const job = tJob.get();
+ const eitherKey = await vault.unlock(tJob);
+ return eitherKey.mapRight((key) => ({ job, key, vault }));
+ }),
)
.map(async (tEitherJobVault) => {
tEitherJobVault.trace.trace('logging into the wegistwy uwu~');
@@ -85,9 +89,10 @@ await LogMetricTraceable.ofLogTraceable(_logJob)
)
.get(),
);
- return eitherBuiltImage.flatMap((buildOutput) =>
- eitherWithAuthdRegistryBuildJob.mapRight((job) => ({ buildOutput, job })),
- );
+ return eitherBuiltImage.joinRight(eitherWithAuthdRegistryBuildJob, (job, buildOutput) => ({
+ job,
+ buildOutput,
+ }));
})
.flatMapAsync(TraceUtil.promiseify(TraceUtil.traceResultingEither(buildImageMetric)))
.peek(
@@ -104,6 +109,13 @@ await LogMetricTraceable.ofLogTraceable(_logJob)
.mapRight(({ job }) => tEitherWithBuiltImage.move(getPushCommand(job.arguments.imageTag)))
.flatMapAsync((tPushCommand) => getStdout(tPushCommand));
})
+ .map(async (tEitherJob) => {
+ const eitherJob = await tEitherJob.get();
+ return eitherJob.fold(
+ (e) => Promise.reject(e),
+ () => Promise.resolve(0),
+ );
+ })
.get();
function getDockerLoginCommand(username: string, registry: string): Command {
@@ -111,7 +123,18 @@ function getDockerLoginCommand(username: string, registry: string): Command {
}
function getBuildCommand({ buildTarget, imageTag, dockerfile, context }: BuildDockerImageJobProps): Command {
- return ['docker', 'build', '--target', buildTarget, '-t', imageTag, '-f', dockerfile, context];
+ return [
+ 'cat',
+ path.join(context, dockerfile),
+ '|',
+ 'docker',
+ 'build',
+ '--target',
+ buildTarget,
+ '-t',
+ imageTag,
+ '-',
+ ];
}
function getPushCommand(tag: string): Command {
diff --git a/worker/scripts/checkout_ci.ts b/worker/scripts/checkout_ci.ts
index ac36d69..65cbc2e 100755
--- a/worker/scripts/checkout_ci.ts
+++ b/worker/scripts/checkout_ci.ts
@@ -150,6 +150,16 @@ await LogMetricTraceable.ofLogTraceable(logTraceableJob)
() => afterJob,
);
})
+ .map(
+ TraceUtil.promiseify((e) =>
+ e.get().fold(
+ (err) => {
+ throw err;
+ },
+ (ok) => ok,
+ ),
+ ),
+ )
.get();
function getWorkingDirectoryForCiJob(job: CheckoutCiJob) {