#!/usr/bin/env bash # # Deploy Smartfolio-backend to its Hugging Face Space. # # Runs in a throwaway git WORKTREE, and that is the whole point of the script. # # The obvious version of this — checking out a deploy branch in the main # working tree — quietly destroys the local database. The Space's history has # no campaigns or verification modules, so for the few seconds the deploy # branch is checked out those entity files do not exist; the `nest start # --watch` dev server notices, restarts, and TypeORM's `synchronize: true` # DROPS every column whose entity it can no longer see. Roles, availability and # suspension reasons all disappear, silently, and the first sign of it is a # "column does not exist" error some minutes later. That happened twice before # this script existed. # # A worktree keeps the deploy in its own directory, so the files the dev server # watches are never touched. # # Usage: scripts/deploy-hf.sh "deploy: what changed" set -euo pipefail MESSAGE="${1:?usage: scripts/deploy-hf.sh \"commit message\"}" REPO_ROOT="$(git rev-parse --show-toplevel)" BRANCH="hf-deploy-$(date +%s)" WORKTREE="$(mktemp -d)/hf-deploy" SOURCE_REF="$(git rev-parse HEAD)" cleanup() { cd "$REPO_ROOT" git worktree remove --force "$WORKTREE" 2>/dev/null || true git branch -D "$BRANCH" 2>/dev/null || true rm -rf "$(dirname "$WORKTREE")" } trap cleanup EXIT cd "$REPO_ROOT" git fetch hf # Build the deploy on top of the Space's own history: GitHub main and hf/main # have permanently diverged and neither can be pushed onto the other. git worktree add -q -b "$BRANCH" "$WORKTREE" hf/main cd "$WORKTREE" # Overlay the code being deployed, then put back the two things that belong to # the Space rather than to us. git checkout "$SOURCE_REF" -- . # The Space README carries required YAML frontmatter (sdk: docker, # app_port: 7860). Overwriting it breaks the Space. git checkout hf/main -- README.md # HF's pre-receive hook rejects any push whose commits add binary files, and # GitHub main carries screenshots. rm -rf "screenshots for readme" git add -A # Refuse rather than get rejected halfway: a binary in the diff means the push # will fail after uploading everything else. if git diff --cached --numstat | awk '$1=="-"' | grep -q .; then echo "Refusing to deploy: binary files are staged and HF will reject them." >&2 git diff --cached --numstat | awk '$1=="-" {print " " $3}' >&2 exit 1 fi if git diff --cached --quiet; then echo "Nothing to deploy — the Space already matches this commit." exit 0 fi git commit -q -m "$MESSAGE" git push hf "$BRANCH:main" echo echo "Pushed. Watch the build:" echo " curl -s https://huggingface.co/api/spaces/mahrooshishaq/SmartfolioBackend \\" echo " | python3 -c \"import sys,json;print(json.load(sys.stdin)['runtime']['stage'])\"" echo echo "RUNNING_BUILDING -> RUNNING_APP_STARTING -> RUNNING"