Spaces:
Running
Running
File size: 8,439 Bytes
88d2f2a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | #!/usr/bin/env bash
# =============================================================================
# scripts/deploy_to_hf.sh β one-command deploy to Hugging Face Spaces.
# =============================================================================
# Strategy: snapshot the current main commit into a fresh orphan branch, swap
# README.md for the HF-flavored version (with the YAML frontmatter Spaces
# needs), force-push that single-commit branch as HF's `main`, then clean up.
#
# Why an orphan branch (not a regular merge / push of main)?
# 1. HF Spaces requires YAML frontmatter at the top of README.md so it
# knows to launch a Docker container. GitHub's full README has none β
# we only want the swap to live on the deploy branch, not on main.
# 2. main's git history is ~1000+ commits. HF pushes carry the full
# reachable history, and any historical commit that ever held a
# binary >10 MB would fail HF's pre-receive hook. Orphan = 1 commit,
# no history to litigate.
#
# Prerequisites:
# * `hf` remote already configured (run once:
# git remote add hf https://huggingface.co/spaces/messili/polyglot-alpha)
# * `hf auth login` already done (token cached by huggingface_hub CLI).
# * Working tree is clean on main, or untracked-only.
# -----------------------------------------------------------------------------
set -euo pipefail
# ---- color/log helpers ------------------------------------------------------
if [[ -t 1 ]]; then
BLUE=$'\033[34m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; RED=$'\033[31m'; RESET=$'\033[0m'
else
BLUE=''; GREEN=''; YELLOW=''; RED=''; RESET=''
fi
log() { printf '%s[deploy]%s %s\n' "$BLUE" "$RESET" "$*"; }
ok() { printf '%s[deploy]%s %s\n' "$GREEN" "$RESET" "$*"; }
warn() { printf '%s[deploy]%s %s\n' "$YELLOW" "$RESET" "$*" >&2; }
die() { printf '%s[deploy]%s %s\n' "$RED" "$RESET" "$*" >&2; exit 1; }
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_ROOT"
# ---- preflight checks -------------------------------------------------------
log "preflight checks"
git remote get-url hf > /dev/null 2>&1 || die "hf remote not configured. Run: git remote add hf https://huggingface.co/spaces/messili/polyglot-alpha"
[[ -f deploy/hf-readme.md ]] || die "deploy/hf-readme.md missing β HF needs the YAML frontmatter version"
[[ -f Dockerfile ]] || die "Dockerfile missing β HF Spaces is a Docker SDK Space"
[[ -f deploy/nginx.conf ]] || die "deploy/nginx.conf missing β required by Dockerfile"
[[ -f deploy/entrypoint.sh ]] || die "deploy/entrypoint.sh missing β required by Dockerfile"
# Working tree state: tracked changes block deploy, untracked are fine.
if ! git diff-index --quiet HEAD --; then
die "working tree has uncommitted tracked changes; commit or stash first"
fi
# Contract ABIs (contracts/out/*.json) are not tracked on main (excluded by
# contracts/.gitignore from Foundry), but the backend NEEDS them at runtime
# to know the deployed contract interfaces. Build them now so the orphan
# snapshot includes a freshly compiled set.
command -v forge >/dev/null 2>&1 || die "forge not installed β install Foundry: https://book.getfoundry.sh/getting-started/installation"
log "running forge build to refresh contracts/out/ (compiled ABIs)"
( cd contracts && forge build --silent ) || die "forge build failed β fix contracts before deploying"
[[ -d contracts/out ]] || die "forge build succeeded but contracts/out/ missing β something is very wrong"
ORIGINAL_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
if [[ "$ORIGINAL_BRANCH" != "main" ]]; then
warn "currently on '$ORIGINAL_BRANCH' (not main) β will checkout main"
git checkout main
fi
MAIN_SHA_SHORT="$(git rev-parse --short HEAD)"
TMP_BRANCH="hf-deploy-$(date +%Y%m%d-%H%M%S)"
log "deploying main @ $MAIN_SHA_SHORT β hf:main (via temp orphan '$TMP_BRANCH')"
# ---- cleanup trap -----------------------------------------------------------
# If anything below fails, restore the user to their starting branch, restore
# contracts/.git if we moved it, and delete the temp orphan branch so they
# don't end up stuck on a half-built orphan.
CONTRACTS_GIT_MOVED=0
cleanup() {
local exit_code=$?
# Restore contracts/.git if we renamed it.
if [[ "$CONTRACTS_GIT_MOVED" -eq 1 && -d contracts/.git.deploy-tmp ]]; then
mv contracts/.git.deploy-tmp contracts/.git
fi
# Switch off temp branch and delete it.
local current
current="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo HEAD)"
if [[ "$current" == "$TMP_BRANCH" || "$current" == "HEAD" ]]; then
git checkout --force "$ORIGINAL_BRANCH" 2>/dev/null || git checkout --force main 2>/dev/null || true
fi
if [[ -n "${TMP_BRANCH:-}" ]] && git show-ref --verify --quiet "refs/heads/$TMP_BRANCH"; then
git branch -D "$TMP_BRANCH" > /dev/null 2>&1 || true
fi
if [[ $exit_code -ne 0 ]]; then
warn "deploy aborted (exit $exit_code)"
fi
exit $exit_code
}
trap cleanup EXIT
# ---- build the orphan snapshot ---------------------------------------------
log "creating orphan branch '$TMP_BRANCH'"
git checkout --orphan "$TMP_BRANCH"
# `git checkout --orphan` keeps the working tree but stages everything. We
# want to start from a clean stage, then re-add everything filtered by
# .gitignore β so a stray binary in working tree doesn't sneak through.
git rm -rf --cached . > /dev/null 2>&1 || true
# Foundry leaves a nested `.git` in `contracts/` (its own submodule lockfile
# tracking). When the outer repo runs `git add -A`, it sees this as a
# (broken) submodule and aborts with "does not have a commit checked out".
# Temporarily rename it; the cleanup trap restores it on the way out.
if [[ -d contracts/.git ]]; then
log "temporarily renaming contracts/.git (foundry nested) so git add -A can recurse"
mv contracts/.git contracts/.git.deploy-tmp
CONTRACTS_GIT_MOVED=1
fi
git add -A
log "swapping README for HF-flavored version (deploy/hf-readme.md β README.md)"
cp deploy/hf-readme.md README.md
git add README.md
# contracts/out (compiled ABI JSON) is in .gitignore on main, but HF Spaces
# needs the ABIs at runtime β force-add the subdir into the orphan snapshot.
if [[ -d contracts/out ]]; then
log "force-adding contracts/out/ (ABIs needed by backend, ignored on main)"
git add -f contracts/out/
fi
# Drop dev-facing assets HF Spaces doesn't need and whose binaries trip
# HF's pre-receive hook (e.g. submission/diagrams/*.png are GitHub hackathon
# docs, never served by the Docker container). We `git rm --cached` them
# from the orphan index β the working tree copies stay so main is untouched
# when the cleanup trap checks us back out.
HF_EXCLUDE_PATHS=(
submission # hackathon write-up β GitHub-only
docs # design docs β GitHub-only
examples # operator example scripts β GitHub-only
contracts/lib # foundry submodules β only needed for forge build
contracts/cache # foundry compile cache
contracts/broadcast # foundry deploy logs
)
for path in "${HF_EXCLUDE_PATHS[@]}"; do
if git ls-files --cached "$path" 2>/dev/null | head -1 | grep -q .; then
git rm -r --cached --quiet "$path" > /dev/null 2>&1 || true
fi
done
# Single commit β HF only ever sees this one.
COMMIT_MSG="deploy: main@${MAIN_SHA_SHORT} β HF Spaces ($(date -u +%Y-%m-%dT%H:%MZ))"
git commit --quiet -m "$COMMIT_MSG"
ok "snapshot committed: $(git rev-parse --short HEAD)"
# ---- push to HF -------------------------------------------------------------
log "force-pushing to hf:main (HF Space will auto-rebuild on receipt)"
if ! git push hf "$TMP_BRANCH:main" --force 2>&1; then
die "push to HF failed β see error above. Common causes: stale auth ('hf auth login'), Space settings (sdk: docker required), or large files."
fi
ok "pushed β https://huggingface.co/spaces/messili/polyglot-alpha"
# ---- restore main, swap README back -----------------------------------------
log "restoring '$ORIGINAL_BRANCH' (your README.md never moved on main)"
git checkout --force "$ORIGINAL_BRANCH"
# Cleanup trap deletes the temp branch on exit.
ok "deploy complete"
echo
echo " HF Space: https://messili-polyglot-alpha.hf.space/"
echo " Build progress: https://huggingface.co/spaces/messili/polyglot-alpha"
echo " Cold rebuild ~3-5 min; warm rebuild ~30-60 s."
|