#!/usr/bin/env bash # Keep the GitHub mirror in step with the deploy (CLAUDE.md "Two remotes", ADR-0007). # # `origin` IS the HuggingFace Space: pushing `main` there DEPLOYS. `github` is a mirror that # only runs CI. Nothing links them, so the mirror silently falls behind every deploy — and a # stale mirror means Monday's `curation-freshness` job reports on artifacts the Space no longer # serves. A freshness check that is itself stale is worse than none, because it reads as # reassurance. # # This hook closes that gap at the only moment git offers: when a deploy push is about to # happen. Install with: make install-hooks # # --------------------------------------------------------------------------------------------- # Two honest limitations, neither of which is worth engineering around: # # 1. **The mirror is pushed FIRST.** Git has no post-push hook, so "after the deploy succeeds" # is not a thing this can be. If the `origin` push then fails (usually a non-fast-forward), # `github` is briefly AHEAD of the live Space. That self-corrects on the next successful # deploy, and CI running a superset of production is the milder of the two errors — the one # this hook exists to prevent is CI running a SUBSET, which looks like a pass. # 2. **A mirror failure warns; it does not block.** The mirror is CI; `origin` is production. # Refusing to ship because a secondary remote was unreachable is disproportionate. The # warning names the one command that fixes it. # # Bypass entirely with `git push --no-verify`. # --------------------------------------------------------------------------------------------- set -euo pipefail remote_name="${1:-}" remote_url="${2:-}" mirror_remote="${MIRROR_REMOTE:-github}" dev_remote="${DEV_REMOTE:-hf-dev}" # The dev Space is also a huggingface.co remote, and `git push hf-dev dev:main` also targets # refs/heads/main — so it satisfies BOTH tests below. Mirroring it would push dev code onto the # mirror's `main`, where CI reads it as production: exactly the stale/wrong-CI failure this hook # exists to prevent, inverted. Excluded by name AND by URL, before the deploy test. case "$remote_name$remote_url" in "$dev_remote"*|*-dev|*-dev.git|*-dev/) exit 0 ;; esac # Only deploy pushes matter. Match on the URL as well as the name so a push by URL, or a # differently-named deploy remote, is still recognised. case "$remote_name$remote_url" in origin*|*huggingface.co*) ;; *) exit 0 ;; esac # stdin: " " per ref being pushed. main_sha="" while read -r _local_ref local_sha remote_ref _remote_sha; do [ "$remote_ref" = "refs/heads/main" ] || continue # All-zero local sha = a branch DELETE. Never mirror that. case "$local_sha" in *[!0]*) main_sha="$local_sha" ;; esac done [ -n "$main_sha" ] || exit 0 # nothing headed for main — not a deploy if ! git remote get-url "$mirror_remote" >/dev/null 2>&1; then echo "[pre-push] no '$mirror_remote' remote — the CI mirror will fall behind this deploy." >&2 echo "[pre-push] git remote add $mirror_remote https://github.com/Anne-Voigt/pdac-genomics-agent.git" >&2 exit 0 fi echo "[pre-push] mirroring ${main_sha:0:7} to '$mirror_remote' so CI matches what is deployed…" if git push --quiet "$mirror_remote" "$main_sha:refs/heads/main"; then echo "[pre-push] mirror in sync — proceeding with the deploy." else echo "[pre-push] WARNING: mirror push failed. The deploy will proceed; CI is now STALE." >&2 echo "[pre-push] Fix it after the deploy with: git push $mirror_remote main" >&2 fi exit 0