// The git hook every push runs, as a Node.js script. See lib/push-hooks.ts for the other side. /** * The pre-receive hook, run by git with the push's " " lines on stdin. It refuses * refs with a path component starting with "-" (git commands could mistake them for options) by * itself, and asks the server about everything else. Without a session (receive-pack started by * something other than Vectrum) it only does the first. */ export function hookScript() { return `#!${process.execPath} "use strict"; // Written by Vectrum (lib/hook-script.ts); rewritten on every start. const { execFileSync } = require("node:child_process"); const net = require("node:net"); const ZERO = /^0+$/; let input = ""; process.stdin.setEncoding("utf8"); process.stdin.on("data", (d) => (input += d)); process.stdin.on("end", () => { const updates = input.split("\\n").filter(Boolean).map((line) => { const [oldSha, newSha, ref] = line.trim().split(" "); return { old: oldSha, new: newSha, ref }; }); const bad = updates.filter((u) => ("/" + u.ref).includes("/-")); if (bad.length) { for (const u of bad) console.error("Vectrum: refusing " + u.ref + " (ref name components must not start with '-')"); process.exit(1); } const socket = process.env.VECTRUM_HOOK_SOCKET; const token = process.env.VECTRUM_PUSH_TOKEN; if (!socket || !token) process.exit(0); for (const u of updates) { u.ff = true; if (ZERO.test(u.old) || ZERO.test(u.new) || !u.ref.startsWith("refs/heads/")) continue; try { execFileSync("git", ["merge-base", "--is-ancestor", u.old, u.new], { stdio: "ignore" }); } catch { u.ff = false; } } const fail = (message) => { console.error("Vectrum: " + message); process.exit(1); }; const timer = setTimeout(() => fail("timed out checking the branch rules."), 20000); let reply = ""; const conn = net.createConnection(socket, () => conn.write(JSON.stringify({ token, updates }) + "\\n")); conn.setEncoding("utf8"); conn.on("data", (d) => (reply += d)); conn.on("error", () => fail("couldn't check the branch rules. Try again.")); conn.on("end", () => { clearTimeout(timer); let answer; try { answer = JSON.parse(reply); } catch { return fail("couldn't check the branch rules. Try again."); } for (const m of answer.messages || []) for (const line of String(m).split("\\n")) console.error("Vectrum: " + line); process.exit(answer.ok ? 0 : 1); }); }); `; }