2.0 KiB · text History b868907
#!/bin/sh
# gitgud-hook — invoked by post-receive in each bare repo.
#
# Reads `<old> <new> <ref>` lines from stdin and POSTs them to the
# Phoenix node along with the repo path so it can identify which
# Repository row to enqueue cache + workflow jobs against.

set -eu

GITGUD_HOOK_URL="${GITGUD_HOOK_URL:-http://127.0.0.1:4000/_hooks/post-receive}"
REPO_PATH="${GIT_DIR:-$(pwd)}"

# `$(pwd)` resolves to the repo's worktree-less directory in a bare
# repo when the hook runs; we send its absolute path so Phoenix can
# look up the matching repository row.
REPO_PATH="$(cd "$REPO_PATH" && pwd)"

STDIN_PAYLOAD="$(cat)"

# The transport (SSH channel / smart-HTTP CGI) exports GITGUD_PUSHER_ID
# with the id of the authenticated pusher. Forward it so Phoenix can
# attribute the workflow runs this push triggers. Absent for anonymous
# pushes — then we just omit the header.
PUSHER_HEADER=""
if [ -n "${GITGUD_PUSHER_ID:-}" ]; then
  PUSHER_HEADER="x-pusher-id: ${GITGUD_PUSHER_ID}"
fi

# Smart HTTP exports GITGUD_JOB_ID when the push was made with a CI
# job's token. Such a push starts no workflows (as on GitHub), so a job
# that pushes can't keep starting itself.
JOB_HEADER=""
if [ -n "${GITGUD_JOB_ID:-}" ]; then
  JOB_HEADER="x-job-id: ${GITGUD_JOB_ID}"
fi

# The node's hook secret (GitGudWeb.Plugs.HookAuth), inherited from the
# git process that runs this hook. Fed to curl on stdin rather than as
# an argument, so it doesn't show up in `ps`.
# Use --data-binary so we preserve exact bytes (newlines etc).
printf 'x-gitgud-hook-token: %s\n' "${GITGUD_HOOK_SECRET:-}" | curl -sf -X POST \
  -H @- \
  -H "content-type: text/plain" \
  -H "x-repo-path: ${REPO_PATH}" \
  ${PUSHER_HEADER:+-H "${PUSHER_HEADER}"} \
  ${JOB_HEADER:+-H "${JOB_HEADER}"} \
  --data-binary "${STDIN_PAYLOAD}" \
  "${GITGUD_HOOK_URL}" >/dev/null || {
    echo "gitgud-hook: failed to notify ${GITGUD_HOOK_URL}" >&2
    # Don't fail the push if the bridge is briefly unavailable;
    # the user already pushed successfully, we just lost the
    # notification. Server-side reconciliation will catch up.
  }