From c4ef8a9ea418a48b226421cd5c95ad0e724b8565 Mon Sep 17 00:00:00 2001 From: dbrosio3 Date: Fri, 22 May 2026 16:38:43 -0300 Subject: [PATCH] feat: enhance pre-push error handling and output reporting --- bin/pushgate.mjs | 14 ++++++-------- hook/pre-push | 10 +++++++++- test/hook.test.ts | 19 +++++++++++++++++++ test/support/hook-harness.ts | 6 ++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/bin/pushgate.mjs b/bin/pushgate.mjs index 2908d60..e118396 100755 --- a/bin/pushgate.mjs +++ b/bin/pushgate.mjs @@ -17,7 +17,7 @@ switch (command) { process.stdout.write(`${HOOK_PROTOCOL}\n`); break; case "pre-push": - await drainStdin(); + drainStdin(); break; default: fail(command ? `Unsupported Pushgate command: ${command}` : "Missing Pushgate command."); @@ -28,15 +28,13 @@ function fail(message) { process.exitCode = 64; } -async function drainStdin() { - try { - for await (const _chunk of process.stdin) { - // Drain Git hook ref updates. Later runner layers will parse this stream. - } - } catch (error) { +function drainStdin() { + process.stdin.on("error", (error) => { const detail = error instanceof Error ? error.message : String(error); process.stderr.write(`Failed to read pre-push input: ${detail}\n`); process.exitCode = 1; - } + }); + // Drain Git hook ref updates. Later runner layers will parse this stream. + process.stdin.resume(); } diff --git a/hook/pre-push b/hook/pre-push index af2ebc7..d3582a3 100755 --- a/hook/pre-push +++ b/hook/pre-push @@ -44,8 +44,16 @@ if [ ! -x "$PUSHGATE_RUNNER" ]; then exit 1 fi -if ! RUNNER_PROTOCOL="$("$PUSHGATE_RUNNER" hook-protocol 2>/dev/null)"; then +if ! RUNNER_PROTOCOL="$("$PUSHGATE_RUNNER" hook-protocol 2>&1)"; then error "Pushgate runner at ${PUSHGATE_RUNNER} could not report its hook protocol." + if [ -n "$RUNNER_PROTOCOL" ]; then + error "Runner output:" + while IFS= read -r line; do + error " $line" + done < { }); }); +test("surfaces runner output when the protocol probe cannot execute", async () => { + await withHarness(async (harness) => { + await harness.installRunnerStub(); + + const result = await harness.runHook({ + env: { + PUSHGATE_RUNNER_PROTOCOL_ERROR: "env: node: No such file or directory", + PUSHGATE_RUNNER_PROTOCOL_EXIT: "127", + }, + stdin: "", + }); + const output = cleanHookOutput(result); + + assert.equal(result.code, 1, output); + assert.match(output, /could not report its hook protocol/); + assert.match(output, /env: node: No such file or directory/); + }); +}); + test("allows a real installed-hook push through the boundary runner", async () => { await withHarness(async (harness) => { await harness.installRealRunner(); diff --git a/test/support/hook-harness.ts b/test/support/hook-harness.ts index d1918c5..fc6112a 100644 --- a/test/support/hook-harness.ts +++ b/test/support/hook-harness.ts @@ -95,6 +95,10 @@ case "\${1:-}" in if [ "$#" -ne 1 ]; then exit 64 fi + if [ "$PUSHGATE_RUNNER_PROTOCOL_EXIT" -ne 0 ]; then + printf '%s\\n' "$PUSHGATE_RUNNER_PROTOCOL_ERROR" >&2 + exit "$PUSHGATE_RUNNER_PROTOCOL_EXIT" + fi printf '%s\\n' "$PUSHGATE_RUNNER_PROTOCOL" ;; pre-push) @@ -312,6 +316,8 @@ function createSandboxEnv( PATH: [binDir, ...systemPath].join(delimiter), PUSHGATE_RUNNER_EXIT: "0", PUSHGATE_RUNNER_PROTOCOL: "1", + PUSHGATE_RUNNER_PROTOCOL_ERROR: "", + PUSHGATE_RUNNER_PROTOCOL_EXIT: "0", PUSHGATE_STUB_DIR: artifactsDir, TERM: "dumb", XDG_CONFIG_HOME: join(homeDir, ".config"),