diff --git a/README.md b/README.md index db8e995..8f8b7cd 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,35 @@ This returns the oldest added payload on queue `foo` and removes it, guaranteein That's all you need to get started! 😎 +## Production quality gate + +The production TypeScript quality gate uses messcript at the pinned commit +`4fe47bd0f15675206aedd0f22ae5eff7aeb01707`. The Node wrapper checks out that +revision into the ignored `node_modules/.cache/queue-messcript` directory, +installs its locked dependencies, builds it, and then runs the CLI. It does not +affect the Deno service or its dependencies. + +Run a named production unit with Node 20.11 or newer: + +``` +npm run quality:unit -- configuration +``` + +The available units are `configuration`, `router`, `middleware`, +`rate-limiter`, `queue-manager`, `persist-engine`, `http-handler`, and +`entrypoint`. Run the complete production gate with: + +``` +npm run quality:production +``` + +Both commands use messcript's recommended `typescript` policy, including its +default `CyclomaticComplexity` and `NPathComplexity` rules and thresholds. The +aggregate scope is explicit: it includes only the eight production units above +and excludes tests, mutation infrastructure, documentation, CI configuration, +generated output, and development tooling. Findings and processing errors +retain messcript's normal non-zero exit status. + To get the number of payloads pending on a queue, send a get request to `/length/:queue` ``` diff --git a/package.json b/package.json new file mode 100644 index 0000000..5ab1960 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "queue-quality-gate", + "private": true, + "engines": { + "node": ">=20.11.0" + }, + "scripts": { + "quality:unit": "node scripts/messcript.mjs", + "quality:production": "node scripts/messcript.mjs all" + } +} diff --git a/scripts/messcript.mjs b/scripts/messcript.mjs new file mode 100644 index 0000000..45fb6d2 --- /dev/null +++ b/scripts/messcript.mjs @@ -0,0 +1,153 @@ +import { spawnSync } from "node:child_process"; +import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import process from "node:process"; +import { fileURLToPath } from "node:url"; + +const projectRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); +const messcriptRepository = "https://github.com/quality-gates/messcript.git"; +const messcriptCommit = "4fe47bd0f15675206aedd0f22ae5eff7aeb01707"; +const toolRoot = join(projectRoot, "node_modules", ".cache", "queue-messcript"); +const buildMarker = join(toolRoot, `.built-${messcriptCommit}`); +const messcriptCli = join(toolRoot, "dist", "cli.js"); + +const productionUnits = new Map([ + ["configuration", ["src/config.ts"]], + ["router", ["src/router.ts"]], + ["middleware", ["src/middleware.ts"]], + ["rate-limiter", ["src/rate_limiter.ts"]], + ["queue-manager", ["src/manager.ts"]], + ["persist-engine", ["src/persist.ts"]], + ["http-handler", ["src/handler.ts"]], + ["entrypoint", ["main.ts"]], +]); + +function run(command, args, cwd) { + const result = spawnSync(command, args, { + cwd, + stdio: "inherit", + }); + + if (result.error) { + console.error(`Unable to run ${command}: ${result.error.message}`); + return 1; + } + + return result.status ?? 1; +} + +function capture(command, args, cwd) { + const result = spawnSync(command, args, { + cwd, + encoding: "utf8", + }); + + if (result.error || result.status !== 0) { + return undefined; + } + + return result.stdout.trim(); +} + +function acquireMesscript() { + mkdirSync(dirname(toolRoot), { recursive: true }); + + if (!existsSync(join(toolRoot, ".git"))) { + if (existsSync(toolRoot)) { + throw new Error(`${toolRoot} exists but is not a Git checkout`); + } + + const cloneExit = run("git", [ + "clone", + "--quiet", + messcriptRepository, + toolRoot, + ], projectRoot); + if (cloneExit !== 0) { + return cloneExit; + } + } + + const fetchExit = run( + "git", + ["fetch", "--quiet", "origin", messcriptCommit], + toolRoot, + ); + if (fetchExit !== 0) { + return fetchExit; + } + + const checkoutExit = run("git", [ + "checkout", + "--quiet", + "--detach", + messcriptCommit, + ], toolRoot); + if (checkoutExit !== 0) { + return checkoutExit; + } + + const checkedOutCommit = capture("git", ["rev-parse", "HEAD"], toolRoot); + if (checkedOutCommit !== messcriptCommit) { + throw new Error( + `messcript checkout is ${ + checkedOutCommit ?? "unknown" + }, expected ${messcriptCommit}`, + ); + } + + if (!existsSync(buildMarker) || !existsSync(messcriptCli)) { + const installExit = run("npm", [ + "ci", + "--ignore-scripts", + "--no-audit", + "--no-fund", + ], toolRoot); + if (installExit !== 0) { + return installExit; + } + + const buildExit = run("npm", ["run", "build"], toolRoot); + if (buildExit !== 0) { + return buildExit; + } + + writeFileSync(buildMarker, `${messcriptCommit}\n`); + } + + return 0; +} + +function requestedPaths(unitName) { + if (unitName === "all") { + return [...productionUnits.values()].flat(); + } + + const paths = productionUnits.get(unitName); + if (!paths) { + const names = [...productionUnits.keys(), "all"].join(", "); + throw new Error( + `Unknown production unit '${unitName}'. Choose one of: ${names}`, + ); + } + return paths; +} + +const unitName = process.argv[2] ?? "all"; + +try { + const paths = requestedPaths(unitName); + const acquireExit = acquireMesscript(); + if (acquireExit !== 0) { + process.exitCode = acquireExit; + } else { + process.exitCode = run( + "node", + [messcriptCli, paths.join(","), "text", "typescript", "--color=never"], + projectRoot, + ); + } +} catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; +}