Auto-commit: 2025-12-03 19:50:08 #87
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: Cloudflare Conditional Deploy | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| branches: | |
| - gh-pages | |
| push: | |
| branches: | |
| - gh-pages | |
| - 'feature/auto-*' | |
| jobs: | |
| detect-and-deploy: | |
| name: Detect changes and deploy only touched apps | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| deployments: write | |
| pull-requests: write | |
| concurrency: | |
| group: cf-pages-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # --- Change Detection Step --- | |
| - name: Determine changed files | |
| id: changes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Determining changed files..." | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" | |
| git fetch origin "${{ github.event.pull_request.base.ref }}" --depth=1 || true | |
| MERGE_BASE=$(git merge-base "$BASE_SHA" HEAD) | |
| DIFF=$(git diff --name-only "$MERGE_BASE"...HEAD) || true | |
| else | |
| BEFORE="${{ github.event.before }}" | |
| AFTER="${{ github.sha }}" | |
| if [[ "$BEFORE" =~ ^0+$ ]]; then | |
| DIFF=$(git ls-files) || true | |
| else | |
| DIFF=$(git diff --name-only "$BEFORE" "$AFTER") || true | |
| fi | |
| fi | |
| echo "Changed files:" | |
| echo "$DIFF" | |
| { | |
| echo "library=false"; echo "hbnb=false"; echo "forces=false" | |
| echo "gui=false"; echo "datro=false"; echo "projections=false" | |
| echo "bpvsbuckler=false" | |
| } >> "$GITHUB_OUTPUT" | |
| if echo "$DIFF" | grep -qE '^static/library/'; then echo "library=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/hbnb/'; then echo "hbnb=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/forces/'; then echo "forces=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/gui/'; then echo "gui=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/datro/'; then echo "datro=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/projections/'; then echo "projections=true" >> "$GITHUB_OUTPUT"; fi | |
| if echo "$DIFF" | grep -qE '^static/bpvsbuckler/'; then echo "bpvsbuckler=true" >> "$GITHUB_OUTPUT"; fi | |
| # --- Setup Node (only run if HBNB needs it) --- | |
| - name: Setup Node (for builds) | |
| if: steps.changes.outputs.hbnb == 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| ###################################################################### | |
| # PREVIEW DEPLOYS FOR PRS | |
| ###################################################################### | |
| # --- Library (Static HTML) --- | |
| - name: Deploy library (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.library == 'true' | |
| id: deploy_library | |
| run: | | |
| npx wrangler pages deploy static/library \ | |
| --project-name=library \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.library[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- HBNB (Built App - React) --- | |
| - name: Build hbnb | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.hbnb == 'true' | |
| run: | | |
| cd static/hbnb | |
| npm ci | |
| npm run build | |
| - name: Deploy hbnb (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.hbnb == 'true' | |
| id: deploy_hbnb | |
| run: | | |
| npx wrangler pages deploy static/hbnb/build \ | |
| --project-name=hbnb \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.hbnb[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- Forces/CEO (Static HTML) --- | |
| - name: Deploy forces/ceo (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.forces == 'true' | |
| id: deploy_forces | |
| run: | | |
| npx wrangler pages deploy static/forces \ | |
| --project-name=ceo \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.ceo[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- GUI (Static HTML) --- | |
| - name: Deploy gui (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.gui == 'true' | |
| id: deploy_gui | |
| run: | | |
| npx wrangler pages deploy static/gui \ | |
| --project-name=gui \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.gui[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- DATRO-HOMEPAGE (Static HTML) --- | |
| - name: Deploy datro-homepage (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.datro == 'true' | |
| id: deploy_datro | |
| run: | | |
| npx wrangler pages deploy static/datro \ | |
| --project-name=datro-homepage \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.datro-homepage[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- Projections (Static HTML) --- | |
| - name: Deploy projections (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.projections == 'true' | |
| id: deploy_projections | |
| run: | | |
| npx wrangler pages deploy static/projections \ | |
| --project-name=projections \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.projections[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- BPVSBuckler (Static HTML) --- | |
| - name: Deploy bpvsbuckler (Preview) | |
| if: github.event_name == 'pull_request' && steps.changes.outputs.bpvsbuckler == 'true' | |
| id: deploy_bpvsbuckler | |
| run: | | |
| npx wrangler pages deploy static/bpvsbuckler \ | |
| --project-name=bpvsbuckler \ | |
| --branch="${{ github.head_ref }}" \ | |
| --commit-hash="${{ github.sha }}" \ | |
| > deploy_output.txt 2>&1 | |
| PREVIEW_URL=$(grep -oP 'https://[a-f0-9]+\.bpvsbuckler[^\s]*' deploy_output.txt | head -1) | |
| echo "url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| echo "✅ Deployed to $PREVIEW_URL" | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # --- FINAL TABLE COMMENT --- | |
| - name: Post Clean Preview Table | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const apps = [ | |
| { name: 'library', changed: '${{ steps.changes.outputs.library }}', url: '${{ steps.deploy_library.outputs.url }}' }, | |
| { name: 'hbnb', changed: '${{ steps.changes.outputs.hbnb }}', url: '${{ steps.deploy_hbnb.outputs.url }}' }, | |
| { name: 'ceo (forces)', changed: '${{ steps.changes.outputs.forces }}', url: '${{ steps.deploy_forces.outputs.url }}' }, | |
| { name: 'gui', changed: '${{ steps.changes.outputs.gui }}', url: '${{ steps.deploy_gui.outputs.url }}' }, | |
| { name: 'datro-homepage', changed: '${{ steps.changes.outputs.datro }}', url: '${{ steps.deploy_datro.outputs.url }}' }, | |
| { name: 'projections', changed: '${{ steps.changes.outputs.projections }}', url: '${{ steps.deploy_projections.outputs.url }}' }, | |
| { name: 'bpvsbuckler', changed: '${{ steps.changes.outputs.bpvsbuckler }}', url: '${{ steps.deploy_bpvsbuckler.outputs.url }}' }, | |
| ]; | |
| let body = '## 🚀 Cloudflare Pages Preview Deployments\n\n'; | |
| body += '| Application | Status | Preview URL |\n'; | |
| body += '| :--- | :--- | :--- |\n'; | |
| let deployed = 0; | |
| for (const app of apps) { | |
| let status, link; | |
| if (app.url && app.url !== '' && app.url !== 'null') { | |
| status = '✅ Deployed'; | |
| link = `[Preview](${app.url})`; | |
| deployed++; | |
| } else if (app.changed === 'true') { | |
| status = '⚠️ Deploy attempted'; | |
| link = 'Check logs'; | |
| } else { | |
| status = '🚫 Skipped'; | |
| link = 'N/A'; | |
| } | |
| body += `| ${app.name} | ${status} | ${link} |\n`; | |
| } | |
| body += `\n**Total Deployed:** ${deployed} application(s)`; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const botComment = comments.find(c => | |
| c.user.type === 'Bot' && | |
| c.body.includes('🚀 Cloudflare Pages Preview Deployments') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| comment_id: botComment.id, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body | |
| }); | |
| } | |