1919 runs-on : ubuntu-24.04
2020 timeout-minutes : 5
2121 outputs :
22- audit : ${{ steps.scope.outputs.audit }}
23- audit_app_generators : ${{ steps.scope.outputs.audit_app_generators }}
24- audit_browser_driver : ${{ steps.scope.outputs.audit_browser_driver }}
25- audit_doc_runtime : ${{ steps.scope.outputs.audit_doc_runtime }}
26- audit_expo : ${{ steps.scope.outputs.audit_expo }}
27- audit_next : ${{ steps.scope.outputs.audit_next }}
28- audit_package_manager : ${{ steps.scope.outputs.audit_package_manager }}
29- audit_parquet_viewer : ${{ steps.scope.outputs.audit_parquet_viewer }}
30- audit_python : ${{ steps.scope.outputs.audit_python }}
31- audit_root : ${{ steps.scope.outputs.audit_root }}
32- audit_skill_runtime : ${{ steps.scope.outputs.audit_skill_runtime }}
3322 base_sha : ${{ steps.scope.outputs.base_sha }}
3423 code : ${{ steps.scope.outputs.code }}
3524 global_code : ${{ steps.scope.outputs.global_code }}
4534 with :
4635 fetch-depth : 0
4736 ref : ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
37+
4838 - name : Validate pull request title
4939 if : github.event_name == 'pull_request'
5040 env :
@@ -53,20 +43,18 @@ jobs:
5343 python3 - <<'PY'
5444 import os
5545 import re
56- import sys
5746
5847 title = os.environ["PR_TITLE"]
5948 pattern = re.compile(
6049 r"(?:build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)"
6150 r"(?:\([a-z0-9][a-z0-9._/-]*\))?!?: \S.*"
6251 )
6352 if len(title) > 72 or pattern.fullmatch(title) is None:
64- print(
65- "Pull request titles must use Conventional Commits and be at most 72 characters.",
66- file=sys.stderr,
53+ raise SystemExit(
54+ "Pull request titles must use Conventional Commits and be at most 72 characters."
6755 )
68- raise SystemExit(1)
6956 PY
57+
7058 - name : Classify changed files
7159 id : scope
7260 env :
@@ -103,16 +91,6 @@ jobs:
10391 root_code="$force_global"
10492 skills=false
10593 workflow=false
106- audit_root=false
107- audit_expo=false
108- audit_next=false
109- audit_python=false
110- audit_app_generators=false
111- audit_browser_driver=false
112- audit_doc_runtime=false
113- audit_package_manager=false
114- audit_parquet_viewer=false
115- audit_skill_runtime=false
11694 knip_browser_driver=false
11795 knip_skill_runtime=false
11896
12199 .github/actions/* | .github/workflows/*)
122100 workflow=true
123101 ;;
124- esac
125-
126- case "$file" in
127102 apps/* | packages/*)
128103 if [[ "$file" != *.md ]]; then code=true; fi
129104 ;;
@@ -155,72 +130,16 @@ jobs:
155130 esac
156131
157132 case "$file" in
158- pnpm-lock.yaml)
159- audit_root=true
160- ;;
161- infra/containers/sandbox/app-templates/expo/package.json | infra/containers/sandbox/app-templates/expo/pnpm-lock.yaml)
162- audit_expo=true
163- ;;
164- infra/containers/sandbox/app-templates/next/package.json | infra/containers/sandbox/app-templates/next/pnpm-lock.yaml)
165- audit_next=true
166- ;;
167- infra/containers/sandbox/requirements.txt)
168- audit_python=true
169- ;;
170- infra/containers/sandbox/app-generators/package.json | infra/containers/sandbox/app-generators/package-lock.json)
171- audit_app_generators=true
172- ;;
173133 infra/containers/sandbox/browser-driver/*)
174134 knip_browser_driver=true
175- case "$file" in
176- */package.json | */package-lock.json) audit_browser_driver=true ;;
177- esac
178- ;;
179- infra/containers/sandbox/doc-runtime/package.json | infra/containers/sandbox/doc-runtime/package-lock.json)
180- audit_doc_runtime=true
181- ;;
182- infra/containers/sandbox/package-manager/package.json | infra/containers/sandbox/package-manager/package-lock.json)
183- audit_package_manager=true
184- ;;
185- infra/containers/sandbox/extension-overrides/parquet-viewer/package.json | infra/containers/sandbox/extension-overrides/parquet-viewer/package-lock.json)
186- audit_parquet_viewer=true
187135 ;;
188136 infra/containers/sandbox/skill-runtime/*)
189137 knip_skill_runtime=true
190- case "$file" in
191- */package.json | */package-lock.json) audit_skill_runtime=true ;;
192- esac
193138 ;;
194139 esac
195140 done < <(git diff --name-only --diff-filter=ACMR -z "$base_sha" "$head_sha")
196141
197- audit=false
198- for value in \
199- "$audit_root" \
200- "$audit_expo" \
201- "$audit_next" \
202- "$audit_python" \
203- "$audit_app_generators" \
204- "$audit_browser_driver" \
205- "$audit_doc_runtime" \
206- "$audit_package_manager" \
207- "$audit_parquet_viewer" \
208- "$audit_skill_runtime"; do
209- if [ "$value" = true ]; then audit=true; break; fi
210- done
211-
212142 {
213- echo "audit=$audit"
214- echo "audit_app_generators=$audit_app_generators"
215- echo "audit_browser_driver=$audit_browser_driver"
216- echo "audit_doc_runtime=$audit_doc_runtime"
217- echo "audit_expo=$audit_expo"
218- echo "audit_next=$audit_next"
219- echo "audit_package_manager=$audit_package_manager"
220- echo "audit_parquet_viewer=$audit_parquet_viewer"
221- echo "audit_python=$audit_python"
222- echo "audit_root=$audit_root"
223- echo "audit_skill_runtime=$audit_skill_runtime"
224143 echo "base_sha=$base_sha"
225144 echo "code=$code"
226145 echo "global_code=$global_code"
@@ -248,71 +167,6 @@ jobs:
248167 shellcheck : true
249168 version : 1.7.12
250169
251- dependency-audit :
252- name : Dependency audit
253- needs : changes
254- if : needs.changes.outputs.audit == 'true'
255- runs-on : ubuntu-24.04
256- timeout-minutes : 20
257- steps :
258- - uses : actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
259- - name : Set up Node for npm lockfile audits
260- if : >-
261- needs.changes.outputs.audit_app_generators == 'true' ||
262- needs.changes.outputs.audit_browser_driver == 'true' ||
263- needs.changes.outputs.audit_doc_runtime == 'true' ||
264- needs.changes.outputs.audit_package_manager == 'true' ||
265- needs.changes.outputs.audit_parquet_viewer == 'true' ||
266- needs.changes.outputs.audit_skill_runtime == 'true'
267- uses : actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
268- with :
269- node-version : 22.22.2
270- - name : Set up uv for Python lockfile audit
271- if : needs.changes.outputs.audit_python == 'true'
272- uses : astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
273- with :
274- enable-cache : false
275- version : 0.11.28
276- - name : Set up Trivy for pnpm lockfile audits
277- if : >-
278- needs.changes.outputs.audit_root == 'true' ||
279- needs.changes.outputs.audit_expo == 'true' ||
280- needs.changes.outputs.audit_next == 'true'
281- uses : aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1
282- with :
283- cache : true
284- version : v0.72.0
285- - name : Audit root pnpm lockfile
286- if : needs.changes.outputs.audit_root == 'true'
287- run : trivy fs --scanners vuln --include-dev-deps --severity MEDIUM,HIGH,CRITICAL --exit-code 1 pnpm-lock.yaml
288- - name : Audit Expo template lockfile
289- if : needs.changes.outputs.audit_expo == 'true'
290- run : trivy fs --scanners vuln --include-dev-deps --severity MEDIUM,HIGH,CRITICAL --exit-code 1 infra/containers/sandbox/app-templates/expo
291- - name : Audit Next.js template lockfile
292- if : needs.changes.outputs.audit_next == 'true'
293- run : trivy fs --scanners vuln --include-dev-deps --severity MEDIUM,HIGH,CRITICAL --exit-code 1 infra/containers/sandbox/app-templates/next
294- - name : Audit sandbox Python lockfile
295- if : needs.changes.outputs.audit_python == 'true'
296- run : uvx --from pip-audit==2.10.1 pip-audit --disable-pip -r infra/containers/sandbox/requirements.txt
297- - name : Audit app generator lockfile
298- if : needs.changes.outputs.audit_app_generators == 'true'
299- run : npm --prefix infra/containers/sandbox/app-generators audit --audit-level=moderate
300- - name : Audit browser driver lockfile
301- if : needs.changes.outputs.audit_browser_driver == 'true'
302- run : npm --prefix infra/containers/sandbox/browser-driver audit --audit-level=moderate
303- - name : Audit document runtime lockfile
304- if : needs.changes.outputs.audit_doc_runtime == 'true'
305- run : npm --prefix infra/containers/sandbox/doc-runtime audit --audit-level=moderate
306- - name : Audit package manager lockfile
307- if : needs.changes.outputs.audit_package_manager == 'true'
308- run : npm --prefix infra/containers/sandbox/package-manager audit --audit-level=moderate
309- - name : Audit Parquet viewer overlay lockfile
310- if : needs.changes.outputs.audit_parquet_viewer == 'true'
311- run : npm --prefix infra/containers/sandbox/extension-overrides/parquet-viewer audit --audit-level=moderate
312- - name : Audit skill runtime lockfile
313- if : needs.changes.outputs.audit_skill_runtime == 'true'
314- run : npm --prefix infra/containers/sandbox/skill-runtime audit --audit-level=moderate
315-
316170 code-checks :
317171 name : Affected code checks
318172 needs : changes
@@ -330,6 +184,7 @@ jobs:
330184 fetch-depth : 0
331185 ref : ${{ needs.changes.outputs.head_sha }}
332186 - uses : ./.github/actions/setup-repository
187+
333188 - name : Resolve dependency-aware workspace scope
334189 id : workspace-scope
335190 run : |
@@ -344,9 +199,11 @@ jobs:
344199 scope="$(pnpm exec turbo run build "${filters[@]}" --dry-run=json)"
345200 echo "packages=$(jq --compact-output '[.packages[] | select(. != "//")] | unique' <<< "$scope")" >> "$GITHUB_OUTPUT"
346201 echo "directories=$(jq --compact-output '[.tasks[].directory] | unique' <<< "$scope")" >> "$GITHUB_OUTPUT"
202+
347203 - name : Lint all files under a changed global configuration
348204 if : needs.changes.outputs.global_code == 'true'
349205 run : pnpm lint
206+
350207 - name : Lint changed non-workspace files
351208 if : needs.changes.outputs.global_code != 'true' && needs.changes.outputs.nonworkspace_code == 'true'
352209 run : |
@@ -362,6 +219,7 @@ jobs:
362219 if [ "${#lintable[@]}" -gt 0 ]; then
363220 pnpm exec biome check --error-on-warnings --no-errors-on-unmatched "${lintable[@]}"
364221 fi
222+
365223 - name : Lint, typecheck, and build affected workspaces
366224 if : steps.workspace-scope.outputs.packages != '[]'
367225 env :
@@ -382,9 +240,11 @@ jobs:
382240 fi
383241 fi
384242 pnpm exec turbo run lint typecheck build "${filters[@]}"
243+
385244 - name : Typecheck operational scripts
386245 if : needs.changes.outputs.root_code == 'true'
387246 run : pnpm typecheck:scripts
247+
388248 - name : Check affected architecture boundaries
389249 if : steps.workspace-scope.outputs.directories != '[]'
390250 env :
@@ -397,6 +257,7 @@ jobs:
397257 --ts-config tsconfig.base.json \
398258 --exclude '(^|/)(dist|\.next|\.turbo|node_modules)/' \
399259 "${directories[@]}"
260+
400261 - name : Check dead code
401262 env :
402263 KNIP_BROWSER_DRIVER : ${{ needs.changes.outputs.knip_browser_driver }}
@@ -426,7 +287,7 @@ jobs:
426287
427288 static-checks :
428289 name : static-checks
429- needs : [changes, workflow-lint, dependency-audit, code-checks]
290+ needs : [changes, workflow-lint, code-checks]
430291 if : always()
431292 runs-on : ubuntu-24.04
432293 timeout-minutes : 5
@@ -435,15 +296,10 @@ jobs:
435296 env :
436297 CHANGES_RESULT : ${{ needs.changes.result }}
437298 CODE_RESULT : ${{ needs.code-checks.result }}
438- DEPENDENCY_AUDIT_RESULT : ${{ needs.dependency-audit.result }}
439299 WORKFLOW_LINT_RESULT : ${{ needs.workflow-lint.result }}
440300 run : |
441301 set -Eeuo pipefail
442- for result in \
443- "$CHANGES_RESULT" \
444- "$CODE_RESULT" \
445- "$DEPENDENCY_AUDIT_RESULT" \
446- "$WORKFLOW_LINT_RESULT"; do
302+ for result in "$CHANGES_RESULT" "$CODE_RESULT" "$WORKFLOW_LINT_RESULT"; do
447303 case "$result" in
448304 success | skipped) ;;
449305 *) exit 1 ;;
0 commit comments