name: CI & Deploy on: push: branches: [main] pull_request: branches: [main] workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: PYTHON_VERSION: "3.12" NODE_VERSION: "20" jobs: # ────────────────────────────────────────────── # Backend: test # ────────────────────────────────────────────── backend: name: Backend CI runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache uv uses: actions/cache@v4 with: path: | ~/.local/share/uv ~/.cache/uv key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('backend/pyproject.toml', 'pyproject.toml') }} restore-keys: | uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}- - name: Install backend dependencies run: | export PATH="$HOME/.local/bin:$PATH" uv venv .venv source .venv/bin/activate uv pip install -e "./backend[dev]" uv pip install pytest httpx - name: Run backend tests run: | export PATH="$HOME/.local/bin:$PATH" source .venv/bin/activate cd backend python -m pytest visual_notebook/tests/ -v --tb=short # ────────────────────────────────────────────── # Frontend: build # ────────────────────────────────────────────── frontend: name: Frontend CI runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: npm cache-dependency-path: frontend/package-lock.json - name: Install & Build working-directory: frontend run: npm ci && npm run build # ────────────────────────────────────────────── # Deploy to Hugging Face Spaces # ────────────────────────────────────────────── deploy: name: Deploy to HF Spaces needs: [backend, frontend] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to HF Container Registry uses: docker/login-action@v3 with: registry: registry.hf.space username: ${{ secrets.HF_USERNAME }} password: ${{ secrets.HF_TOKEN }} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile push: true tags: | registry.hf.space/${{ secrets.HF_SPACE_ID }}:latest registry.hf.space/${{ secrets.HF_SPACE_ID }}:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max - name: Restart HF Space run: | curl -s -f -X POST \ "https://huggingface.co/api/spaces/${{ secrets.HF_SPACE_ID }}/restart" \ -H "Authorization: Bearer ${{ secrets.HF_TOKEN }}" \ -H "Content-Type: application/json" \ || echo "Restart request failed — image push should still trigger rebuild."