// A stand-in for scripts/gitea-api.sh in the review tests: same argv // (METHOD PATH [BODY]), same output (body on stdout, "HTTP " on // stderr, exit 1 on a non-2xx code). It reads no credential file; the login // comes from the credential path's agents// segment. Every call is // appended to $FAKE_GITEA_LOG, and posted comments are served back from it. // $FAKE_GITEA_SCENARIO names a JSON file of rules that override the // defaults: {rules: [{method, path (regex), http, body, sleepMs, fail}]}. import { appendFileSync, existsSync, readFileSync } from "node:fs"; const [method, path, body] = process.argv.slice(2); const env = process.env; const read = (f) => (f && existsSync(f) ? readFileSync(f, "utf8") : null); const scenario = JSON.parse(read(env.FAKE_GITEA_SCENARIO) ?? "{}"); const prior = (read(env.FAKE_GITEA_LOG) ?? "").split("\n").filter(Boolean).map((l) => JSON.parse(l)); const cred = env.MOSAIC_GITEA_CREDENTIAL_FILE ?? ""; const loginOf = (p) => /\/agents\/([^/]+)\/secrets\//.exec(p)?.[1] ?? null; const login = loginOf(cred); appendFileSync(env.FAKE_GITEA_LOG, `${JSON.stringify({ method, path, body: body === undefined ? null : JSON.parse(body), cred })}\n`); function answer(http, obj) { if (obj !== undefined) process.stdout.write(typeof obj === "string" ? obj : JSON.stringify(obj)); process.stderr.write(`HTTP ${http}\n`); if (http < 200 || http > 299) { process.stderr.write(`gitea-api: ${method} ${path} failed (HTTP ${http})\n`); process.exit(1); } process.exit(0); } const issueUrl = (n) => `https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/${n}`; const rule = (scenario.rules ?? []).find((r) => r.method === method && new RegExp(r.path).test(path)); if (rule) { if (rule.sleepMs) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, rule.sleepMs); if (rule.fail) { process.stderr.write("gitea-api: request failed\n"); process.exit(1); } if (rule.http) answer(rule.http, rule.body); } let m; if (method === "GET" && path === "user") answer(200, { login }); if (method === "POST" && (m = /^repos\/mosaicstack\/stack\/issues\/(\d+)\/comments$/.exec(path))) { const id = 1000 + prior.filter((p) => p.method === "POST").length; answer(201, { id, issue_url: issueUrl(m[1]), body: JSON.parse(body).body, user: { login } }); } if (method === "GET" && (m = /^repos\/mosaicstack\/stack\/issues\/comments\/(\d+)$/.exec(path))) { const id = Number(m[1]); const post = prior.filter((p) => p.method === "POST")[id - 1000]; if (post) answer(200, { id, issue_url: issueUrl(/issues\/(\d+)\/comments$/.exec(post.path)[1]), body: post.body.body, user: { login: loginOf(post.cred) } }); answer(404, { message: "not found" }); } answer(404, { message: "no route" });