-
Notifications
You must be signed in to change notification settings - Fork 3
333 lines (318 loc) · 10.9 KB
/
Copy pathci.yml
File metadata and controls
333 lines (318 loc) · 10.9 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
# This GitHub Actions workflow runs the continuous-integration (CI) pipeline
# for the "modern-react-template" repository.
#
# Summary:
# - Triggers: `push` to `main` and `pull_request` events targeting `main`.
# - Concurrency: cancels in-progress runs for the same ref to avoid duplicated work.
# - Jobs include secret scanning, linting, formatting check, unit tests, build,
# end-to-end tests (Playwright + axe), and a static analysis step (Knip).
# - Artifacts: test coverage, build `dist/`, and Playwright reports are uploaded
# and retained for a short period to help debugging CI failures.
#
# Notes for newcomers:
# - Each job runs on `ubuntu-latest` and uses `actions/setup-node` (Node.js 20).
# - `HUSKY` is disabled in CI (`HUSKY: '0'`) so pre-commit hooks don't run during
# automated CI installs.
# - To run these checks locally, install deps with `npm ci` then run the script
# names used in the jobs (for example `npm run lint`, `npm run test:unit`,
# `npm run build`, `npm run test:e2e`).
# - Repository variables such as `ENABLE_GH_PAGES` and `ENABLE_JSDOC_BUILD` are
# logged by several jobs and may toggle additional CI behavior when configured
# in the repository settings.
#
# This file is heavily commented so contributors can understand when and how
# each job runs. If you change job names or add new steps, also update these
# comments so the next person can follow the CI flow.
name: CI
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
log-context:
name: Log workflow context
runs-on: ubuntu-latest
# This job centralizes logging of workflow context so it's printed once
# at the start of the run instead of repeated in every job.
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Log workflow context
run: |
echo "[CI][context] Triggered by $GITHUB_EVENT_NAME on ref $GITHUB_REF for $GITHUB_REPOSITORY"
- name: Debug Info (non-sensitive)
# Run debug-info here once per workflow run; `show-env=false` to avoid
# printing environment variables during normal CI runs.
uses: ./.github/actions/debug-info
with:
show-env: 'false'
secret-scan:
# Secret scanning: detects accidentally committed secrets using Gitleaks.
# This job is a fast safety check and will fail if secrets are found.
name: Secret Scanning (Gitleaks)
runs-on: ubuntu-latest
needs: [log-context]
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Secret Scanning
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_CONFIG: .gitleaks.toml
GITLEAKS_ENABLE_COMMENTS: false
lint:
# Lint: runs ESLint to enforce code style and catch common issues.
# Skips Husky hooks by setting HUSKY=0 and caches npm to speed up runs.
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
env:
HUSKY: '0'
needs: [log-context]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache the local npm cache to speed up `npm ci`.
# Key format: <OS>-node-<hash-of-lockfile>
# - `runner.os` isolates caches per runner OS.
# - `hashFiles('**/package-lock.json')` invalidates the cache when
# `package-lock.json` changes (i.e. dependencies changed).
# `restore-keys` provides a fallback prefix if an exact key isn't found.
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run lint
format:
# Format Check: runs Prettier in "check" mode to ensure code formatting
# matches project conventions (does not auto-fix in CI).
name: Format Check
runs-on: ubuntu-latest
permissions:
contents: read
env:
HUSKY: '0'
needs: [log-context]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache npm (same strategy as in lint): caches `~/.npm` keyed by
# OS + lockfile hash so dependency changes invalidate the cache.
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run prettier -- --check
test:
# Unit Tests: runs Vitest unit tests. For PRs it runs changed-only tests;
# on main it runs the full test suite with coverage and uploads a report.
name: Unit Tests
runs-on: ubuntu-latest
needs: [log-context, lint]
permissions:
contents: read
env:
HUSKY: '0'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache npm for tests: reuse npm cache between jobs/runs.
# To force-refresh this cache, update `package-lock.json` or change
# the cache key here (not recommended normally).
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Run changed-only unit tests for PR
if: github.event_name == 'pull_request'
run: |
echo "Running changed-only unit tests for PR"
npm run test:unit -- --changed
- name: Run full unit tests with coverage
if: github.event_name != 'pull_request'
run: |
echo "Running full unit tests with coverage"
npm run test:coverage
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
retention-days: 7
build:
# Build: creates the production build (Vite). The built `dist/` is uploaded
# as an artifact so it can be inspected if a release or further checks need it.
name: Build
runs-on: ubuntu-latest
needs: [log-context, test]
permissions:
contents: read
env:
HUSKY: '0'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache npm for build job. Same key pattern; helps avoid repeated
# package downloads during `npm ci`.
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Cache Vite build cache
uses: actions/cache@v4
with:
# Cache Vite build artifacts to speed up subsequent builds.
# Key includes both the lockfile and `vite.config.ts` so config
# changes also invalidate the cache.
path: |
node_modules/.vite
.vite
key: ${{ runner.os }}-vite-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/vite.config.ts') }}
restore-keys: |
${{ runner.os }}-vite-
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1
e2e:
# E2E Tests: runs Playwright end-to-end tests and accessibility checks
# (axe). Playwright browsers are installed explicitly and results are
# uploaded as artifacts for debugging test failures.
name: E2E Tests (Playwright + Axe)
runs-on: ubuntu-latest
needs: [log-context, build]
permissions:
contents: read
env:
HUSKY: '0'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache npm for e2e job as well.
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Cache Playwright browsers and cache
uses: actions/cache@v4
with:
# Cache Playwright browser downloads and related caches. This
# avoids re-downloading large browser binaries between workflow runs.
# Keyed by lockfile hash so browser-cache invalidates on deps change.
path: |
~/.cache/ms-playwright
~/.cache/playwright
node_modules/.cache
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
knip:
# Knip: static analysis tool to find unused code and dependencies. This
# job is marked `if: always()` so it runs even when other jobs fail,
# and its output is uploaded to help maintainers clean up the codebase.
name: Knip (Unused Code Analysis)
runs-on: ubuntu-latest
permissions:
contents: read
if: always()
needs: [log-context]
env:
HUSKY: '0'
steps:
- uses: actions/checkout@v4
- name: Log workflow context
# Keep a brief log here indicating the knip job started (context already logged by `log-context`).
run: |
echo "[CI][knip] Starting Knip run"
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Cache npm
uses: actions/cache@v4
with:
# Cache npm for knip job too.
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- name: Run Knip (non-blocking)
run: npm run knip || true # Always succeed
- name: Upload Knip report
if: always()
uses: actions/upload-artifact@v4
with:
name: knip-report
path: .
retention-days: 7