3636 production_matrix : ${{ steps.classify.outputs.production_matrix }}
3737 test_matrix : ${{ steps.classify.outputs.test_matrix }}
3838 test_packages : ${{ steps.classify.outputs.test_packages }}
39+ typecheck_packages : ${{ steps.classify.outputs.typecheck_packages }}
3940 steps :
4041 - name : Checkout code
4142 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
@@ -214,9 +215,9 @@ jobs:
214215 --health-interval 5s
215216 --health-timeout 5s
216217 --health-retries 10
217- # The desktop executor uses Redis.
218+ # Desktop inbox and Project Files use Redis.
218219 redis :
219- image : redis:8.2-alpine
220+ image : ${{ (matrix.group == 'desktop-inbox' || matrix.group == 'project-files') && ' redis:8.2-alpine' || '' }}
220221 ports :
221222 - 6379:6379
222223 options : >-
@@ -228,6 +229,7 @@ jobs:
228229 DATABASE_URL : postgresql://postgres:postgres@127.0.0.1:5432/sim_test
229230 BETTER_AUTH_SECRET : http-e2e-ci-secret-at-least-32-characters
230231 E2E_APP_SERVER : start
232+ PROJECT_FILES_E2E_APP_SERVER : start
231233 ENCRYPTION_KEY : ' 0000000000000000000000000000000000000000000000000000000000000000'
232234
233235 steps :
@@ -241,6 +243,7 @@ jobs:
241243
242244 # Migrations create their own extensions, as on a fresh self-hosted install.
243245 - name : Provision the database through migrations
246+ if : matrix.group != 'project-files'
244247 working-directory : packages/db
245248 run : bun run db:migrate
246249
@@ -262,6 +265,17 @@ jobs:
262265 apps/sim/.next/prerender-manifest.json > /dev/null ||
263266 { echo "::error::The build prerendered posts (a hosted build) or has no prerender manifest."; exit 1; }
264267
268+ # JOBS=4 caps node-gyp parallelism as docker/app.Dockerfile does (laverdet/isolated-vm#428).
269+ - name : Build native isolate addon for Project file rendering
270+ if : matrix.group == 'project-files'
271+ working-directory : apps/sim
272+ env :
273+ JOBS : 4
274+ run : |
275+ addon_dir="$(node -p 'require("node:path").dirname(require.resolve("isolated-vm/package.json", { paths: ["."] }))')"
276+ cd "$addon_dir"
277+ bun run install
278+
265279 # No step timeout: the job's bound covers a hang without cutting a slow but healthy suite
266280 # short of writing its report.
267281 - name : Run end-to-end suites
@@ -286,7 +300,7 @@ jobs:
286300 if-no-files-found : ignore
287301 retention-days : 7
288302
289- # Browser and Project Files suites reuse the production build, avoiding dev-route compiles.
303+ # Browser suites reuse the production build, avoiding dev-route compiles.
290304 # Each job has its own database and runtime flags; the build reads public env at startup.
291305 # Each browser partitions the full viewport list across two shards, including future additions.
292306 #
@@ -316,15 +330,6 @@ jobs:
316330 --health-interval 5s
317331 --health-timeout 5s
318332 --health-retries 10
319- redis :
320- image : ${{ matrix.group == 'project-files' && 'redis:8.2-alpine' || '' }}
321- ports :
322- - 6379:6379
323- options : >-
324- --health-cmd "redis-cli ping"
325- --health-interval 5s
326- --health-timeout 5s
327- --health-retries 10
328333 env :
329334 DATABASE_URL : postgresql://postgres:postgres@127.0.0.1:5432/sim_test
330335 BETTER_AUTH_SECRET : http-e2e-ci-secret-at-least-32-characters
@@ -338,11 +343,11 @@ jobs:
338343 # setup action's caches.
339344 - &checkout-mirror
340345 name : Checkout code (mirror)
341- if : github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
346+ if : (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
342347 uses : useblacksmith/checkout@25227e61ff9dafe400e22fa487b673eac4e4409a # v1.8.1
343348 - &checkout-plain
344349 name : Checkout code
345- if : github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
350+ if : (vars.CI_PROVIDER != '' && vars.CI_PROVIDER != 'blacksmith') || github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
346351 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
347352
348353
@@ -352,30 +357,17 @@ jobs:
352357 provider : ${{ vars.CI_PROVIDER }}
353358
354359 - name : Provision the database through migrations
355- if : matrix.group != 'project-files'
356360 working-directory : packages/db
357361 run : bun run db:migrate
358362
359363 - *download-e2e-build
360364 - *extract-e2e-build
361365
362- # JOBS=4 caps node-gyp parallelism as docker/app.Dockerfile does (laverdet/isolated-vm#428).
363- - name : Build native isolate addon for Project file rendering
364- if : matrix.group == 'project-files'
365- working-directory : apps/sim
366- env :
367- JOBS : 4
368- run : |
369- addon_dir="$(node -p 'require("node:path").dirname(require.resolve("isolated-vm/package.json", { paths: ["."] }))')"
370- cd "$addon_dir"
371- bun run install
372-
373366 - name : Run end-to-end suites
374367 working-directory : apps/sim
375368 env :
376369 MOBILE_E2E_BROWSER : ${{ matrix.browser }}
377370 MOBILE_E2E_SHARD : ${{ matrix.shard }}
378- PROJECT_FILES_E2E_APP_SERVER : start
379371 run : bash ../../.github/scripts/http-e2e.sh "${{ matrix.group }}"
380372
381373 - name : Upload end-to-end reports and server logs
@@ -397,13 +389,14 @@ jobs:
397389 retention-days : 7
398390
399391 # Desktop tools exercise the real Electron app against the shared production build.
392+ # Hosted 4-vCPU runs passed both shards within 14 seconds of 8-vCPU; production peak ~4 GB.
400393 # Two runners: the lease-lapse test sleeps through a long import and then a lease (~3 min), as
401394 # long as the rest of the spec together, so on one runner it set the time for every run.
402395 desktop-live :
403396 name : desktop-live (${{ matrix.tests }})
404397 needs : [changes, e2e-build]
405398 if : needs.changes.outputs.desktop_live == 'true'
406- runs-on : ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu -ubuntu-2404' || 'ubuntu-latest' }}
399+ runs-on : ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu -ubuntu-2404' || 'ubuntu-latest' }}
407400 timeout-minutes : 30
408401 strategy :
409402 fail-fast : false
@@ -557,6 +550,7 @@ jobs:
557550 # kept off the test shards so neither waits on the other.
558551 lint :
559552 name : lint
553+ needs : changes
560554 runs-on : &runner-4vcpu ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
561555 timeout-minutes : 15
562556
@@ -569,16 +563,14 @@ jobs:
569563 # Worth stating because the failure was invisible for so long: the migration
570564 # audit read the resulting `git diff` failure as "no migrations changed" and
571565 # exited 0, so it had never actually run on a push build.
572- # Same mirror/plain split as the integration job's checkout.
573- - &checkout-mirror-depth2
574- name : Checkout code (mirror)
575- if : github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
566+ # Same provider/trust split as the build jobs' checkout.
567+ - name : Checkout code (mirror)
568+ if : (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
576569 uses : useblacksmith/checkout@25227e61ff9dafe400e22fa487b673eac4e4409a # v1.8.1
577570 with :
578571 fetch-depth : 2
579- - &checkout-plain-depth2
580- name : Checkout code
581- if : github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
572+ - name : Checkout code
573+ if : (vars.CI_PROVIDER != '' && vars.CI_PROVIDER != 'blacksmith') || github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
582574 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
583575 with :
584576 fetch-depth : 2
@@ -689,14 +681,23 @@ jobs:
689681 - name : Migration safety (zero-downtime) audit
690682 run : bun run check:migrations "${{ steps.audit_base.outputs.ref }}"
691683
692- # Every workspace, not just realtime. packages/emcn, packages/utils,
684+ # Every affected workspace, following the same real task graph as tests. Root/unknown
685+ # changes select all. packages/emcn, packages/utils,
693686 # apps/desktop and apps/docs had no type check in CI at all; apps/sim's
694687 # source was covered only as a side effect of `next build` in the separate
695688 # `build` job. This does NOT cover apps/sim's tests — its tsconfig
696689 # excludes *.test.ts(x), which carry ~2.2k errors; the `test-types` job
697690 # ratchets those per file instead.
698- - name : Type-check all workspaces
699- run : bunx turbo run type-check
691+ - name : Type-check affected workspaces
692+ env :
693+ TYPECHECK_PACKAGES : ${{ needs.changes.outputs.typecheck_packages }}
694+ run : |
695+ jq -e 'type == "array" and all(.[]; type == "string")' <<< "$TYPECHECK_PACKAGES" > /dev/null
696+ filters=()
697+ while IFS= read -r package; do filters+=("--filter=$package"); done < <(jq -r '.[]' <<< "$TYPECHECK_PACKAGES")
698+ if [ "${#filters[@]}" -gt 0 ]; then
699+ bunx turbo run type-check "${filters[@]}"
700+ fi
700701
701702 - name : Check schema and migrations are in sync
702703 working-directory : packages/db
@@ -754,21 +755,29 @@ jobs:
754755 name : test (${{ matrix.shard }}/${{ needs.changes.outputs.test_app == 'true' && '2' || '1' }})
755756 needs : changes
756757 if : needs.changes.outputs.test == 'true'
757- runs-on : ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest ' }}
758+ runs-on : ${{ needs.changes.outputs.test_app == 'true' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04 ' }}
758759 timeout-minutes : 15
759760 strategy :
760761 fail-fast : false
761762 matrix : ${{ fromJSON(needs.changes.outputs.test_matrix) }}
762763
763764
764765 steps :
765- - *checkout-mirror-depth2
766- - *checkout-plain-depth2
766+ - name : Checkout code (mirror)
767+ if : needs.changes.outputs.test_app == 'true' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork
768+ uses : useblacksmith/checkout@25227e61ff9dafe400e22fa487b673eac4e4409a # v1.8.1
769+ with :
770+ fetch-depth : 2
771+ - name : Checkout code
772+ if : needs.changes.outputs.test_app != 'true' || (vars.CI_PROVIDER != '' && vars.CI_PROVIDER != 'blacksmith') || github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
773+ uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
774+ with :
775+ fetch-depth : 2
767776
768777 - name : Setup workspace
769778 uses : ./.github/actions/setup
770779 with :
771- provider : ${{ vars.CI_PROVIDER }}
780+ provider : ${{ needs.changes.outputs.test_app != 'true' && 'github' || vars.CI_PROVIDER }}
772781 turbo-cache-key : turbo-cache-test-${{ matrix.shard }}
773782
774783 # cloud-review-tools.test.ts runs the real helper on the runner, which shells
@@ -805,6 +814,7 @@ jobs:
805814 run : |
806815 if [ "$SHARD" = 1 ]; then
807816 bun run test:scripts
817+ jq -e 'type == "array" and all(.[]; type == "string")' <<< "$TEST_PACKAGES" > /dev/null
808818 filters=()
809819 while IFS= read -r package; do filters+=("--filter=$package"); done < <(jq -r '.[]' <<< "$TEST_PACKAGES")
810820 if [ "${#filters[@]}" -gt 0 ]; then
@@ -971,6 +981,8 @@ jobs:
971981 steps :
972982 - name : Checkout code
973983 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
984+ with :
985+ sparse-checkout : .github/scripts
974986 - name : Require every check to pass
975987 env :
976988 NEEDS : ${{ toJSON(needs) }}
0 commit comments