-
Notifications
You must be signed in to change notification settings - Fork 9
383 lines (326 loc) · 13.4 KB
/
Copy pathci.yml
File metadata and controls
383 lines (326 loc) · 13.4 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
name: CI
on:
push:
pull_request:
# Least-privilege: nothing here needs write access to the repo.
permissions:
contents: read
jobs:
# Root-level tooling only (package.json at the repo root) - none of this
# needs PHP/Composer or nuxt/'s own dependencies.
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: 2
- name: Setup Node
uses: actions/setup-node@v7
with:
# 22, not this repo's pinned 16 (or the other jobs' 20) - the
# lint tools themselves need it: cspell requires >=22.18.0,
# markdownlint-cli2 >=22, commitlint >=22.12.0. This job only
# runs root-level tooling, never touches the app's own runtime.
node-version: '22'
cache: 'npm'
- run: npm install
- name: ESLint (scripts/)
run: npm run lint:js
- name: Prettier
run: npm run lint:format
- name: cspell
run: npm run lint:cspell
- name: markdownlint
run: npm run lint:md
- name: knip (unused/unlisted dependencies)
run: npm run lint:knip
- name: npm audit (production dependencies)
run: npm run lint:audit
- name: renovate-config-validator
run: npm run lint:renovate
# This repository is public and is what people copy to start a
# site, so a URL only the author can reach is a defect in the
# published artefact, not a stray comment.
- name: Private host references
run: npm run lint:private
# Only checks the most recent commit - good enough to catch the
# common case (a single non-conforming commit message) without the
# complexity of resolving a full PR commit range.
- name: commitlint
run: npx commitlint --from HEAD~1 --to HEAD --verbose
- name: JSON sweep
run: |
rc=0; count=0
while IFS= read -r -d '' f; do
count=$((count + 1))
if python3 -m json.tool "$f" > /dev/null 2>&1; then
echo " [PASS] $f"
else
echo " [FAIL] $f"
rc=1
fi
done < <(find . -name '*.json' -not -path '*/.git/*' -not -path '*/node_modules/*' \
-not -path '*/nuxt/*' -not -path '*/drupal/*' -not -path '*/.vscode/*' -not -path '*/.devcontainer/*' -print0)
echo "--- $count JSON file(s) checked ---"
exit "$rc"
- name: Shell syntax sweep
run: |
rc=0; count=0
while IFS= read -r -d '' f; do
count=$((count + 1))
if bash -n "$f" 2>/dev/null; then
echo " [PASS] $f"
else
echo " [FAIL] $f"
rc=1
fi
done < <(find . -name '*.sh' -not -path '*/.git/*' -not -path '*/node_modules/*' \
-not -path '*/nuxt/*' -not -path '*/drupal/*' -print0)
echo "--- $count shell file(s) checked ---"
exit "$rc"
- name: yamllint
run: |
pip install yamllint -q
yamllint -d "{extends: default, rules: {line-length: {max: 200, level: warning}}}" .gitlab-ci.yml .github/workflows/ci.yml
# Prose-quality lint for README.md - see .vale.ini for scoping/exceptions.
- name: Install Vale
run: |
vale_version="3.17.1"
vale_sha256="db947f89f2292e6a0381a61de155f6a5f5cb4cb460ca178ea412ef605559cefd"
curl -sL --max-time 60 "https://github.com/vale-cli/vale/releases/download/v${vale_version}/vale_${vale_version}_Linux_64-bit.tar.gz" -o /tmp/vale.tar.gz
echo "${vale_sha256} /tmp/vale.tar.gz" | sha256sum -c - || { echo "vale checksum mismatch" >&2; exit 1; }
sudo tar -xzf /tmp/vale.tar.gz -C /usr/local/bin vale
sudo chmod +x /usr/local/bin/vale
- name: Install ai-tells style package
run: |
ai_tells_version="1.31.0"
ai_tells_sha256="bc1267248f13e65928475c439ad7ae1bf806a20d09254c08d7d8c4a9c8b811f0"
curl -sL --max-time 60 "https://github.com/tbhb/vale-ai-tells/releases/download/v${ai_tells_version}/ai-tells.zip" -o /tmp/ai-tells.zip
echo "${ai_tells_sha256} /tmp/ai-tells.zip" | sha256sum -c - || { echo "ai-tells checksum mismatch" >&2; exit 1; }
python3 -c "
import zipfile, os
with zipfile.ZipFile('/tmp/ai-tells.zip') as z:
for name in z.namelist():
if name.startswith('ai-tells/styles/') and not name.endswith('/'):
target = os.path.join('styles', name[len('ai-tells/styles/'):])
os.makedirs(os.path.dirname(target), exist_ok=True)
with open(target, 'wb') as f:
f.write(z.read(name))
"
- name: Vale
run: vale README.md
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: mbstring, pdo_sqlite, intl, gd, xml, zip, opcache
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
# setup-node v5 turned caching on by itself when package.json
# names a package manager, and keys it on the root lockfile
# alone. This job installs from nuxt/, so name both.
cache: npm
cache-dependency-path: |
package-lock.json
nuxt/package-lock.json
- name: Validate and install Composer dependencies
working-directory: drupal
run: composer validate --strict && composer install --no-interaction --no-progress
# Not `npm run build` - Druxt fetches the JSON:API index at build
# time, so building needs a live Drupal backend. That happens in
# test_e2e, via .devtools/.
- name: Install Nuxt dependencies
working-directory: nuxt
run: npm install
- name: Create .env
run: cp .env.example .env
# Lint + unit tests were ported from the old auto-running
# test-preview.yml, which is now a manual-only preview workflow.
- name: Lint code
working-directory: nuxt
run: npm run lint
- name: Run unit tests
working-directory: nuxt
run: npm run test:unit
# fail_ci_if_error is false (the old workflow had true): tokenless
# uploads for public repos are rate-limited and shouldn't fail CI on
# a starter kit. The token-less integration itself is unchanged.
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v7
with:
files: ./nuxt/coverage/clover.xml
name: codecov-umbrella
fail_ci_if_error: false
# Protected branches reject tokenless uploads ("Token required
# because branch is protected"), which is what leaves the README
# coverage badge empty. Needs a CODECOV_TOKEN repository secret.
token: ${{ secrets.CODECOV_TOKEN }}
# The root scripts run on the app's Node 16, but coverage reporting
# needs Node 20+, so the tests run on a modern Node here. They use only
# node:test and node:assert, so nothing is installed.
test_scripts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: '22'
- name: Run the script tests with coverage
run: npm run test:scripts:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v7
with:
files: ./coverage/scripts-lcov.info
name: scripts
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
test_e2e:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: mbstring, pdo_sqlite, intl, gd, xml, zip, opcache
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
# setup-node v5 turned caching on by itself when package.json
# names a package manager, and keys it on the root lockfile
# alone. This job installs from nuxt/, so name both.
cache: npm
cache-dependency-path: |
package-lock.json
nuxt/package-lock.json
- name: Assemble, provision, and start the Drupal backend
working-directory: drupal
run: |
.devtools/assemble
.devtools/provision
.devtools/start
env:
WEBSERVER_HOST: 127.0.0.1
WEBSERVER_PORT: 8888
# Anonymous JSON:API never touches OAuth, so nothing else here
# notices a consumer the backend cannot look up.
- name: OAuth consumer is recognised
run: npm run check:oauth
- name: Install Nuxt dependencies
working-directory: nuxt
run: npm install
- name: Install Cypress binary
working-directory: nuxt
run: npx cypress install
- name: Run e2e tests
working-directory: nuxt
run: npm run test:e2e
- name: Upload Cypress artifacts on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: cypress-artifacts
path: |
nuxt/cypress/screenshots
nuxt/cypress/videos
# The documented consumer flow (README: `npx giget@1 ... --install`) is
# not what the jobs above exercise - they work from the git checkout
# and call .devtools/ directly. This job consumes the same artifact a
# giget user gets: a tarball of this exact commit, no .git, no
# preinstalled dependencies - and lets the root postinstall stand the
# whole site up.
#
# `git archive` produces that tarball from the commit under test, which
# giget cannot do - it only fetches refs already pushed to GitHub.
test_consumer_install:
runs-on: ubuntu-latest
steps:
# The documented minimum, so a pass means the lock and the
# provisioning actually work there - not just on a newer PHP.
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_sqlite, intl, gd, xml, zip, opcache
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
- name: Build the tarball a giget consumer gets
run: git archive --prefix=site/ HEAD | tar -x -C /tmp
# `env -u CI`: postinstall deliberately steps aside on CI machines
# - this job's whole point is to behave like a consumer machine.
- name: Root npm install (giget's --install step)
working-directory: /tmp/site
run: env -u CI npm install
- name: Backend is up and provisioned
working-directory: /tmp/site
run: |
. ./.env
curl -sf "${BASE_URL}/jsonapi" | grep -q '"jsonapi"'
- name: OAuth consumer is recognised
working-directory: /tmp/site
run: npm run check:oauth
- name: Frontend builds against the live backend
working-directory: /tmp/site/nuxt
run: npm run build
# What the root install promises on machines without a working PHP: a
# consumer's `npm install` must never fail, `npm run setup` must
# fail loudly, and a too-old PHP must be rejected by the preflight.
test_install_guardrails:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
- name: Hide the runner's preinstalled PHP
run: while command -v php >/dev/null 2>&1; do sudo mv "$(command -v php)" "$(command -v php).hidden"; done
- name: npm install without PHP succeeds with guidance
run: |
env -u CI npm install > /tmp/install.log 2>&1
grep -q 'The backend needs PHP' /tmp/install.log
- name: npm run setup without PHP fails with guidance
run: |
if npm run setup > /tmp/setup.log 2>&1; then echo "setup should have failed"; exit 1; fi
grep -q 'Missing required tools' /tmp/setup.log
- name: Old PHP is rejected by the version preflight
run: |
SHIM=$(mktemp -d)
printf '#!/bin/sh\necho 8.2.29\n' > "$SHIM/php"
printf '#!/bin/sh\nexit 0\n' > "$SHIM/composer"
chmod +x "$SHIM/php" "$SHIM/composer"
if PATH="$SHIM:$PATH" npm run setup > /tmp/old-php.log 2>&1; then echo "setup should have failed"; exit 1; fi
grep -q 'too old' /tmp/old-php.log
# The preflight exits the process, so without postinstall screening
# the version first this is what would fail `npm install` outright.
- name: Old PHP still leaves npm install green
run: |
SHIM=$(mktemp -d)
printf '#!/bin/sh\necho 8.2.29\n' > "$SHIM/php"
printf '#!/bin/sh\nexit 0\n' > "$SHIM/composer"
chmod +x "$SHIM/php" "$SHIM/composer"
PATH="$SHIM:$PATH" env -u CI npm install > /tmp/old-php-install.log 2>&1
grep -q 'The backend needs PHP' /tmp/old-php-install.log