cds-snc/elenchos

View on GitHub
src/routes/index.ts

Summary

Maintainability
A
1 hr
Test Coverage
import express, { Response } from "express";
import {
  getVersion,
  handleEvent,
  checkEnv,
  noteError,
  enforceRefId,
  isCloseEvent,
  isBeforePr,
  beforePr,
  getRelease,
  dbCanConnect,
  isFailedCheckRun
} from "../lib";
import { ClusterWorker, Request, Release } from "../interfaces";
import { Worker, isMainThread } from "worker_threads";

let workers: ClusterWorker = {};

// terminate worker
const terminate = async (worker: Worker, refId: string): Promise<void> => {
  console.log(`terminate worker for refId: ${refId}`);
  ((worker.terminate() as unknown) as Promise<number>).then((code: number) => {
    console.log("index.ts => exit code", code);
    delete workers[refId];
  });
};
//  https://nodejs.org/api/worker_threads.html
export const setupWorker = (
  req: Request,
  refId: string,
  release: Release
): Worker => {
  // can init and send data
  console.log(`setup worker for refId ${refId}`);

  const w = new Worker("./worker.js", {
    workerData: { req, refId, release }
  });

  w.on("message", e => {
    terminate(w, refId);
  });

  return w;
};

const isBeforePrEvent = async (req: Request, res: Response) => {
  const defaultMessage = "✅ event received";
  let beforePR = false;

  // handle events before a PR
  if (isBeforePr(req)) {
    await beforePr(req);
    res.send(defaultMessage);
    beforePR = true;
  }

  return beforePR;
};

export const main = async (req: Request, res: Response) => {
  const refId = enforceRefId(req, res);
  const eventInfo = handleEvent(req);
  const defaultMessage = "✅ event received";

  await dbCanConnect(req, res);

  // check if we want to handle this type of event
  if (!eventInfo.handleEvent) {
    res.send(`✅ event ignored ${eventInfo.type}`);
    return;
  }

  console.log(`✅ version: ${getVersion()}`);
  console.log(`✅ event: ${eventInfo.type}  ✅ refId: ${refId} `);

  const closed = await isCloseEvent(req, res);

  if (closed) {
    return;
  }

  const beforePR = await isBeforePrEvent(req, res);

  if (beforePR) {
    return;
  }

  // handle deployment
  let release = await getRelease({ refId });

  /*
  // @todo needs more testing re-add to handleEvent at that point
  const failedRun = await isFailedCheckRun(req, refId);

  if (failedRun) {
    res.send(`❌failed check run`);
    return;
  }
  */

  // hand off to Worker
  if (isMainThread && checkEnv()) {
    // stop existing worker + start a new worker
    if (refId && workers[refId]) {
      //@ts-ignore
      await terminate(workers[refId], refId);
    }

    res.send(defaultMessage);

    //@ts-ignore
    workers[refId] = setupWorker({ body: req.body }, refId, release);
  }

  // if not res send ??
};

const router = express.Router();

router.get("/favicon.ico", (req, res) => res.status(204));

router.post("/", async (req: Request, res) => {
  try {
    await main(req, res);
  } catch (e) {
    noteError(`deploy ${e.message}`, e);
  }
});

export default router;