Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Build
description: >
The static site, into ./dist.

A composite action rather than a reusable workflow so it runs in the caller's
job, under the caller's name -- CI / Build -- rather than as a nested
"caller / callee" check.

It has exactly one caller: there is no CD here, so nothing can drift from
anything. It is split out so this repository has the same shape as the rest of
the organisation, and for no stronger reason than that.

NOTHING LEAVES THE RUNNER. The site is left in ./dist for ../test to assert
against.

runs:
using: composite
steps:
# --frozen-lockfile so CI fails on a lockfile that does not match
# package.json, rather than quietly resolving something newer than what
# anyone has run locally.
- name: Install JS dependencies
shell: bash
run: bun install --frozen-lockfile

- name: Build
shell: bash
run: bun run build
37 changes: 37 additions & 0 deletions .github/actions/test/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Test
description: >
Is this commit good. Nothing is published here; a failure means the site is
wrong, not that the pipeline is.

Runs AFTER ../build, because everything it asserts is a property of ./dist. A
static site has two ways to be broken that matter -- it did not build, and it
built the wrong thing -- and only the second one needs a test.

The assertions are this site's own and differ from its siblings': how many
pages it emits, and what else has to be on them. That is the part worth
keeping per-repo.

runs:
using: composite
steps:
# A build that emits nothing still "succeeds", so the artefacts are
# checked rather than the exit code. All three pages, because a broken
# route is invisible from the index alone.
- name: Every page was actually written
shell: bash
run: |
for page in index devtools/index games/index; do
test -s "dist/$page.html" || { echo "dist/$page.html is missing or empty"; exit 1; }
done
# The point of this site is that it ships no JavaScript. Nothing else
# would notice an integration being added back, and by then the pages
# have a runtime they did not need.
- name: No JavaScript was shipped
shell: bash
run: |
if find dist -name '*.js' | grep -q .; then
echo "::error::dist contains JavaScript -- this site is meant to ship none"
find dist -name '*.js'
exit 1
fi

55 changes: 28 additions & 27 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
name: CI

# A static site has one way to be broken that matters: it does not build. That
# is the whole check.
# Every pull request and every merge to main: build, then test, on one runner.
#
# Nothing is published and nothing is deployed, so a green tick means one thing
# -- this commit is good.
#
# The push trigger is not redundant: this repository has no CD, so nothing else
# covers a merge to main.

on:
pull_request:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
Expand All @@ -16,29 +22,24 @@ concurrency:
cancel-in-progress: true

jobs:
build:
ci:
runs-on: ubuntu-latest
# Bounded, so a step that hangs fails here rather than sitting until the
# runner's own timeout hours later.
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"
- run: bun install --frozen-lockfile
- run: bun run build
# A build that emits nothing still "succeeds", so the artefacts are
# checked rather than the exit code. All three pages, because a broken
# route is invisible from the index alone.
- name: Every page was actually written
run: |
for page in index devtools/index games/index; do
test -s "dist/$page.html" || { echo "dist/$page.html is missing or empty"; exit 1; }
done
# The point of this site is that it ships no JavaScript. Nothing else
# would notice an integration being added back, and by then the pages
# have a runtime they did not need.
- name: No JavaScript was shipped
run: |
if grep -rq '<script[^>]*src=' dist/*.html dist/*/*.html; then
echo "a page loads a script — this site is meant to ship none"
exit 1
fi
# Third-party actions are pinned by SHA, with the tag in a trailing
# comment so the version is still readable.
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

# Reads .mise.toml, which is where bun's version is already pinned for
# everyone working on this repo. This used to be oven-sh/setup-bun with
# `bun-version: "1.3"` written out here -- a second place to change one
# version, and two places drift.
- uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac # v2

- name: Build
uses: ./.github/actions/build

- name: Test
uses: ./.github/actions/test
Loading