summaryrefslogtreecommitdiff
path: root/hooks/server/job/activity.ts
diff options
context:
space:
mode:
Diffstat (limited to 'hooks/server/job/activity.ts')
-rw-r--r--hooks/server/job/activity.ts100
1 files changed, 100 insertions, 0 deletions
diff --git a/hooks/server/job/activity.ts b/hooks/server/job/activity.ts
new file mode 100644
index 0000000..14ea459
--- /dev/null
+++ b/hooks/server/job/activity.ts
@@ -0,0 +1,100 @@
+import {
+ Either,
+ ErrorSource,
+ type IActivity,
+ type IEither,
+ type ITraceable,
+ jsonModel,
+ JsonResponse,
+ LogLevel,
+ Metric,
+ PenguenoError,
+ type PenguenoRequest,
+ type ServerTrace,
+ TraceUtil,
+ validateExecutionEntries,
+} from "@emprespresso/pengueno";
+import { isJob, type Job } from "@emprespresso/ci-model";
+import type { IJobQueuer } from "@emprespresso/ci-hooks";
+
+const wellFormedJobMetric = Metric.fromName("Job.WellFormed");
+
+const jobJsonTransformer = (
+ j: ITraceable<unknown, ServerTrace>,
+): IEither<PenguenoError, Job> =>
+ j.bimap(TraceUtil.withMetricTrace(wellFormedJobMetric))
+ .map((tJson) => {
+ if (!isJob(tJson) || !validateExecutionEntries(tJson)) {
+ const err = "seems like a pwetty mawfomed job \\(-.-)/";
+ tJson.trace.addTrace(LogLevel.WARN).trace(err);
+ return Either.left<PenguenoError, Job>(new PenguenoError(err, 400));
+ }
+ return Either.right<PenguenoError, Job>(tJson);
+ })
+ .peek((tJob) =>
+ tJob.trace.trace(
+ tJob.get().fold((err) =>
+ err ? wellFormedJobMetric.failure : wellFormedJobMetric.success
+ ),
+ )
+ )
+ .get();
+
+export interface IJobHookActivity {
+ processHook: IActivity;
+}
+
+const jobHookRequestMetric = Metric.fromName("JobHook.process");
+export class JobHookActivityImpl implements IJobHookActivity {
+ constructor(
+ private readonly queuer: IJobQueuer<ITraceable<Job, ServerTrace>>,
+ ) {}
+
+ private trace(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return r.bimap(TraceUtil.withClassTrace(this))
+ .bimap(
+ TraceUtil.withMetricTrace(jobHookRequestMetric),
+ );
+ }
+
+ public processHook(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return this.trace(r).map(jsonModel(jobJsonTransformer))
+ .map(async (tEitherJobJson) => {
+ const eitherJob = await tEitherJobJson.get();
+ return eitherJob.flatMapAsync(async (job) => {
+ const eitherQueued = await tEitherJobJson.move(job)
+ .map(this.queuer.queue)
+ .get();
+ return eitherQueued.mapLeft((e) => new PenguenoError(e.message, 500));
+ });
+ })
+ .peek(
+ TraceUtil.promiseify((tJob) =>
+ tJob.get().fold(
+ (err: PenguenoError | undefined, _val: string | undefined) => {
+ if (!err) {
+ tJob.trace.trace(jobHookRequestMetric.success);
+ tJob.trace.trace(`all queued up and weady to go :D !! ${_val}`);
+ return;
+ }
+ tJob.trace.trace(
+ err.source === ErrorSource.SYSTEM
+ ? jobHookRequestMetric.failure
+ : jobHookRequestMetric.warn,
+ );
+ tJob.trace.addTrace(err.source).trace(`${err}`);
+ },
+ )
+ ),
+ )
+ .map(
+ TraceUtil.promiseify((tEitherQueuedJob) =>
+ new JsonResponse(r, tEitherQueuedJob.get(), {
+ status: tEitherQueuedJob.get()
+ .fold(({ status }, _val) => _val ? 200 : status),
+ })
+ ),
+ )
+ .get();
+ }
+}