-
Notifications
You must be signed in to change notification settings - Fork 3
188 lines (159 loc) · 7.05 KB
/
Copy pathci.yml
File metadata and controls
188 lines (159 loc) · 7.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
name: CI
on:
push:
pull_request:
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build and gates
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Check out the content submodule
env:
CONTENT_DEPLOY_KEY: ${{ secrets.CONTENT_DEPLOY_KEY }}
run: |
if [ -z "$CONTENT_DEPLOY_KEY" ]; then
echo "::error::CI cannot read src/content, so no collection would have any entries."
echo "src/content is a git submodule pointing at michaeljolley/content, which is"
echo "private. The default GITHUB_TOKEN is scoped to this repository only and"
echo "cannot clone another one."
echo ""
echo "Fix, once, by hand:"
echo " 1. ssh-keygen -t ed25519 -C 'baldbeardedbuilder.com CI' -f content-ci -N ''"
echo " 2. On michaeljolley/content, Settings, Deploy keys, Add deploy key."
echo " Paste content-ci.pub. Leave write access UNCHECKED, a build only reads."
echo " 3. On this repository, save the private half, the whole content-ci file"
echo " including its BEGIN and END lines, as the secret CONTENT_DEPLOY_KEY."
echo " 4. Delete both local files. GitHub keeps the only copies that matter."
echo ""
echo "A deploy key rather than a token on purpose. A token expires and is tied to"
echo "a person, so it brings this same failure back later without warning."
echo ""
echo "This job fails rather than building without content, because an empty"
echo "collection set makes every gate below pass for the wrong reason."
exit 1
fi
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# printf rather than echo, because a key is worthless if its final newline is lost.
printf '%s\n' "$CONTENT_DEPLOY_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -t rsa,ecdsa,ed25519 github.com >> ~/.ssh/known_hosts 2>/dev/null
git submodule update --init --depth 1 src/content
if [ ! -f src/content/content.config.ts ]; then
echo "::error::src/content was cloned but content.config.ts is not in it."
exit 1
fi
echo "src/content present, $(find src/content -name '*.md' | wc -l) markdown files."
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
# Fails if a generated artifact was hand edited. themes.css, the font CSS, the
# taxonomy map and _redirects are all outputs, never inputs.
- name: Generated artifacts are in sync
run: pnpm gen:check
- name: Unit and redirect tests
run: pnpm test
# The baseline was trimmed to the two legacy tables v2 actually reads, so a
# migration leaning on something that went would only fail on a db push against
# a fresh project, which is the worst place to find out.
- name: Migration chain is self contained
run: pnpm check:migrations
# Catches the class of mistake that a build will happily ship: a Supabase column
# that changed shape under a query, a nullable view column read as if it were not.
- name: Types
run: pnpm check
- name: Build
run: pnpm build
# The step above is the first thing in this job that produces dist, and four tests
# in redirects.build.test.mjs need it. They were only in the run above, before the
# build, so they skipped on every run and reported green while asserting nothing.
# Run again here, where dist exists. REQUIRE_DIST turns the skip into a failure, so
# this cannot quietly stop working again if the steps are ever reordered.
- name: Redirect tests against the real build
run: pnpm test
env:
REQUIRE_DIST: '1'
# Reads the built output rather than the source, because the sitemap and the
# Pagefind index are generated and so are never reviewed by a person. Catches a
# parked route that still ships, and any page listed in the sitemap whose own
# markup says noindex.
- name: Shipped output
run: pnpm check:dist
# In this job rather than the browser one because it needs no browser, and it reads
# source as well as dist so server handlers and conditional states are covered too.
- name: Published addresses
run: pnpm check:emails
# Both browser gates need dist, and a build is slow enough that handing it over
# beats building it three times.
- name: Upload dist
uses: actions/upload-artifact@v7
with:
name: dist
path: dist
retention-days: 3
a11y:
name: Accessibility and layout
runs-on: ubuntu-latest
needs: build
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: actions/download-artifact@v8
with:
name: dist
path: dist
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm a11y
# Rides along in this job because it is the only one that pays for a browser, and
# installing chromium twice to run a second thirty second check is not worth it.
# Different question from accessibility, same requirement: a laid out page.
- name: Layout geometry
run: pnpm check:layout
# Counts intents rather than measuring anything, so it is its own step: a doubled
# count has no visible symptom, and a failure here should not read as a layout one.
- name: Share intents
run: pnpm check:share
# Separate from the accessibility job on purpose. axe only reports a missing id when
# the element needed a name to be usable, so this catches a class that job is right
# to stay quiet about, and a failure here should not read as an axe one.
- name: Id references
run: pnpm check:aria
# Rides along here because it needs a browser and a built dist. Sixteen themes times
# five heading levels is 96 computed colors, and the failure being guarded is a
# heading that reads as body text or as a link rather than one that looks broken.
- name: Prose heading color
run: pnpm check:headings
perf:
name: Performance budget
runs-on: ubuntu-latest
needs: build
timeout-minutes: 30
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
- uses: actions/download-artifact@v8
with:
name: dist
path: dist
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm perf