HF-SaaS / scripts /deploy.sh
luizcireno-crypto
chore: add clean deployment script + document mandatory workflow
07aa9a2
raw
history blame
5.15 kB
#!/bin/bash
# ============================================================
# HF-VPS β€” Clean Deployment Script
#
# Enforces the mandatory workflow:
# local changes β†’ GitHub (source of truth) β†’ HF Space
#
# Usage:
# bash scripts/deploy.sh # standard clean deploy
# bash scripts/deploy.sh --factory # factory reset (full Docker rebuild, no cache)
#
# Requirements:
# - .env.local must exist with HF_TOKEN set
# - Both git remotes must be configured:
# origin β†’ https://github.com/luizcireno-crypto/HF-SaaS.git
# hf β†’ https://huggingface.co/spaces/lulavc/HF-SaaS.git
#
# What this does:
# 1. Validates environment and git state
# 2. Pushes to GitHub (origin/main)
# 3. Force-pushes to HF Space (ensures no stale git refs or old files)
# 4. Optionally triggers a factory restart (full clean Docker rebuild)
# 5. Monitors build status until RUNNING or ERROR
# ============================================================
set -e
# ---- Load credentials from .env.local ----
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$ROOT_DIR/.env.local"
if [ ! -f "$ENV_FILE" ]; then
echo "[deploy] ERROR: .env.local not found at $ROOT_DIR/.env.local"
echo "[deploy] Create it with: HF_TOKEN=hf_..."
exit 1
fi
source "$ENV_FILE"
if [ -z "$HF_TOKEN" ]; then
echo "[deploy] ERROR: HF_TOKEN is not set in .env.local"
exit 1
fi
HF_USERNAME="${HF_USERNAME:-lulavc}"
HF_SPACE="${HF_SPACE:-HF-SaaS}"
FACTORY_RESET=false
# ---- Parse flags ----
for arg in "$@"; do
case $arg in
--factory) FACTORY_RESET=true ;;
esac
done
echo ""
echo "============================================"
echo " HF-VPS Clean Deployment"
echo " Space: $HF_USERNAME/$HF_SPACE"
if [ "$FACTORY_RESET" = true ]; then
echo " Mode: Factory Reset (full Docker rebuild)"
else
echo " Mode: Standard (incremental Docker rebuild)"
fi
echo "============================================"
echo ""
# ---- Step 1: Validate git state ----
cd "$ROOT_DIR"
BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [ "$BRANCH" != "main" ]; then
echo "[deploy] ERROR: Not on main branch (currently on: $BRANCH)"
echo "[deploy] Switch to main before deploying."
exit 1
fi
if ! git diff-index --quiet HEAD --; then
echo "[deploy] ERROR: Uncommitted changes detected."
echo "[deploy] Commit all changes before deploying."
git status --short
exit 1
fi
echo "[deploy] Git state OK β€” branch: main, working tree clean"
# ---- Step 2: Push to GitHub (source of truth) ----
echo "[deploy] Pushing to GitHub (origin/main)..."
git push origin main
echo "[deploy] GitHub updated βœ“"
# ---- Step 3: Force-push to HF Space (clean git state) ----
echo "[deploy] Force-pushing to HF Space (no stale refs or old files)..."
git push hf main --force
echo "[deploy] HF Space git updated βœ“"
# ---- Step 4: Factory reset (optional β€” busts Docker cache) ----
if [ "$FACTORY_RESET" = true ]; then
echo "[deploy] Triggering factory restart (clean Docker rebuild, no cache)..."
RESTART_RESP=$(curl -s -X POST \
"https://huggingface.co/api/spaces/$HF_USERNAME/$HF_SPACE/restart?factory=true" \
-H "Authorization: Bearer $HF_TOKEN")
echo "[deploy] Factory restart triggered: $RESTART_RESP"
fi
# ---- Step 5: Monitor build status ----
echo ""
echo "[deploy] Monitoring build status..."
echo "[deploy] Logs: https://huggingface.co/spaces/$HF_USERNAME/$HF_SPACE?logs=container"
echo ""
MAX_WAIT=300 # 5 minutes max
INTERVAL=10
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
STAGE=$(curl -s \
"https://huggingface.co/api/spaces/$HF_USERNAME/$HF_SPACE" \
-H "Authorization: Bearer $HF_TOKEN" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('runtime',{}).get('stage','unknown'))" 2>/dev/null)
ERROR=$(curl -s \
"https://huggingface.co/api/spaces/$HF_USERNAME/$HF_SPACE" \
-H "Authorization: Bearer $HF_TOKEN" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('runtime',{}).get('errorMessage',''))" 2>/dev/null)
printf "[deploy] [%3ds] Stage: %s\n" "$ELAPSED" "$STAGE"
if [ "$STAGE" = "RUNNING" ]; then
echo ""
echo "============================================"
echo " Deployment successful!"
echo " Space: https://huggingface.co/spaces/$HF_USERNAME/$HF_SPACE"
echo " App: https://$HF_USERNAME-$(echo $HF_SPACE | tr '[:upper:]' '[:lower:]').hf.space"
echo "============================================"
exit 0
fi
if [ "$STAGE" = "ERROR" ] || [ "$STAGE" = "BUILD_ERROR" ]; then
echo ""
echo "[deploy] ERROR: Build failed!"
echo "[deploy] Error: $ERROR"
echo "[deploy] Check logs: https://huggingface.co/spaces/$HF_USERNAME/$HF_SPACE?logs=container"
exit 1
fi
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "[deploy] Timed out after ${MAX_WAIT}s β€” check logs manually:"
echo "[deploy] https://huggingface.co/spaces/$HF_USERNAME/$HF_SPACE?logs=container"
exit 1