Stop reading the whole club to draw the organisers' dashboard #62
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
| # CI for a static site with no services to stand up. | |
| # | |
| # The ordering here is deliberate and load-bearing: `build` and `dev` share the | |
| # .next directory, so running them concurrently deletes the chunks the dev server | |
| # is serving. The page then returns 200 with no JavaScript, which looks like a | |
| # pass to anything that only checks status codes. So the build finishes and is | |
| # cleared before the dev server starts, and `smoke` runs first to prove the server | |
| # is actually serving a hydrating page before `qa` reports on it. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: web | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - run: npm ci | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Lint | |
| run: npm run lint | |
| # Static and fast, so it runs before the build. Guards the categorical-colour | |
| # constraints that a comment used to only assert — see content/programs.ts. | |
| - name: Palette constraints | |
| run: npm run palette | |
| # firestore.rules hardcodes the join form's allowed values, because Firestore | |
| # rules cannot import. This diffs the two copies and asserts the create-only | |
| # boundary is still closed. | |
| # | |
| # It runs in CI because nothing else here would catch the drift: the smoke test | |
| # submits no applications and the QA sweep reads pixels. The failure it prevents | |
| # is a real applicant getting permission-denied on a path the form offers, with | |
| # the page rendering perfectly. Needs no Firebase project and no network. | |
| - name: Firestore rules match the form | |
| run: npm run rules | |
| - name: Build | |
| run: npm run build | |
| # Proves the site is genuinely static. If a route ever starts needing a | |
| # server at request time this fails, which is the point — the whole | |
| # zero-credentials setup depends on it staying static. | |
| - name: Assert the build is fully prerendered | |
| run: | | |
| if grep -qE '^\S*λ|^\S*ƒ' .next/routes-manifest.json 2>/dev/null; then | |
| echo "A dynamic route appeared; this site must stay fully static." >&2 | |
| exit 1 | |
| fi | |
| # All three engines, not just Chromium. Chromium-only testing let a CSP | |
| # directive ship that made the site render completely blank in Safari's | |
| # engine — no CSS, no fonts, no JavaScript. Safari is the majority of mobile | |
| # traffic in the audience this is built for, so "it works in Chrome" is not a | |
| # result. | |
| - name: Install browser engines for Playwright | |
| run: npx playwright install --with-deps chromium webkit firefox | |
| # Cleared so the dev server builds its own chunks rather than inheriting | |
| # production ones. | |
| - name: Clear build output before starting dev | |
| run: rm -rf .next | |
| - name: Start dev server | |
| run: | | |
| npx next dev -p 3000 > /tmp/dev.log 2>&1 & | |
| for i in $(seq 1 60); do | |
| if [ "$(curl -s -o /dev/null -w %{http_code} http://localhost:3000 || true)" = "200" ]; then | |
| echo "up after ${i} tries"; exit 0 | |
| fi | |
| sleep 2 | |
| done | |
| echo "dev server never came up:" >&2; cat /tmp/dev.log >&2; exit 1 | |
| # Must precede qa: a page serving no client JS passes most of qa's checks. | |
| # SITE_URL is set explicitly rather than relying on the default, so the port | |
| # is stated in one place next to the server that binds it. | |
| - name: Smoke (is client JS actually alive?) | |
| run: npm run smoke | |
| env: | |
| SITE_URL: http://localhost:3000 | |
| - name: Accessibility and layout sweep | |
| run: npm run qa | |
| env: | |
| SITE_URL: http://localhost:3000 | |
| # Feature-by-feature across engines: the frosted plate, container queries, the | |
| # lh unit, color-mix, token alpha, the full-bleed band, fonts resolving rather | |
| # than falling back, and hydration. | |
| - name: Cross-engine audit | |
| run: npm run browsers | |
| env: | |
| SITE_URL: http://localhost:3000 | |
| - name: Upload QA report on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: qa-report | |
| path: web/study/qa/ | |
| if-no-files-found: ignore |