From ce42058b0c897de57d945c6c9c5e1f2f861e450d Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:06:05 +0100 Subject: [PATCH 01/19] feat(ci): add GitHub Actions workflow for deploying CMS and Web applications to Vercel --- .github/workflows/deploy.yml | 132 +++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..9cf0a8d --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,132 @@ +name: Deploy + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + deploy_cms: + description: 'Deploy CMS' + required: false + default: true + type: boolean + deploy_web: + description: 'Deploy Web' + required: false + default: true + type: boolean + +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + +jobs: + deploy-cms: + name: Deploy CMS + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' || github.event.inputs.deploy_cms == 'true' }} + outputs: + deployment_url: ${{ steps.deploy.outputs.deployment_url }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment + run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ./cms + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} + + - name: Build Project + run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ./cms + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} + + - name: Deploy to Vercel + id: deploy + run: | + DEPLOYMENT_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "CMS deployed to: $DEPLOYMENT_URL" + working-directory: ./cms + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} + + - name: Wait for CMS to be ready + run: | + echo "Waiting for CMS deployment to be ready..." + sleep 30 + # Verify the deployment is accessible + for i in {1..10}; do + if curl -s -o /dev/null -w "%{http_code}" "${{ steps.deploy.outputs.deployment_url }}/admin" | grep -q "200\|301\|302"; then + echo "CMS is ready!" + exit 0 + fi + echo "Attempt $i: CMS not ready yet, waiting..." + sleep 10 + done + echo "Warning: Could not verify CMS readiness, proceeding anyway" + + deploy-web: + name: Deploy Web + runs-on: ubuntu-latest + needs: deploy-cms + if: ${{ always() && (github.event_name == 'push' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Install dependencies + run: pnpm install + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment + run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ./web + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} + + - name: Build Project + run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ./web + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} + CMS_URL: ${{ secrets.CMS_URL }} + + - name: Deploy to Vercel + id: deploy + run: | + DEPLOYMENT_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "Web deployed to: $DEPLOYMENT_URL" + working-directory: ./web + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} + + - name: Deployment Summary + run: | + echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **CMS**: ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }}" >> $GITHUB_STEP_SUMMARY + echo "- **Web**: ${{ steps.deploy.outputs.deployment_url }}" >> $GITHUB_STEP_SUMMARY From 0d006a7089532fc0db57f199e55a2606fb7d415e Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:07:37 +0100 Subject: [PATCH 02/19] fix(ci): use Vercel remote build instead of local build --- .github/workflows/deploy.yml | 42 ++++++------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9cf0a8d..69ef181 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -39,33 +39,22 @@ jobs: - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Pull Vercel Environment - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + - name: Link Vercel Project + run: vercel link --yes --project=${{ secrets.VERCEL_CMS_PROJECT_ID }} --token=${{ secrets.VERCEL_TOKEN }} working-directory: ./cms - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - - - name: Build Project - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - working-directory: ./cms - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - name: Deploy to Vercel id: deploy run: | - DEPLOYMENT_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "CMS deployed to: $DEPLOYMENT_URL" working-directory: ./cms - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - name: Wait for CMS to be ready run: | echo "Waiting for CMS deployment to be ready..." sleep 30 - # Verify the deployment is accessible for i in {1..10}; do if curl -s -o /dev/null -w "%{http_code}" "${{ steps.deploy.outputs.deployment_url }}/admin" | grep -q "200\|301\|302"; then echo "CMS is ready!" @@ -90,39 +79,20 @@ jobs: with: node-version: 22 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9 - - - name: Install dependencies - run: pnpm install - - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Pull Vercel Environment - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - working-directory: ./web - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - - - name: Build Project - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} + - name: Link Vercel Project + run: vercel link --yes --project=${{ secrets.VERCEL_WEB_PROJECT_ID }} --token=${{ secrets.VERCEL_TOKEN }} working-directory: ./web - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - CMS_URL: ${{ secrets.CMS_URL }} - name: Deploy to Vercel id: deploy run: | - DEPLOYMENT_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "Web deployed to: $DEPLOYMENT_URL" working-directory: ./web - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - name: Deployment Summary run: | From bf43b0410aa37dc5bf2f58646c7257fd94319737 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:08:52 +0100 Subject: [PATCH 03/19] fix(ci): set VERCEL_PROJECT_ID as env variable --- .github/workflows/deploy.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 69ef181..d2e58c7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -39,17 +39,15 @@ jobs: - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Link Vercel Project - run: vercel link --yes --project=${{ secrets.VERCEL_CMS_PROJECT_ID }} --token=${{ secrets.VERCEL_TOKEN }} - working-directory: ./cms - - name: Deploy to Vercel id: deploy run: | - DEPLOYMENT_URL=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "CMS deployed to: $DEPLOYMENT_URL" working-directory: ./cms + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - name: Wait for CMS to be ready run: | @@ -82,17 +80,15 @@ jobs: - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Link Vercel Project - run: vercel link --yes --project=${{ secrets.VERCEL_WEB_PROJECT_ID }} --token=${{ secrets.VERCEL_TOKEN }} - working-directory: ./web - - name: Deploy to Vercel id: deploy run: | - DEPLOYMENT_URL=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "Web deployed to: $DEPLOYMENT_URL" working-directory: ./web + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - name: Deployment Summary run: | From 0675d24af2c1b6724b5a3084e77e027acacc26dd Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:10:12 +0100 Subject: [PATCH 04/19] fix(ci): remove working-directory, use Vercel project root settings --- .github/workflows/deploy.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d2e58c7..424c4b8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -45,7 +45,6 @@ jobs: DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "CMS deployed to: $DEPLOYMENT_URL" - working-directory: ./cms env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -86,7 +85,6 @@ jobs: DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "Web deployed to: $DEPLOYMENT_URL" - working-directory: ./web env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} From 6b09e438e220b6776a67db595e599eb04d1879e8 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:18:14 +0100 Subject: [PATCH 05/19] refactor(ci): remove unnecessary ready check step --- .github/workflows/deploy.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 424c4b8..435f945 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -48,19 +48,6 @@ jobs: env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - - name: Wait for CMS to be ready - run: | - echo "Waiting for CMS deployment to be ready..." - sleep 30 - for i in {1..10}; do - if curl -s -o /dev/null -w "%{http_code}" "${{ steps.deploy.outputs.deployment_url }}/admin" | grep -q "200\|301\|302"; then - echo "CMS is ready!" - exit 0 - fi - echo "Attempt $i: CMS not ready yet, waiting..." - sleep 10 - done - echo "Warning: Could not verify CMS readiness, proceeding anyway" deploy-web: name: Deploy Web From 4528bf478e6bdc48ca45167d5bc3b7970611d11e Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:19:01 +0100 Subject: [PATCH 06/19] docs(ci): add description to deploy workflow --- .github/workflows/deploy.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 435f945..a0c26f9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,3 +1,11 @@ +# Deployment workflow for the JHB Software website. +# +# This workflow deploys the CMS before the Web frontend to ensure the frontend +# always builds against the latest CMS schema and content. The Web frontend +# fetches data from the CMS at build time, so the CMS must be deployed first. +# +# Disable automatic Vercel deployments for both projects to avoid race conditions. + name: Deploy on: From 1fd6122d66e5d4855bde117fded7eea08702228a Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:21:32 +0100 Subject: [PATCH 07/19] feat(ci): add preview deployments and concurrency control --- .github/workflows/deploy.yml | 107 ++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a0c26f9..39197b6 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,6 +4,9 @@ # always builds against the latest CMS schema and content. The Web frontend # fetches data from the CMS at build time, so the CMS must be deployed first. # +# Production: Triggered on push to main +# Preview: Triggered on pull requests, uses CMS preview URL for Web build +# # Disable automatic Vercel deployments for both projects to avoid race conditions. name: Deploy @@ -12,6 +15,8 @@ on: push: branches: - main + pull_request: + types: [opened, synchronize, reopened] workflow_dispatch: inputs: deploy_cms: @@ -24,15 +29,28 @@ on: required: false default: true type: boolean + environment: + description: 'Environment' + required: false + default: 'preview' + type: choice + options: + - preview + - production + +concurrency: + group: deploy-${{ github.ref }} + cancel-in-progress: true env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + IS_PRODUCTION: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event.inputs.environment == 'production' }} jobs: deploy-cms: name: Deploy CMS runs-on: ubuntu-latest - if: ${{ github.event_name == 'push' || github.event.inputs.deploy_cms == 'true' }} + if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_cms == 'true' }} outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} steps: @@ -47,8 +65,9 @@ jobs: - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Deploy to Vercel - id: deploy + - name: Deploy to Vercel (Production) + id: deploy-prod + if: ${{ env.IS_PRODUCTION == 'true' }} run: | DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT @@ -56,12 +75,32 @@ jobs: env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} + - name: Deploy to Vercel (Preview) + id: deploy-preview + if: ${{ env.IS_PRODUCTION != 'true' }} + run: | + DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }}) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "CMS preview deployed to: $DEPLOYMENT_URL" + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} + + - name: Set deployment URL output + id: deploy + run: | + if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then + echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT + else + echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT + fi deploy-web: name: Deploy Web runs-on: ubuntu-latest needs: deploy-cms - if: ${{ always() && (github.event_name == 'push' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} + if: ${{ always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} + outputs: + deployment_url: ${{ steps.deploy.outputs.deployment_url }} steps: - name: Checkout uses: actions/checkout@v4 @@ -74,8 +113,9 @@ jobs: - name: Install Vercel CLI run: npm install -g vercel@latest - - name: Deploy to Vercel - id: deploy + - name: Deploy to Vercel (Production) + id: deploy-prod + if: ${{ env.IS_PRODUCTION == 'true' }} run: | DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT @@ -83,9 +123,62 @@ jobs: env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} + - name: Deploy to Vercel (Preview) + id: deploy-preview + if: ${{ env.IS_PRODUCTION != 'true' }} + run: | + DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "Web preview deployed to: $DEPLOYMENT_URL" + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} + + - name: Set deployment URL output + id: deploy + run: | + if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then + echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT + else + echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT + fi + - name: Deployment Summary run: | - echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY + if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then + echo "## Production Deployment Complete" >> $GITHUB_STEP_SUMMARY + else + echo "## Preview Deployment Complete" >> $GITHUB_STEP_SUMMARY + fi echo "" >> $GITHUB_STEP_SUMMARY echo "- **CMS**: ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }}" >> $GITHUB_STEP_SUMMARY echo "- **Web**: ${{ steps.deploy.outputs.deployment_url }}" >> $GITHUB_STEP_SUMMARY + + comment-preview: + name: Comment Preview URLs + runs-on: ubuntu-latest + needs: [deploy-cms, deploy-web] + if: ${{ github.event_name == 'pull_request' && needs.deploy-web.result == 'success' }} + steps: + - name: Find existing comment + uses: peter-evans/find-comment@v3 + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '## Preview Deployment' + + - name: Create or update comment + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + edit-mode: replace + body: | + ## Preview Deployment + + | Project | URL | + |---------|-----| + | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | + | Web | ${{ needs.deploy-web.outputs.deployment_url }} | + + The Web preview uses the CMS preview URL for content fetching. From ba84ea4fc6c3fb83dfadd6d5def4001d5aee7132 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:26:09 +0100 Subject: [PATCH 08/19] test(web): add preview deployment banner and console logs --- web/src/layout/Layout.astro | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/web/src/layout/Layout.astro b/web/src/layout/Layout.astro index a0f4247..751158f 100644 --- a/web/src/layout/Layout.astro +++ b/web/src/layout/Layout.astro @@ -3,6 +3,7 @@ import CacheClearButton from '@/components/CacheClearButton.astro' import PostHog from '@/components/PostHog.astro' import { websiteConfig } from '@/config' import '@fontsource-variable/montserrat' +import { CMS_URL } from 'astro:env/client' import { VERCEL_ENV } from 'astro:env/server' import { ClientRouter } from 'astro:transitions' import type { SeoMetadata } from 'cms/src/payload-types' @@ -24,6 +25,10 @@ const { preview } = Astro.locals.globalState const enableAnalytics = VERCEL_ENV === 'production' && !preview const showCacheButton = import.meta.env.DEV && !preview +const isPreviewDeployment = VERCEL_ENV === 'preview' + +console.log('[Preview Test] CMS_URL:', CMS_URL) +console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV) --- @@ -59,6 +64,13 @@ const showCacheButton = import.meta.env.DEV && !preview "url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='32' height='32' fill='none' stroke='rgb(15 23 42 / 0.025)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e\")", }} > + { + isPreviewDeployment && ( +
+ Preview Deployment - CMS: {CMS_URL} +
+ ) + }
From a570d60211c998d2f0bb6dfc982acea4476fcdbb Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:34:59 +0100 Subject: [PATCH 09/19] docs(ci): add prerequisites and TODO for bypass secret migration --- .github/workflows/deploy.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 39197b6..592203f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,7 +7,12 @@ # Production: Triggered on push to main # Preview: Triggered on pull requests, uses CMS preview URL for Web build # -# Disable automatic Vercel deployments for both projects to avoid race conditions. +# Prerequisites: +# - Disable automatic Vercel deployments for both projects to avoid race conditions +# - Disable Vercel Authentication for CMS preview deployments (Settings → Deployment Protection) +# +# TODO: Migrate to using VERCEL_AUTOMATION_BYPASS_SECRET instead of disabling authentication. +# This would require passing the bypass header in getRedirects.ts and the PayloadSDK. name: Deploy @@ -127,7 +132,7 @@ jobs: id: deploy-preview if: ${{ env.IS_PRODUCTION != 'true' }} run: | - DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) + DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} -e CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT echo "Web preview deployed to: $DEPLOYMENT_URL" env: From d98901d23f7cd49d1ca90cebd8adfe7eda24c446 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:41:49 +0100 Subject: [PATCH 10/19] feat(ci): add Vercel inspect links to PR comment --- .github/workflows/deploy.yml | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 592203f..377cefe 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -58,6 +58,7 @@ jobs: if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_cms == 'true' }} outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} + inspect_url: ${{ steps.deploy.outputs.inspect_url }} steps: - name: Checkout uses: actions/checkout@v4 @@ -74,8 +75,11 @@ jobs: id: deploy-prod if: ${{ env.IS_PRODUCTION == 'true' }} run: | - DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) + OUTPUT=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) + INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT echo "CMS deployed to: $DEPLOYMENT_URL" env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -84,8 +88,11 @@ jobs: id: deploy-preview if: ${{ env.IS_PRODUCTION != 'true' }} run: | - DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }}) + OUTPUT=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) + INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT echo "CMS preview deployed to: $DEPLOYMENT_URL" env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -95,8 +102,10 @@ jobs: run: | if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT + echo "inspect_url=${{ steps.deploy-prod.outputs.inspect_url }}" >> $GITHUB_OUTPUT else echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT + echo "inspect_url=${{ steps.deploy-preview.outputs.inspect_url }}" >> $GITHUB_OUTPUT fi deploy-web: @@ -106,6 +115,7 @@ jobs: if: ${{ always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} + inspect_url: ${{ steps.deploy.outputs.inspect_url }} steps: - name: Checkout uses: actions/checkout@v4 @@ -122,8 +132,11 @@ jobs: id: deploy-prod if: ${{ env.IS_PRODUCTION == 'true' }} run: | - DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) + OUTPUT=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) + INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT echo "Web deployed to: $DEPLOYMENT_URL" env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} @@ -132,8 +145,11 @@ jobs: id: deploy-preview if: ${{ env.IS_PRODUCTION != 'true' }} run: | - DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} -e CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) + OUTPUT=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} 2>&1) + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) + INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT echo "Web preview deployed to: $DEPLOYMENT_URL" env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} @@ -143,8 +159,10 @@ jobs: run: | if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT + echo "inspect_url=${{ steps.deploy-prod.outputs.inspect_url }}" >> $GITHUB_OUTPUT else echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT + echo "inspect_url=${{ steps.deploy-preview.outputs.inspect_url }}" >> $GITHUB_OUTPUT fi - name: Deployment Summary @@ -181,9 +199,9 @@ jobs: body: | ## Preview Deployment - | Project | URL | - |---------|-----| - | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | - | Web | ${{ needs.deploy-web.outputs.deployment_url }} | + | Project | Preview | Inspect | + |---------|---------|---------| + | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | [View](${{ needs.deploy-cms.outputs.inspect_url }}) | + | Web | ${{ needs.deploy-web.outputs.deployment_url }} | [View](${{ needs.deploy-web.outputs.inspect_url }}) | The Web preview uses the CMS preview URL for content fetching. From 00e243f860aa6c33d3280ae406a51209d1c8e3ba Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:45:07 +0100 Subject: [PATCH 11/19] refactor(ci): simplify and speed up deployment workflow --- .github/workflows/deploy.yml | 113 ++++++++--------------------------- 1 file changed, 24 insertions(+), 89 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 377cefe..27be94f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -49,7 +49,6 @@ concurrency: env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - IS_PRODUCTION: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event.inputs.environment == 'production' }} jobs: deploy-cms: @@ -63,51 +62,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - - - name: Install Vercel CLI - run: npm install -g vercel@latest - - - name: Deploy to Vercel (Production) - id: deploy-prod - if: ${{ env.IS_PRODUCTION == 'true' }} - run: | - OUTPUT=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) - INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') - echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT - echo "CMS deployed to: $DEPLOYMENT_URL" - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - - - name: Deploy to Vercel (Preview) - id: deploy-preview - if: ${{ env.IS_PRODUCTION != 'true' }} + - name: Deploy to Vercel + id: deploy run: | - OUTPUT=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) - INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') - echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT - echo "CMS preview deployed to: $DEPLOYMENT_URL" + PROD_FLAG=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' && '--prod' || '' }} + OUTPUT=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) + echo "$OUTPUT" + echo "deployment_url=$(echo "$OUTPUT" | grep -E '^https://' | tail -1)" >> $GITHUB_OUTPUT + echo "inspect_url=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}')" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} - - name: Set deployment URL output - id: deploy - run: | - if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then - echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT - echo "inspect_url=${{ steps.deploy-prod.outputs.inspect_url }}" >> $GITHUB_OUTPUT - else - echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT - echo "inspect_url=${{ steps.deploy-preview.outputs.inspect_url }}" >> $GITHUB_OUTPUT - fi - deploy-web: name: Deploy Web runs-on: ubuntu-latest @@ -120,61 +85,31 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - - - name: Install Vercel CLI - run: npm install -g vercel@latest - - - name: Deploy to Vercel (Production) - id: deploy-prod - if: ${{ env.IS_PRODUCTION == 'true' }} - run: | - OUTPUT=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) - INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') - echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT - echo "Web deployed to: $DEPLOYMENT_URL" - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - - - name: Deploy to Vercel (Preview) - id: deploy-preview - if: ${{ env.IS_PRODUCTION != 'true' }} - run: | - OUTPUT=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} 2>&1) - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -E '^https://' | tail -1) - INSPECT_URL=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}') - echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT - echo "Web preview deployed to: $DEPLOYMENT_URL" - env: - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - - - name: Set deployment URL output + - name: Deploy to Vercel id: deploy run: | - if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then - echo "deployment_url=${{ steps.deploy-prod.outputs.deployment_url }}" >> $GITHUB_OUTPUT - echo "inspect_url=${{ steps.deploy-prod.outputs.inspect_url }}" >> $GITHUB_OUTPUT + IS_PROD=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' }} + if [ "$IS_PROD" == "true" ]; then + OUTPUT=$(npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) else - echo "deployment_url=${{ steps.deploy-preview.outputs.deployment_url }}" >> $GITHUB_OUTPUT - echo "inspect_url=${{ steps.deploy-preview.outputs.inspect_url }}" >> $GITHUB_OUTPUT + OUTPUT=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ + --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} \ + --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} 2>&1) fi + echo "$OUTPUT" + echo "deployment_url=$(echo "$OUTPUT" | grep -E '^https://' | tail -1)" >> $GITHUB_OUTPUT + echo "inspect_url=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}')" >> $GITHUB_OUTPUT + env: + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} - name: Deployment Summary run: | - if [ "${{ env.IS_PRODUCTION }}" == "true" ]; then - echo "## Production Deployment Complete" >> $GITHUB_STEP_SUMMARY - else - echo "## Preview Deployment Complete" >> $GITHUB_STEP_SUMMARY - fi + echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "- **CMS**: ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }}" >> $GITHUB_STEP_SUMMARY - echo "- **Web**: ${{ steps.deploy.outputs.deployment_url }}" >> $GITHUB_STEP_SUMMARY + echo "| Project | URL | Inspect |" >> $GITHUB_STEP_SUMMARY + echo "|---------|-----|---------|" >> $GITHUB_STEP_SUMMARY + echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | [View](${{ needs.deploy-cms.outputs.inspect_url }}) |" >> $GITHUB_STEP_SUMMARY + echo "| Web | ${{ steps.deploy.outputs.deployment_url }} | [View](${{ steps.deploy.outputs.inspect_url }}) |" >> $GITHUB_STEP_SUMMARY comment-preview: name: Comment Preview URLs From a6e1930fb4ac02442437cd4d6fb2f60d6a314fcb Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:49:16 +0100 Subject: [PATCH 12/19] fix(ci): improve URL parsing from Vercel output --- .github/workflows/deploy.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 27be94f..cc82737 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -68,8 +68,10 @@ jobs: PROD_FLAG=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' && '--prod' || '' }} OUTPUT=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) echo "$OUTPUT" - echo "deployment_url=$(echo "$OUTPUT" | grep -E '^https://' | tail -1)" >> $GITHUB_OUTPUT - echo "inspect_url=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}')" >> $GITHUB_OUTPUT + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -oE 'https://[a-zA-Z0-9.-]+\.vercel\.app' | head -1) + INSPECT_URL=$(echo "$OUTPUT" | grep -oE 'https://vercel\.com/[^ ]+' | head -1) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -97,8 +99,10 @@ jobs: --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} 2>&1) fi echo "$OUTPUT" - echo "deployment_url=$(echo "$OUTPUT" | grep -E '^https://' | tail -1)" >> $GITHUB_OUTPUT - echo "inspect_url=$(echo "$OUTPUT" | grep 'Inspect:' | awk '{print $2}')" >> $GITHUB_OUTPUT + DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -oE 'https://[a-zA-Z0-9.-]+\.vercel\.app' | head -1) + INSPECT_URL=$(echo "$OUTPUT" | grep -oE 'https://vercel\.com/[^ ]+' | head -1) + echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT + echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} From 67397ffeb9ac2254aa1c2496609cb59c57caddf7 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 21:52:46 +0100 Subject: [PATCH 13/19] refactor(ci): simplify by using vercel stdout directly, remove inspect URLs --- .github/workflows/deploy.yml | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cc82737..c230315 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -57,7 +57,6 @@ jobs: if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_cms == 'true' }} outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} - inspect_url: ${{ steps.deploy.outputs.inspect_url }} steps: - name: Checkout uses: actions/checkout@v4 @@ -66,12 +65,8 @@ jobs: id: deploy run: | PROD_FLAG=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' && '--prod' || '' }} - OUTPUT=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) - echo "$OUTPUT" - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -oE 'https://[a-zA-Z0-9.-]+\.vercel\.app' | head -1) - INSPECT_URL=$(echo "$OUTPUT" | grep -oE 'https://vercel\.com/[^ ]+' | head -1) + DEPLOYMENT_URL=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -82,7 +77,6 @@ jobs: if: ${{ always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} - inspect_url: ${{ steps.deploy.outputs.inspect_url }} steps: - name: Checkout uses: actions/checkout@v4 @@ -92,17 +86,13 @@ jobs: run: | IS_PROD=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' }} if [ "$IS_PROD" == "true" ]; then - OUTPUT=$(npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1) + DEPLOYMENT_URL=$(npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) else - OUTPUT=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ + DEPLOYMENT_URL=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} \ - --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} 2>&1) + --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) fi - echo "$OUTPUT" - DEPLOYMENT_URL=$(echo "$OUTPUT" | grep -oE 'https://[a-zA-Z0-9.-]+\.vercel\.app' | head -1) - INSPECT_URL=$(echo "$OUTPUT" | grep -oE 'https://vercel\.com/[^ ]+' | head -1) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT - echo "inspect_url=$INSPECT_URL" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEB_PROJECT_ID }} @@ -110,10 +100,10 @@ jobs: run: | echo "## Deployment Complete" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "| Project | URL | Inspect |" >> $GITHUB_STEP_SUMMARY - echo "|---------|-----|---------|" >> $GITHUB_STEP_SUMMARY - echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | [View](${{ needs.deploy-cms.outputs.inspect_url }}) |" >> $GITHUB_STEP_SUMMARY - echo "| Web | ${{ steps.deploy.outputs.deployment_url }} | [View](${{ steps.deploy.outputs.inspect_url }}) |" >> $GITHUB_STEP_SUMMARY + echo "| Project | URL |" >> $GITHUB_STEP_SUMMARY + echo "|---------|-----|" >> $GITHUB_STEP_SUMMARY + echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url }} |" >> $GITHUB_STEP_SUMMARY + echo "| Web | ${{ steps.deploy.outputs.deployment_url }} |" >> $GITHUB_STEP_SUMMARY comment-preview: name: Comment Preview URLs @@ -138,9 +128,9 @@ jobs: body: | ## Preview Deployment - | Project | Preview | Inspect | - |---------|---------|---------| - | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | [View](${{ needs.deploy-cms.outputs.inspect_url }}) | - | Web | ${{ needs.deploy-web.outputs.deployment_url }} | [View](${{ needs.deploy-web.outputs.inspect_url }}) | + | Project | URL | + |---------|-----| + | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | + | Web | ${{ needs.deploy-web.outputs.deployment_url }} | The Web preview uses the CMS preview URL for content fetching. From 6e25accdbdf29fe6a5812cd3c2bec75228a125d6 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:03:07 +0100 Subject: [PATCH 14/19] feat(ci): add change detection and skip tags support --- .github/workflows/deploy.yml | 79 +++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c230315..7b67f1b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,6 +7,13 @@ # Production: Triggered on push to main # Preview: Triggered on pull requests, uses CMS preview URL for Web build # +# Skip builds by adding to commit message: +# - [skip-cms] - Skip CMS deployment +# - [skip-web] - Skip Web deployment +# +# For CMS-triggered web rebuilds (content updates), use Vercel's deployment hook: +# Vercel → Web project → Settings → Git → Deploy Hooks +# # Prerequisites: # - Disable automatic Vercel deployments for both projects to avoid race conditions # - Disable Vercel Authentication for CMS preview deployments (Settings → Deployment Protection) @@ -51,10 +58,64 @@ env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} jobs: + detect-changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + cms_changed: ${{ steps.changes.outputs.cms_changed }} + web_changed: ${{ steps.changes.outputs.web_changed }} + skip_cms: ${{ steps.skip.outputs.skip_cms }} + skip_web: ${{ steps.skip.outputs.skip_web }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check for skip tags + id: skip + run: | + COMMIT_MSG="${{ github.event.head_commit.message || github.event.pull_request.title || '' }}" + echo "skip_cms=$([[ "$COMMIT_MSG" == *"[skip-cms]"* ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT + echo "skip_web=$([[ "$COMMIT_MSG" == *"[skip-web]"* ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT + + - name: Detect changed files + id: changes + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + # Manual trigger: use input values + echo "cms_changed=true" >> $GITHUB_OUTPUT + echo "web_changed=true" >> $GITHUB_OUTPUT + else + # Push/PR: detect actual changes + if [ "${{ github.event_name }}" == "pull_request" ]; then + BASE_SHA=${{ github.event.pull_request.base.sha }} + HEAD_SHA=${{ github.event.pull_request.head.sha }} + else + BASE_SHA=${{ github.event.before }} + HEAD_SHA=${{ github.sha }} + fi + + CHANGED_FILES=$(git diff --name-only $BASE_SHA $HEAD_SHA 2>/dev/null || echo "") + + # Check if cms/ or web/ folders have changes (or workflow file) + CMS_CHANGED=$([[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false') + WEB_CHANGED=$([[ "$CHANGED_FILES" == *"web/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false') + + echo "cms_changed=$CMS_CHANGED" >> $GITHUB_OUTPUT + echo "web_changed=$WEB_CHANGED" >> $GITHUB_OUTPUT + echo "Changed files: $CHANGED_FILES" + fi + deploy-cms: name: Deploy CMS runs-on: ubuntu-latest - if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_cms == 'true' }} + needs: detect-changes + if: | + (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_cms == 'true') || + (github.event_name != 'workflow_dispatch' && + needs.detect-changes.outputs.cms_changed == 'true' && + needs.detect-changes.outputs.skip_cms == 'false') outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} steps: @@ -73,8 +134,16 @@ jobs: deploy-web: name: Deploy Web runs-on: ubuntu-latest - needs: deploy-cms - if: ${{ always() && (github.event_name != 'workflow_dispatch' || github.event.inputs.deploy_web == 'true') && (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') }} + needs: [detect-changes, deploy-cms] + if: | + always() && + (needs.deploy-cms.result == 'success' || needs.deploy-cms.result == 'skipped') && + ( + (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_web == 'true') || + (github.event_name != 'workflow_dispatch' && + needs.detect-changes.outputs.web_changed == 'true' && + needs.detect-changes.outputs.skip_web == 'false') + ) outputs: deployment_url: ${{ steps.deploy.outputs.deployment_url }} steps: @@ -102,7 +171,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "| Project | URL |" >> $GITHUB_STEP_SUMMARY echo "|---------|-----|" >> $GITHUB_STEP_SUMMARY - echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url }} |" >> $GITHUB_STEP_SUMMARY + echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }} |" >> $GITHUB_STEP_SUMMARY echo "| Web | ${{ steps.deploy.outputs.deployment_url }} |" >> $GITHUB_STEP_SUMMARY comment-preview: @@ -130,7 +199,7 @@ jobs: | Project | URL | |---------|-----| - | CMS | ${{ needs.deploy-cms.outputs.deployment_url }} | + | CMS | ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }} | | Web | ${{ needs.deploy-web.outputs.deployment_url }} | The Web preview uses the CMS preview URL for content fetching. From 7cb676b283517db2a97155c3e1d6051746de0a61 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:14:08 +0100 Subject: [PATCH 15/19] fix(ci): handle empty CMS_URL and fix PROD_FLAG expression --- .github/workflows/deploy.yml | 19 ++++++++--- README.md | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7b67f1b..2f0a900 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -125,7 +125,11 @@ jobs: - name: Deploy to Vercel id: deploy run: | - PROD_FLAG=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' && '--prod' || '' }} + IS_PROD=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' }} + PROD_FLAG="" + if [ "$IS_PROD" == "true" ]; then + PROD_FLAG="--prod" + fi DEPLOYMENT_URL=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT env: @@ -154,12 +158,19 @@ jobs: id: deploy run: | IS_PROD=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' }} + CMS_URL="${{ needs.deploy-cms.outputs.deployment_url }}" + if [ "$IS_PROD" == "true" ]; then DEPLOYMENT_URL=$(npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) - else + elif [ -n "$CMS_URL" ]; then + # Preview with CMS preview URL DEPLOYMENT_URL=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ - --build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} \ - --env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}) + --build-env CMS_URL=$CMS_URL \ + --env CMS_URL=$CMS_URL) + else + # Preview without CMS override (uses production CMS from Vercel env vars) + echo "CMS deployment skipped, using production CMS from Vercel env vars" + DEPLOYMENT_URL=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }}) fi echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT env: diff --git a/README.md b/README.md index 19b3fd8..f9d9af3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,64 @@ # Website of JHB Software Monorepository of the JHB Website frontend and content management system (CMS) + +## Deployment + +This repository uses a GitHub Actions workflow to deploy both the CMS and Web frontend to Vercel. The workflow ensures the CMS is always deployed before the Web frontend, as the frontend fetches data from the CMS at build time. + +### How It Works + +| Trigger | CMS | Web | Environment | +|---------|-----|-----|-------------| +| Push to `main` | If `cms/` changed | If `web/` changed | Production | +| Pull request | If `cms/` changed | If `web/` changed | Preview | +| Manual dispatch | Configurable | Configurable | Configurable | +| Vercel Deploy Hook | No | Yes | Production | + +### Vercel Setup + +To avoid double deployments (one from Vercel's Git integration and one from GitHub Actions), disable automatic deployments in Vercel: + +1. Go to **Vercel Dashboard** → **CMS Project** → **Settings** → **Git** +2. Under "Deploy Hooks", you can optionally create a hook for CMS-triggered rebuilds +3. Under "Ignored Build Step", select **Don't build** (or use the GitHub Actions workflow exclusively) +4. Repeat for the **Web Project** + +Alternatively, disconnect the Git repository from Vercel entirely and rely solely on the GitHub Actions workflow for deployments. + +### CMS-Triggered Web Rebuilds + +When content is updated in the CMS, you can trigger a Web rebuild using Vercel's Deploy Hook: + +1. Go to **Vercel Dashboard** → **Web Project** → **Settings** → **Git** → **Deploy Hooks** +2. Create a new hook (e.g., "CMS Content Update") +3. Use the generated URL in your CMS to trigger rebuilds when content is published + +### Skip Deployments + +Add these tags to your commit message to skip specific deployments: + +- `[skip-cms]` - Skip CMS deployment +- `[skip-web]` - Skip Web deployment + +Example: `fix(web): update styles [skip-cms]` + +### Required GitHub Secrets + +| Secret | Description | +|--------|-------------| +| `VERCEL_TOKEN` | Vercel API token ([create here](https://vercel.com/account/tokens)) | +| `VERCEL_ORG_ID` | Vercel Team ID (Settings → General) | +| `VERCEL_CMS_PROJECT_ID` | CMS project ID (Project Settings → General) | +| `VERCEL_WEB_PROJECT_ID` | Web project ID (Project Settings → General) | + +### Preview Deployments + +For pull requests, the workflow: +1. Deploys CMS to a preview URL +2. Deploys Web to a preview URL, configured to use the CMS preview URL +3. Posts a comment on the PR with both preview URLs + +**Note:** Disable Vercel Authentication for CMS preview deployments to allow the Web build to fetch data: +- Go to **Vercel Dashboard** → **CMS Project** → **Settings** → **Deployment Protection** +- Set Vercel Authentication to **Disabled** or **Only Production** From 844beefbc231067891f24a8353d282b540837337 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:15:37 +0100 Subject: [PATCH 16/19] test(cms): add dummy sitemap entry to test CMS-only deployment --- cms/src/endpoints/sitemap.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cms/src/endpoints/sitemap.ts b/cms/src/endpoints/sitemap.ts index d0f1289..926b741 100644 --- a/cms/src/endpoints/sitemap.ts +++ b/cms/src/endpoints/sitemap.ts @@ -59,6 +59,12 @@ export async function getSitemap(req: PayloadRequest) { } } + // TODO: Remove this dummy entry - testing CMS-only deployment + pages.push({ + path: '/dummy-test-entry', + updatedAt: new Date().toISOString(), + }) + const jsonString = JSON.stringify(pages) const etag = createHash('md5').update(jsonString).digest('hex') From b74132136892455df204757c80556c0f0f951fd4 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:25:27 +0100 Subject: [PATCH 17/19] fix(ci): install Vercel CLI globally to avoid npx download --- .github/workflows/deploy.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2f0a900..903bd03 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -122,6 +122,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install Vercel CLI + run: npm install -g vercel + - name: Deploy to Vercel id: deploy run: | @@ -130,7 +133,7 @@ jobs: if [ "$IS_PROD" == "true" ]; then PROD_FLAG="--prod" fi - DEPLOYMENT_URL=$(npx vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy $PROD_FLAG --yes --token=${{ secrets.VERCEL_TOKEN }}) echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT env: VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }} @@ -154,6 +157,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install Vercel CLI + run: npm install -g vercel + - name: Deploy to Vercel id: deploy run: | @@ -161,16 +167,16 @@ jobs: CMS_URL="${{ needs.deploy-cms.outputs.deployment_url }}" if [ "$IS_PROD" == "true" ]; then - DEPLOYMENT_URL=$(npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) elif [ -n "$CMS_URL" ]; then # Preview with CMS preview URL - DEPLOYMENT_URL=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ + DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ --build-env CMS_URL=$CMS_URL \ --env CMS_URL=$CMS_URL) else # Preview without CMS override (uses production CMS from Vercel env vars) echo "CMS deployment skipped, using production CMS from Vercel env vars" - DEPLOYMENT_URL=$(npx vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }}) + DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }}) fi echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT env: From 3ff8c2288ae06eca4534e357a2c94db9363e5d02 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:36:32 +0100 Subject: [PATCH 18/19] feat: add Vercel automation bypass for protected CMS previews --- .github/workflows/deploy.yml | 11 +++++------ README.md | 14 +++++++++++--- web/astro.config.mjs | 5 +++++ web/src/cms/getRedirects.ts | 4 ++++ web/src/cms/sdk/bypassHeader.ts | 20 ++++++++++++++++++++ web/src/cms/sdk/cachedFetch.ts | 8 ++++++-- 6 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 web/src/cms/sdk/bypassHeader.ts diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 903bd03..d52943b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,10 +16,7 @@ # # Prerequisites: # - Disable automatic Vercel deployments for both projects to avoid race conditions -# - Disable Vercel Authentication for CMS preview deployments (Settings → Deployment Protection) -# -# TODO: Migrate to using VERCEL_AUTOMATION_BYPASS_SECRET instead of disabling authentication. -# This would require passing the bypass header in getRedirects.ts and the PayloadSDK. +# - Set up CMS_VERCEL_AUTOMATION_BYPASS_SECRET to allow Web builds to fetch from protected CMS previews name: Deploy @@ -169,10 +166,12 @@ jobs: if [ "$IS_PROD" == "true" ]; then DEPLOYMENT_URL=$(vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }}) elif [ -n "$CMS_URL" ]; then - # Preview with CMS preview URL + # Preview with CMS preview URL and bypass secret for Vercel Authentication DEPLOYMENT_URL=$(vercel deploy --yes --token=${{ secrets.VERCEL_TOKEN }} \ --build-env CMS_URL=$CMS_URL \ - --env CMS_URL=$CMS_URL) + --build-env CMS_VERCEL_AUTOMATION_BYPASS_SECRET=${{ secrets.CMS_VERCEL_AUTOMATION_BYPASS_SECRET }} \ + --env CMS_URL=$CMS_URL \ + --env CMS_VERCEL_AUTOMATION_BYPASS_SECRET=${{ secrets.CMS_VERCEL_AUTOMATION_BYPASS_SECRET }}) else # Preview without CMS override (uses production CMS from Vercel env vars) echo "CMS deployment skipped, using production CMS from Vercel env vars" diff --git a/README.md b/README.md index f9d9af3..cb03b3e 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Example: `fix(web): update styles [skip-cms]` | `VERCEL_ORG_ID` | Vercel Team ID (Settings → General) | | `VERCEL_CMS_PROJECT_ID` | CMS project ID (Project Settings → General) | | `VERCEL_WEB_PROJECT_ID` | Web project ID (Project Settings → General) | +| `CMS_VERCEL_AUTOMATION_BYPASS_SECRET` | CMS bypass secret for preview builds (see below) | ### Preview Deployments @@ -59,6 +60,13 @@ For pull requests, the workflow: 2. Deploys Web to a preview URL, configured to use the CMS preview URL 3. Posts a comment on the PR with both preview URLs -**Note:** Disable Vercel Authentication for CMS preview deployments to allow the Web build to fetch data: -- Go to **Vercel Dashboard** → **CMS Project** → **Settings** → **Deployment Protection** -- Set Vercel Authentication to **Disabled** or **Only Production** +#### CMS Authentication Bypass + +To allow the Web build to fetch data from protected CMS preview deployments: + +1. Go to **Vercel Dashboard** → **CMS Project** → **Settings** → **Deployment Protection** +2. Enable **Vercel Authentication** (requires Pro plan with Advanced Deployment Protection) +3. Copy the **Protection Bypass for Automation** secret +4. Add it as `CMS_VERCEL_AUTOMATION_BYPASS_SECRET` in GitHub repository secrets + +This allows the Web build to authenticate with the CMS preview while keeping it protected from public access. diff --git a/web/astro.config.mjs b/web/astro.config.mjs index 9ead447..b800654 100644 --- a/web/astro.config.mjs +++ b/web/astro.config.mjs @@ -28,6 +28,11 @@ export default defineConfig({ context: 'server', access: 'public', }), + CMS_VERCEL_AUTOMATION_BYPASS_SECRET: envField.string({ + context: 'server', + access: 'secret', + optional: true, + }), }, }, }) diff --git a/web/src/cms/getRedirects.ts b/web/src/cms/getRedirects.ts index 23ca610..32be50d 100644 --- a/web/src/cms/getRedirects.ts +++ b/web/src/cms/getRedirects.ts @@ -2,13 +2,17 @@ import { PayloadSDK } from '@payloadcms/sdk' import type { RedirectConfig } from 'astro' import type { Config } from 'cms/src/payload-types' import 'dotenv/config' +import { addBypassHeader } from './sdk/bypassHeader' /** Fetches the redirects from the CMS and converts them to the Astro `RedirectConfig` format. */ export async function getRedirects(): Promise> { // Because import.meta.env and astro:env is not available in Astro config files and this method is called from // the Astro config file, use process.env to access the environment variable instead. + const bypassSecret = process.env.CMS_VERCEL_AUTOMATION_BYPASS_SECRET + const payloadSDK = new PayloadSDK({ baseURL: process.env.CMS_URL! + '/api', + fetch: (input, init) => fetch(input, addBypassHeader(init, bypassSecret)), }) const redirectsCms = await payloadSDK.find({ diff --git a/web/src/cms/sdk/bypassHeader.ts b/web/src/cms/sdk/bypassHeader.ts new file mode 100644 index 0000000..41271b3 --- /dev/null +++ b/web/src/cms/sdk/bypassHeader.ts @@ -0,0 +1,20 @@ +/** + * Adds the Vercel automation bypass header to a request if the secret is configured. + * This allows fetching from CMS preview deployments that have Vercel Authentication enabled. + */ +export function addBypassHeader( + init: RequestInit | undefined, + bypassSecret: string | undefined, +): RequestInit { + if (!bypassSecret) { + return init ?? {} + } + + const headers = new Headers(init?.headers) + headers.set('x-vercel-protection-bypass', bypassSecret) + + return { + ...init, + headers, + } +} diff --git a/web/src/cms/sdk/cachedFetch.ts b/web/src/cms/sdk/cachedFetch.ts index f731b14..ce07799 100644 --- a/web/src/cms/sdk/cachedFetch.ts +++ b/web/src/cms/sdk/cachedFetch.ts @@ -1,3 +1,5 @@ +import { CMS_VERCEL_AUTOMATION_BYPASS_SECRET } from 'astro:env/server' +import { addBypassHeader } from './bypassHeader' import { cache } from './cache' /** @@ -20,6 +22,8 @@ export function createCachedFetch(baseFetch: typeof fetch): typeof fetch { input: RequestInfo | URL, init?: RequestInit, ): Promise { + // Add bypass header for Vercel Authentication + const initWithBypass = addBypassHeader(init, CMS_VERCEL_AUTOMATION_BYPASS_SECRET) // Convert input to URL string for caching const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url @@ -55,7 +59,7 @@ export function createCachedFetch(baseFetch: typeof fetch): typeof fetch { } // Make the actual request - const response = await baseFetch(input, init) + const response = await baseFetch(input, initWithBypass) if (response.ok) { // Clone the response so we can read it and still return it @@ -72,6 +76,6 @@ export function createCachedFetch(baseFetch: typeof fetch): typeof fetch { } // For non-GET requests or when cache is not explicitly enabled, just forward the request - return baseFetch(input, init) + return baseFetch(input, initWithBypass) } } From 2d1465e99d3735a74c8495f7e319b6715107a40f Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Mon, 22 Dec 2025 22:43:13 +0100 Subject: [PATCH 19/19] chore: remove test code from cms and web --- cms/src/endpoints/sitemap.ts | 6 ------ web/src/layout/Layout.astro | 12 ------------ 2 files changed, 18 deletions(-) diff --git a/cms/src/endpoints/sitemap.ts b/cms/src/endpoints/sitemap.ts index 926b741..d0f1289 100644 --- a/cms/src/endpoints/sitemap.ts +++ b/cms/src/endpoints/sitemap.ts @@ -59,12 +59,6 @@ export async function getSitemap(req: PayloadRequest) { } } - // TODO: Remove this dummy entry - testing CMS-only deployment - pages.push({ - path: '/dummy-test-entry', - updatedAt: new Date().toISOString(), - }) - const jsonString = JSON.stringify(pages) const etag = createHash('md5').update(jsonString).digest('hex') diff --git a/web/src/layout/Layout.astro b/web/src/layout/Layout.astro index 751158f..a0f4247 100644 --- a/web/src/layout/Layout.astro +++ b/web/src/layout/Layout.astro @@ -3,7 +3,6 @@ import CacheClearButton from '@/components/CacheClearButton.astro' import PostHog from '@/components/PostHog.astro' import { websiteConfig } from '@/config' import '@fontsource-variable/montserrat' -import { CMS_URL } from 'astro:env/client' import { VERCEL_ENV } from 'astro:env/server' import { ClientRouter } from 'astro:transitions' import type { SeoMetadata } from 'cms/src/payload-types' @@ -25,10 +24,6 @@ const { preview } = Astro.locals.globalState const enableAnalytics = VERCEL_ENV === 'production' && !preview const showCacheButton = import.meta.env.DEV && !preview -const isPreviewDeployment = VERCEL_ENV === 'preview' - -console.log('[Preview Test] CMS_URL:', CMS_URL) -console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV) --- @@ -64,13 +59,6 @@ console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV) "url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='32' height='32' fill='none' stroke='rgb(15 23 42 / 0.025)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e\")", }} > - { - isPreviewDeployment && ( -
- Preview Deployment - CMS: {CMS_URL} -
- ) - }