diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8a49cc..b372724 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,7 +128,7 @@ jobs: release: name: release - needs: [check, e2e] + needs: [check, site, e2e] # Off until launch: the repository variable RELEASE_ENABLED is set to true once v0.0.0 is tagged and staging exists. # Without the tag, semantic-release counts every commit and picks 1.0.0. if: github.event_name == 'push' && vars.RELEASE_ENABLED == 'true' @@ -177,3 +177,20 @@ jobs: git checkout -B staging origin/staging git merge --no-ff origin/main -m "chore(release): merge main into staging [skip ci]" git push origin staging + + deploy-site: + name: deploy site + needs: release + # Only main is production; Vercel no longer deploys it on push (site/vercel.json), so this is the one production deploy, + # made after the release job has pushed its version commit. + if: github.ref_name == 'main' + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + # The hook builds main's tip, so an older commit can never replace a newer one in production. + - name: Trigger the production deploy + env: + HOOK: ${{ secrets.VERCEL_DEPLOY_HOOK_MAIN }} + run: | + if [ -z "$HOOK" ]; then echo "::error::VERCEL_DEPLOY_HOOK_MAIN is not set"; exit 1; fi + curl --fail-with-body -sS -X POST "$HOOK" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99bb0db..42b4bab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,3 +101,7 @@ workflow's `release` job runs them after the checks pass. the bot commits `chore(release): x.y.z [skip ci]` to `main`, and then merges `main` back into `staging`. Release candidates only change the published package, so the repo keeps the last release's version between releases. Never edit these pins by hand. +- **The website** deploys to production from CI, not from Vercel's push hook: after the `release` job, the + `deploy-site` job calls a Vercel Deploy Hook (the `VERCEL_DEPLOY_HOOK_MAIN` secret), which builds `main`'s tip. + That way the release commit, not the merge before it, is what goes live. Pull requests and `staging` still get + Vercel previews on push. diff --git a/site/scripts/ignore-build.sh b/site/scripts/ignore-build.sh new file mode 100644 index 0000000..e8eb992 --- /dev/null +++ b/site/scripts/ignore-build.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Vercel's ignoreCommand (run from site/): exit 0 skips the build, 1 builds. Lives here because vercel.json caps the +# command at 256 characters. Builds when there's no last deploy to compare with, or its commit is missing from the +# shallow clone, or anything the site reads changed since it. +if [ -n "$VERCEL_GIT_PREVIOUS_SHA" ] && + git cat-file -e "$VERCEL_GIT_PREVIOUS_SHA^{commit}" 2>/dev/null && + git diff --quiet "$VERCEL_GIT_PREVIOUS_SHA" HEAD -- . ../packages ../skill ../package.json ../tsconfig.base.json ../bun.lock; then + exit 0 +fi +exit 1 diff --git a/site/vercel.json b/site/vercel.json index cc02795..9813c11 100644 --- a/site/vercel.json +++ b/site/vercel.json @@ -3,5 +3,6 @@ "framework": "nextjs", "installCommand": "cd .. && bun install --frozen-lockfile", "buildCommand": "cd .. && bun run --filter @stackmap/viewer build && cd site && bun run build", - "ignoreCommand": "if [ -n \"$VERCEL_GIT_PREVIOUS_SHA\" ] && git cat-file -e \"$VERCEL_GIT_PREVIOUS_SHA^{commit}\" 2>/dev/null && git diff --quiet \"$VERCEL_GIT_PREVIOUS_SHA\" HEAD -- . ../packages ../package.json ../tsconfig.base.json ../bun.lock; then exit 0; else exit 1; fi" + "git": { "deploymentEnabled": { "main": false } }, + "ignoreCommand": "sh scripts/ignore-build.sh" }