Spaces:
Sleeping
Sleeping
| name: Deploy to HuggingFace Space | |
| # Redeploys the HuggingFace Docker Space on every merge to main (a merged | |
| # PR pushes to main). Mirrors the manual flow in deploy/huggingface/SETUP.md: | |
| # HF's git endpoint rejects the >10 MiB .xiidm blobs that sit in branch | |
| # *history*, so we push ONE squashed, history-free commit of the current | |
| # tree (large binaries ride along via Git LFS). | |
| # | |
| # Required repo configuration (Settings → Secrets and variables → Actions): | |
| # - secret HF_TOKEN : a HuggingFace WRITE access token with access to the Space | |
| # - variable HF_SPACE : the Space path, e.g. "your-user/co-study4grid-game" | |
| # - variable HF_USERNAME : (optional) the token owner's HF username — only | |
| # needed when the Space lives under an ORG and so | |
| # differs from the owner part of HF_SPACE. | |
| # | |
| # The job no-ops (does not fail) when HF_TOKEN / HF_SPACE are absent, so the | |
| # workflow is inert until you opt in by setting them. | |
| # Test-gated (D7): deploy runs ONLY after the "Tests" workflow completes | |
| # successfully on main — a green build is the gate, not just a merge. A | |
| # manual `workflow_dispatch` (optionally from an older commit) is the | |
| # rollback path; see deploy/huggingface/SETUP.md → "Rolling back". | |
| on: | |
| workflow_run: | |
| workflows: [ "Tests" ] | |
| types: [ completed ] | |
| branches: [ main ] | |
| workflow_dispatch: {} | |
| # Never run two deploys at once; the latest merge wins. | |
| concurrency: | |
| group: huggingface-space-deploy | |
| cancel-in-progress: true | |
| permissions: | |
| contents: write # push the per-deploy rollback tag back to origin | |
| jobs: | |
| deploy: | |
| name: Push snapshot to HF Space | |
| runs-on: ubuntu-latest | |
| # workflow_run fires on completion regardless of result — only deploy a | |
| # SUCCESSFUL Tests run. workflow_dispatch always proceeds (rollback). | |
| if: >- | |
| github.event_name == 'workflow_dispatch' || | |
| github.event.workflow_run.conclusion == 'success' | |
| steps: | |
| - name: Check the deploy is configured | |
| id: guard | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| HF_SPACE: ${{ vars.HF_SPACE }} | |
| run: | | |
| if [ -z "$HF_TOKEN" ] || [ -z "$HF_SPACE" ]; then | |
| echo "::notice::HF_TOKEN secret and/or HF_SPACE variable not set — skipping deploy." | |
| echo "configured=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "configured=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| # The tested commit: the head of the Tests run (workflow_run), or the | |
| # dispatched ref (workflow_dispatch / rollback). | |
| - name: Resolve the deployed commit | |
| if: steps.guard.outputs.configured == 'true' | |
| id: sha | |
| run: echo "sha=${{ github.event.workflow_run.head_sha || github.sha }}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout the tested tree + LFS objects | |
| if: steps.guard.outputs.configured == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.sha.outputs.sha }} | |
| lfs: true | |
| fetch-depth: 1 # an orphan snapshot only needs the current tree | |
| - name: Configure git + LFS | |
| if: steps.guard.outputs.configured == 'true' | |
| run: | | |
| git lfs install --local | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Build a history-free snapshot | |
| if: steps.guard.outputs.configured == 'true' | |
| env: | |
| DEPLOY_SHA: ${{ steps.sha.outputs.sha }} | |
| run: | | |
| cp deploy/huggingface/README.md README.md # HF needs the frontmatter at repo root | |
| git checkout --orphan hf-deploy | |
| git add -A | |
| # Drop inert local dev artifacts from the deployed snapshot. | |
| git rm -q --cached --ignore-unmatch \ | |
| .claude/plan.md profiling_patch_results.json || true | |
| git commit -q -m "Deploy ${DEPLOY_SHA::7}" | |
| test "$(git rev-list --count HEAD)" -eq 1 # sanity: exactly one commit | |
| - name: Push to the HuggingFace Space | |
| if: steps.guard.outputs.configured == 'true' | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| HF_SPACE: ${{ vars.HF_SPACE }} | |
| HF_USERNAME: ${{ vars.HF_USERNAME }} | |
| DEPLOY_SHA: ${{ steps.sha.outputs.sha }} | |
| run: | | |
| user="${HF_USERNAME:-${HF_SPACE%%/*}}" | |
| # The token is a GitHub secret → masked in logs even inside the URL. | |
| git remote add space "https://${user}:${HF_TOKEN}@huggingface.co/spaces/${HF_SPACE}" | |
| git -c protocol.version=0 push -f space hf-deploy:main | |
| echo "::notice::Pushed snapshot of ${DEPLOY_SHA::7} to spaces/${HF_SPACE}; HF will rebuild." | |
| # Rollback pointer (D7): tag the exact commit deployed to the Space, | |
| # so a bad deploy can be reverted by re-dispatching this workflow from | |
| # a prior `space-deploy-*` tag. The Space push itself is force-pushed | |
| # and history-free, so this origin tag is the only durable record of | |
| # what shipped. Never fails the deploy. | |
| - name: Tag the deployed commit on origin | |
| if: steps.guard.outputs.configured == 'true' | |
| env: | |
| DEPLOY_SHA: ${{ steps.sha.outputs.sha }} | |
| run: | | |
| tag="space-deploy-$(date -u +%Y%m%d-%H%M%S)-${DEPLOY_SHA::7}" | |
| git tag -a "$tag" "$DEPLOY_SHA" -m "Deployed to HF Space" || { echo "::warning::tag create failed"; exit 0; } | |
| git push origin "refs/tags/$tag" || echo "::warning::tag push failed (non-fatal)" | |
| echo "::notice::Tagged deployed commit as $tag" | |