Deploy to GitHub Pages #91
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to GitHub Pages | |
| on: | |
| push: | |
| branches: ["main"] | |
| paths: | |
| - "src/**" | |
| - ".github/workflows/deploy.yml" | |
| - "package.json" | |
| workflow_dispatch: | |
| workflow_run: | |
| workflows: ["Run Pipelines", "Generate Summaries"] | |
| branches: [main] | |
| types: [completed] | |
| permissions: | |
| contents: write | |
| pages: write | |
| id-token: write | |
| # Allow one concurrent deployment | |
| concurrency: | |
| group: "pages" | |
| cancel-in-progress: true | |
| env: | |
| DATA_DIR: "data" | |
| PIPELINE_DATA_BRANCH: "_data" | |
| # ============================================================================= | |
| # FORK CONFIGURATION | |
| # ============================================================================= | |
| # Config is loaded from JSON file. Priority: PIPELINE_CONFIG_FILE → config/config.json | |
| # | |
| # For forks, you have 2 options: | |
| # 1. Create config/config.json (copy from config.example.json) - keeps this file unchanged | |
| # 2. Create your own named config (e.g., config/myorg.json) and update PIPELINE_CONFIG_FILE below | |
| # | |
| # Either option = zero merge conflicts when syncing with upstream | |
| # ============================================================================= | |
| PIPELINE_CONFIG_FILE: ${{ secrets.PIPELINE_CONFIG_FILE || 'config/example.json' }} | |
| jobs: | |
| build-and-deploy: | |
| if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout main branch | |
| uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| # Set up pipeline-data branch and restore data | |
| - name: Setup pipeline-data branch | |
| uses: ./.github/actions/pipeline-data | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| operation: setup | |
| branch_name: ${{ env.PIPELINE_DATA_BRANCH }} | |
| data_dir: ${{ env.DATA_DIR }} | |
| # Restore database from dump | |
| - name: Restore database | |
| uses: ./.github/actions/restore-db | |
| with: | |
| operation: restore | |
| dump_dir: ${{ env.DATA_DIR }}/dump | |
| db_path: ${{ env.DATA_DIR }}/db.sqlite | |
| - name: Copy yesterday's stats for all tracked repositories | |
| run: | | |
| YESTERDAY=$(date -d "yesterday" +'%Y-%m-%d') | |
| shopt -s nullglob | |
| for file in data/*/stats/day/stats_${YESTERDAY}.json; do | |
| cp "$file" "${file%_*}.json" | |
| echo "Copied: $(basename $(dirname $(dirname $(dirname "$file"))))" | |
| done | |
| # Generate static JSON leaderboard API endpoints | |
| - name: Export Leaderboard API | |
| run: bun run pipeline export-leaderboard --output-dir=${{ env.DATA_DIR }} | |
| - name: Generate Directory Listings | |
| uses: jayanta525/github-pages-directory-listing@v4.0.0 | |
| with: | |
| FOLDER: data | |
| # Auto-detect site URL based on repo type: | |
| # - Org/user sites (*.github.io): https://{owner}.github.io | |
| # - Project sites: https://{owner}.github.io/{repo} | |
| - name: Determine site URL and base path | |
| id: site-config | |
| run: | | |
| REPO_NAME="${{ github.event.repository.name }}" | |
| OWNER="${{ github.repository_owner }}" | |
| CONFIG_FILE="${{ env.PIPELINE_CONFIG_FILE }}" | |
| # Auto-detect base path and site URL | |
| if [[ "$REPO_NAME" == *.github.io ]]; then | |
| echo "site_url=https://${OWNER}.github.io" >> $GITHUB_OUTPUT | |
| echo "base_path=" >> $GITHUB_OUTPUT | |
| else | |
| echo "site_url=https://${OWNER}.github.io/${REPO_NAME}" >> $GITHUB_OUTPUT | |
| echo "base_path=/${REPO_NAME}" >> $GITHUB_OUTPUT | |
| fi | |
| # Read SITE_NAME from config file if it exists | |
| if [[ -f "$CONFIG_FILE" ]]; then | |
| SITE_NAME=$(jq -r '.SITE_NAME // empty' "$CONFIG_FILE") | |
| if [[ -n "$SITE_NAME" ]]; then | |
| echo "site_name=$SITE_NAME" >> $GITHUB_OUTPUT | |
| fi | |
| fi | |
| - name: Build Next.js app | |
| run: bun run build | |
| env: | |
| NEXT_TELEMETRY_DISABLED: 1 | |
| CI: true | |
| BASE_PATH: ${{ secrets.BASE_PATH || steps.site-config.outputs.base_path }} | |
| NEXT_PUBLIC_BASE_PATH: ${{ secrets.BASE_PATH || steps.site-config.outputs.base_path }} | |
| SITE_URL: ${{ secrets.SITE_URL || steps.site-config.outputs.site_url }} | |
| SITE_NAME: ${{ secrets.SITE_NAME || steps.site-config.outputs.site_name || github.repository_owner }} | |
| NEXT_PUBLIC_SITE_NAME: ${{ secrets.SITE_NAME || steps.site-config.outputs.site_name || github.repository_owner }} | |
| NEXT_PUBLIC_GITHUB_REPO: ${{ github.repository }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| NEXT_PUBLIC_GITHUB_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_GITHUB_CLIENT_ID }} | |
| NEXT_PUBLIC_AUTH_WORKER_URL: ${{ secrets.NEXT_PUBLIC_AUTH_WORKER_URL }} | |
| - name: Move data directory into out folder | |
| run: | | |
| cp -r data out/ | |
| cp -r out/data/api out/api | |
| - name: Create .nojekyll file | |
| run: touch out/.nojekyll | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v5 | |
| - name: Upload artifact | |
| uses: actions/upload-pages-artifact@v4 | |
| with: | |
| path: out | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| # Cleanup worktree (always runs) | |
| - name: Cleanup | |
| if: always() | |
| uses: ./.github/actions/pipeline-data | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| operation: cleanup | |
| branch_name: ${{ env.PIPELINE_DATA_BRANCH }} | |
| data_dir: ${{ env.DATA_DIR }} |