From 2ae2ebc8aa7c4600f499ab7d2264dcb1d16db4ae Mon Sep 17 00:00:00 2001 From: Elizabeth Date: Mon, 2 Jun 2025 19:27:15 -0700 Subject: Fixes when getStdout would throw early --- mod.ts | 2 +- server/health.ts | 15 ++++++++---- server/mod.ts | 2 +- u/fn/either.ts | 18 +++++++-------- u/process/env.ts | 9 +++++--- u/process/run.ts | 18 +++++++++------ u/trace/itrace.ts | 2 +- u/trace/logger.ts | 51 ++++++++++++++++++++++++++--------------- worker/jobs/ci_pipeline.run | 4 ++-- worker/scripts/ansible_playbook | 2 +- 10 files changed, 76 insertions(+), 47 deletions(-) diff --git a/mod.ts b/mod.ts index 98470fc..b239992 100755 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S deno run --allow-env --allow-net +#!/usr/bin/env -S deno run --allow-env --allow-net --allow-run import { argv, IEither, Either } from "@emprespresso/pengueno"; import { runServer } from "@emprespresso/ci_server"; diff --git a/server/health.ts b/server/health.ts index 8fbc69d..e69077b 100644 --- a/server/health.ts +++ b/server/health.ts @@ -17,9 +17,16 @@ export const healthCheck: HealthChecker = ( .bimap(TraceUtil.withFunctionTrace(healthCheck)) .move(getRequiredEnv("LAMINAR_HOST")) // ensure LAMINAR_HOST is propagated to getStdout for other procedures - .map((tEitherEnv) => tEitherEnv.get() + .map((tEitherEnv) => + tEitherEnv + .get() .flatMapAsync((_hasEnv) => - getStdout(tEitherEnv.move(["laminarc", "show-jobs"])) - )) - .map(TraceUtil.promiseify((stdout) => stdout.get().moveRight(HealthCheckOutput.YAASSSLAYQUEEN))) + getStdout(tEitherEnv.move(["laminarc", "show-jobs"])), + ), + ) + .map( + TraceUtil.promiseify((stdout) => + stdout.get().moveRight(HealthCheckOutput.YAASSSLAYQUEEN), + ), + ) .get(); diff --git a/server/mod.ts b/server/mod.ts index 1fd4e99..02b307a 100644 --- a/server/mod.ts +++ b/server/mod.ts @@ -18,5 +18,5 @@ export const runServer = ( }; return Either.fromFailable(() => Deno.serve(serverConfig, (req) => server.serve(req)), - ).flatMapAsync((server) => Either.fromFailableAsync(server.finished)); + ).flatMapAsync((server) => Either.fromFailableAsync(() => server.finished)); }; diff --git a/u/fn/either.ts b/u/fn/either.ts index 54f9fc2..ffe8033 100644 --- a/u/fn/either.ts +++ b/u/fn/either.ts @@ -32,7 +32,7 @@ export class Either implements IEither { private readonly self: Left | Right; private constructor( - init: { err?: E, ok?: T }, + init: { err?: E; ok?: T }, public readonly _tag: IEitherTag = iEitherTag, ) { this.self = | Right>{ @@ -85,11 +85,11 @@ export class Either implements IEither { } static left(e: E): IEither { - return new Either({ err: e}); + return new Either({ err: e }); } static right(t: T): IEither { - return new Either({ok: t}); + return new Either({ ok: t }); } static fromFailable(s: Supplier): IEither { @@ -100,12 +100,12 @@ export class Either implements IEither { } } - static async fromFailableAsync(s: Promise): Promise> { - try { - return Either.right(await s); - } catch (e) { - return Either.left(e as E); - } + static async fromFailableAsync( + s: Supplier>, + ): Promise> { + return await s() + .then((t: T) => Either.right(t)) + .catch((e: E) => Either.left(e)); } } diff --git a/u/process/env.ts b/u/process/env.ts index 470cb39..5ba4189 100644 --- a/u/process/env.ts +++ b/u/process/env.ts @@ -1,10 +1,13 @@ import { Either, type IEither } from "@emprespresso/pengueno"; export const getRequiredEnv = (name: V): IEither => - Either.fromFailable(() => Deno.env.get(name) as V | undefined) // could throw when no permission. + Either.fromFailable( + () => Deno.env.get(name) as V | undefined, + ) // could throw when no permission. .flatMap( - (v) => (v && Either.right(v)) || - Either.left(new Error(`environment variable "${name}" is required D:`)) + (v) => + (v && Either.right(v)) || + Either.left(new Error(`environment variable "${name}" is required D:`)), ); type ObjectFromList, V = string> = { diff --git a/u/process/run.ts b/u/process/run.ts index 8004f75..7a74c3e 100644 --- a/u/process/run.ts +++ b/u/process/run.ts @@ -28,10 +28,12 @@ export const getStdout = ( stdout: "piped", stderr: "piped", ...options, - }).output(); + }); }) - .map((tOut) => - Either.fromFailableAsync(tOut.get()), + .map((tCmd) => + Either.fromFailableAsync(() => + tCmd.get().output(), + ), ) .map( TraceUtil.promiseify((tEitherOut) => @@ -45,11 +47,13 @@ export const getStdout = ( tEitherOut.trace.addTrace(LogLevel.ERROR).trace(`o.o wat ${e}`); return new Error(`${e}`); }) - .flatMap((decodedOutput): Either => { + .flatMap((decodedOutput): IEither => { const { code, stdoutText, stderrText } = decodedOutput; - tEitherOut.trace - .addTrace(LogLevel.DEBUG) - .trace(`stderr hehehe ${stderrText}`); + if (stderrText) { + tEitherOut.trace + .addTrace(LogLevel.DEBUG) + .trace(`stderr: ${stderrText}`); + } if (code !== 0) { const msg = `i weceived an exit code of ${code} i wanna zewoooo :<`; tEitherOut.trace.addTrace(LogLevel.ERROR).trace(msg); diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts index c3cb8ad..fcfbe32 100644 --- a/u/trace/itrace.ts +++ b/u/trace/itrace.ts @@ -48,7 +48,7 @@ export class TraceableImpl implements ITraceable { public flatMap<_T>( mapper: ITraceableMapper, TraceWith>, ): ITraceable<_T, TraceWith> { - return mapper(this); + return mapper(this); } public flatMapAsync<_T>( diff --git a/u/trace/logger.ts b/u/trace/logger.ts index 4f29839..8e62b02 100644 --- a/u/trace/logger.ts +++ b/u/trace/logger.ts @@ -11,6 +11,7 @@ export interface ILogger { debug: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void; + sys: (...args: unknown[]) => void; } export enum LogLevel { UNKNOWN = "UNKNOWN", @@ -18,6 +19,7 @@ export enum LogLevel { WARN = "WARN", DEBUG = "DEBUG", ERROR = "ERROR", + SYS = "SYS", } const logLevelOrder: Array = [ LogLevel.DEBUG, @@ -35,6 +37,7 @@ const defaultAllowedLevels = () => LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, + LogLevel.SYS, ] as Array; export const logWithLevel = ( @@ -51,13 +54,21 @@ export const logWithLevel = ( return logger.warn; case LogLevel.ERROR: return logger.error; + case LogLevel.SYS: + return logger.sys; } }; export type LogTraceSupplier = ITraceWith>; const defaultTrace = () => `[${new Date().toISOString()}]`; -export const LoggerImpl = console; +export const LoggerImpl = { + log: console.log, + debug: console.debug, + warn: console.warn, + error: console.error, + sys: console.log, +}; export class LogTrace implements ITrace { constructor( private readonly logger: ILogger = LoggerImpl, @@ -78,28 +89,32 @@ export class LogTrace implements ITrace { } public trace(trace: LogTraceSupplier) { - const { line, level: _level } = this.foldTraces(this.traces.concat(trace)); + const { traces, level: _level } = this.foldTraces( + this.traces.concat(trace), + ); if (!this.allowedLevels().includes(_level)) return; const level = _level === LogLevel.UNKNOWN ? this.defaultLevel : _level; - logWithLevel(this.logger, level)(`[${level}]${line}`); + const line = { level, message: traces.at(-1), traces: traces.slice(0, -1) }; + logWithLevel( + this.logger, + level, + )(line); } - private foldTraces(traces: Array) { - const { line, level } = traces.reduce( - (acc: { line: string; level: number }, t) => { - const val = typeof t === "function" ? t() : t; - if (isLogLevel(val)) { - return { - ...acc, - level: Math.max(logLevelOrder.indexOf(val), acc.level), - }; - } - const line = [acc.line, val].join(" "); - return { ...acc, line }; - }, - { line: "", level: -1 }, + private foldTraces(_traces: Array) { + const _logTraces = _traces.map((trace) => + typeof trace === "function" ? trace() : trace, ); - return { line, level: logLevelOrder[level] ?? LogLevel.UNKNOWN }; + const _level = _logTraces + .filter((trace) => isLogLevel(trace)) + .reduce((acc, level) => Math.max(logLevelOrder.indexOf(level), acc), -1); + const level = logLevelOrder[_level] ?? LogLevel.UNKNOWN; + + const traces = _logTraces.filter((trace) => !isLogLevel(trace)); + return { + level, + traces, + }; } } diff --git a/worker/jobs/ci_pipeline.run b/worker/jobs/ci_pipeline.run index 46237f6..66b02ed 100644 --- a/worker/jobs/ci_pipeline.run +++ b/worker/jobs/ci_pipeline.run @@ -48,7 +48,7 @@ await LogMetricTraceable.ofLogTraceable(_logJob) }, }; return Either.fromFailableAsync( - Deno.mkdir(wd).then(() => Deno.chdir(wd)) + () => Deno.mkdir(wd).then(() => Deno.chdir(wd)) .then(() => tEitherJob.move(fetchPackageJob).map(executeJob).get()) .then(() => ciJob), ); @@ -58,7 +58,7 @@ await LogMetricTraceable.ofLogTraceable(_logJob) tEitherCiJob.get().then((eitherCiJob) => eitherCiJob.flatMapAsync<{ cmd: Command; job: CheckoutCiJob }>((ciJob) => Either.fromFailableAsync( - Deno.readTextFile( + () => Deno.readTextFile( `${getSrcDirectoryForCiJob(ciJob)}/${CI_WORKFLOW_FILE}`, ), ).then((eitherWorkflowJson) => diff --git a/worker/scripts/ansible_playbook b/worker/scripts/ansible_playbook index 026f892..fe2810b 100755 --- a/worker/scripts/ansible_playbook +++ b/worker/scripts/ansible_playbook @@ -104,7 +104,7 @@ await LogMetricTraceable.ofLogTraceable(_logJob).bimap(TraceUtil.withMetricTrace const saveToTempFile = (text: string): Promise> => Either.fromFailableAsync( - Deno.makeTempDir({ dir: Deno.cwd() }) + () => Deno.makeTempDir({ dir: Deno.cwd() }) .then((dir) => Deno.makeTempFile({ dir })) .then(async (f) => { await Deno.writeTextFile(f, text); -- cgit v1.2.3-70-g09d2