Skip to content

Fix the WebKit mount stall behind the smoke failures, and let the preview gate see WebKit #776

Fix the WebKit mount stall behind the smoke failures, and let the preview gate see WebKit

Fix the WebKit mount stall behind the smoke failures, and let the preview gate see WebKit #776

Workflow file for this run

name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm test
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm format
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
packaging:
name: Packaging — publint + attw
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm -r --filter '@pretable/core' --filter '@pretable/react' --filter '@pretable/stream-adapter' --filter '@pretable/ui' build
- run: pnpm lint:packaging
publish-preflight:
name: Publish preflight
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm publish:preflight
api-report:
name: API Extractor — report freshness
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm -r --filter '@pretable/core' --filter '@pretable/react' --filter '@pretable/stream-adapter' --filter '@pretable/ui' build
- run: pnpm api:check
deploy-prod:
name: Deploy → Vercel (production)
needs:
[
test,
typecheck,
lint,
format,
build,
packaging,
publish-preflight,
api-report,
]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
# Required GitHub secrets:
# VERCEL_TOKEN — vercel.com/account/tokens
# VERCEL_ORG_ID — Vercel team id
# VERCEL_PROJECT_ID — pretable project id
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Install Playwright browser
run: pnpm exec playwright install --with-deps chromium webkit
- name: Pull Vercel project settings
run: |
mkdir -p .vercel
cat > .vercel/project.json <<EOF
{"projectId":"${{ secrets.VERCEL_PROJECT_ID }}","orgId":"${{ secrets.VERCEL_ORG_ID }}","projectName":"pretable"}
EOF
npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
rm -rf .vercel/output
- name: Build with Vercel
run: npx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel (production)
id: deploy
run: |
url=$(npx vercel deploy --prebuilt --archive=tgz --prod --yes --token=${{ secrets.VERCEL_TOKEN }} | tail -n 1)
echo "deployment_url=$url" >> "$GITHUB_OUTPUT"
echo "Deployed: $url"
- name: Wait for production alias to update
# vercel deploy --prod returns once the unique deployment URL is
# ready; the public alias atomically repoints shortly after. A short
# readiness loop avoids racing the alias swap.
run: |
for i in 1 2 3 4 5 6; do
code=$(curl -sS -o /dev/null -w "%{http_code}" "https://pretable.vercel.app" || true)
echo "Attempt $i: HTTP $code"
if [ "$code" = "200" ]; then exit 0; fi
sleep 5
done
echo "Public alias did not return 200 after deploy"
exit 1
- name: Smoke test prod with Playwright
env:
BASE_URL: https://pretable.vercel.app
run: pnpm --filter @pretable/app-website smoke
- name: Upload smoke artifacts on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: website-smoke-traces
path: apps/website/test-results/
retention-days: 7
deploy-preview:
name: Deploy → Vercel (preview)
needs:
[
test,
typecheck,
lint,
format,
build,
packaging,
publish-preflight,
api-report,
]
runs-on: ubuntu-latest
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'dependabot[bot]'
permissions:
contents: read
pull-requests: write
outputs:
preview_url: ${{ steps.deploy.outputs.preview_url }}
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Pull Vercel project settings
run: |
mkdir -p .vercel
cat > .vercel/project.json <<EOF
{"projectId":"${{ secrets.VERCEL_PROJECT_ID }}","orgId":"${{ secrets.VERCEL_ORG_ID }}","projectName":"pretable"}
EOF
npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
rm -rf .vercel/output
- name: Build with Vercel
run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy preview to Vercel
id: deploy
run: |
url=$(npx vercel deploy --prebuilt --archive=tgz --yes --token=${{ secrets.VERCEL_TOKEN }} | tail -n 1)
echo "preview_url=$url" >> "$GITHUB_OUTPUT"
echo "Preview: $url"
- name: Comment preview URL on PR
uses: marocchino/sticky-pull-request-comment@v3
with:
header: vercel-preview
message: |
### Vercel preview ready
**Preview**: ${{ steps.deploy.outputs.preview_url }}
**Commit**: `${{ github.event.pull_request.head.sha }}`
<sub>Updated automatically by the `deploy-preview` job.</sub>
smoke-preview:
name: Smoke test → Vercel preview (Playwright)
needs: deploy-preview
runs-on: ubuntu-latest
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login != 'dependabot[bot]'
env:
PREVIEW_URL: ${{ needs.deploy-preview.outputs.preview_url }}
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Choose preview verification mode
id: preview-access
run: |
if [ -n "$VERCEL_AUTOMATION_BYPASS_SECRET" ]; then
echo "mode=browser" >> "$GITHUB_OUTPUT"
else
echo "mode=skip" >> "$GITHUB_OUTPUT"
{
echo "### Preview smoke skipped"
echo
echo "No \`VERCEL_AUTOMATION_BYPASS_SECRET\` repository secret is configured, so the Playwright browser smoke cannot reach the protection-gated preview (it returns 401 without a bypass)."
echo
echo "Add the secret to enable real preview smoke coverage: Vercel → Project → Settings → Deployment Protection → Protection Bypass for Automation, then save it as the \`VERCEL_AUTOMATION_BYPASS_SECRET\` repository secret."
} >> "$GITHUB_STEP_SUMMARY"
fi
- name: Install Playwright browser
if: steps.preview-access.outputs.mode == 'browser'
run: pnpm exec playwright install --with-deps chromium webkit
- name: Wait for preview to respond
if: steps.preview-access.outputs.mode == 'browser'
run: |
# Readiness ping only: send the bypass header alone. Do NOT send
# `x-vercel-set-bypass-cookie: true` here — that makes Vercel answer
# with a 307 + Set-Cookie (to seed the bypass cookie) rather than 200,
# which a cookieless curl can't satisfy. Playwright keeps the cookie
# header (it persists the cookie across requests); this plain curl
# just needs a 200 to know the deployment is live.
for i in 1 2 3 4 5 6; do
code=$(curl -sS -o /dev/null -w "%{http_code}" \
-H "x-vercel-protection-bypass: $VERCEL_AUTOMATION_BYPASS_SECRET" \
"$PREVIEW_URL" || true)
echo "Attempt $i: HTTP $code"
if [ "$code" = "200" ]; then exit 0; fi
sleep 5
done
echo "Preview did not return 200"
exit 1
- name: Smoke test preview with Playwright
if: steps.preview-access.outputs.mode == 'browser'
env:
BASE_URL: ${{ env.PREVIEW_URL }}
# Every project, matching the production smoke below. Pinning this to
# chromium made the pre-merge gate structurally blind to exactly the
# regressions it exists to stop: a WebKit-only mount stall shipped, then
# failed the production smoke on every `main` run for 19 hours while
# every PR check stayed green. A gate that cannot see what the next gate
# blocks on is not a gate.
run: pnpm --filter @pretable/app-website smoke
- name: Upload Playwright traces on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: website-preview-traces
path: apps/website/test-results/
retention-days: 7