Spaces:
Runtime error
Runtime error
| name: HF β GitHub Sync | |
| # Trigger on every push to main (GitHub β HF direction) | |
| # and hourly to pull any HF-side changes back (HF β GitHub direction) | |
| on: | |
| push: | |
| branches: [main] | |
| schedule: | |
| - cron: '0 * * * *' # hourly HF pull-check | |
| workflow_dispatch: | |
| inputs: | |
| force_direction: | |
| description: 'Force sync direction (hf-wins | gh-wins | auto)' | |
| required: false | |
| default: 'auto' | |
| env: | |
| HF_REPO_TYPE: space # model | dataset | space | |
| HF_REPO: ${{ vars.HF_REPO }} # e.g. your-org/codecraftlab | |
| jobs: | |
| sync: | |
| name: Sync HuggingFace β GitHub | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout (full history) | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Configure git identity | |
| run: | | |
| git config user.email "sync-bot@codecraftlab.noreply" | |
| git config user.name "CodeCraftLab Sync Bot" | |
| - name: Install git-lfs | |
| run: | | |
| sudo apt-get install -y git-lfs | |
| git lfs install | |
| - name: Add HuggingFace remote | |
| run: | | |
| git remote add hf \ | |
| "https://user:${{ secrets.HF_TOKEN }}@huggingface.co/${HF_REPO_TYPE}s/${HF_REPO}" | |
| git fetch hf --prune | |
| - name: Detect divergence and resolve | |
| id: sync | |
| env: | |
| FORCE_DIRECTION: ${{ github.event.inputs.force_direction || 'auto' }} | |
| run: | | |
| set -euo pipefail | |
| HF_HEAD=$(git rev-parse hf/main 2>/dev/null || echo "NONE") | |
| GH_HEAD=$(git rev-parse HEAD) | |
| if [ "$HF_HEAD" = "NONE" ]; then | |
| echo "action=push-to-hf" >> "$GITHUB_OUTPUT" | |
| echo "reason=HF remote has no main branch β initial push" | |
| exit 0 | |
| fi | |
| BASE=$(git merge-base HEAD hf/main 2>/dev/null || echo "NONE") | |
| if [ "$FORCE_DIRECTION" = "hf-wins" ]; then | |
| echo "action=hf-wins" >> "$GITHUB_OUTPUT" | |
| echo "reason=Forced HF-wins override" | |
| elif [ "$FORCE_DIRECTION" = "gh-wins" ]; then | |
| echo "action=push-to-hf" >> "$GITHUB_OUTPUT" | |
| echo "reason=Forced GH-wins override" | |
| elif [ "$HF_HEAD" = "$GH_HEAD" ]; then | |
| echo "action=in-sync" >> "$GITHUB_OUTPUT" | |
| echo "reason=Already in sync" | |
| elif [ "$BASE" = "$GH_HEAD" ]; then | |
| # HF is ahead β pull HF β GitHub | |
| echo "action=hf-wins" >> "$GITHUB_OUTPUT" | |
| echo "reason=GitHub is behind HF β fast-forward" | |
| elif [ "$BASE" = "$HF_HEAD" ]; then | |
| # GitHub is ahead β push GitHub β HF | |
| echo "action=push-to-hf" >> "$GITHUB_OUTPUT" | |
| echo "reason=HF is behind GitHub β pushing" | |
| else | |
| # Both diverged β HF is source of truth | |
| echo "action=hf-wins" >> "$GITHUB_OUTPUT" | |
| echo "reason=CONFLICT: both diverged β HF wins (source of truth)" | |
| fi | |
| - name: "[In-sync] Nothing to do" | |
| if: steps.sync.outputs.action == 'in-sync' | |
| run: echo "β HF and GitHub are in sync β no action required." | |
| - name: "[Push] GitHub β HuggingFace" | |
| if: steps.sync.outputs.action == 'push-to-hf' | |
| run: | | |
| echo "π€ Pushing GitHub β HuggingFace" | |
| git push hf main | |
| - name: "[HF Wins] HuggingFace β GitHub" | |
| if: steps.sync.outputs.action == 'hf-wins' | |
| run: | | |
| echo "π₯ HuggingFace wins β overwriting GitHub main" | |
| git reset --hard hf/main | |
| git push origin main --force-with-lease || git push origin main --force | |
| - name: Summary | |
| if: always() | |
| run: | | |
| echo "### Sync Result" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **Action:** ${{ steps.sync.outputs.action }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **Trigger:** ${{ github.event_name }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **Branch:** main" >> "$GITHUB_STEP_SUMMARY" | |
| # ------------------------------------------------------------------ | |
| # Validate HF Space config on every push | |
| # ------------------------------------------------------------------ | |
| validate-space-config: | |
| name: Validate HF Space README config | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Check README frontmatter | |
| run: | | |
| python3 - <<'EOF' | |
| import re, sys | |
| with open("README.md") as f: | |
| content = f.read() | |
| match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL) | |
| if not match: | |
| print("β README is missing HF Space YAML frontmatter") | |
| sys.exit(1) | |
| frontmatter = match.group(1) | |
| required_keys = ["title", "sdk", "app_port", "license"] | |
| missing = [k for k in required_keys if k + ":" not in frontmatter] | |
| if missing: | |
| print(f"β Missing frontmatter keys: {missing}") | |
| sys.exit(1) | |
| if "sdk: streamlit" in frontmatter: | |
| print("β sdk is still 'streamlit' β should be 'docker' for FastAPI") | |
| sys.exit(1) | |
| print("β HF Space frontmatter is valid") | |
| EOF | |