Cache mobile typechecks and overlap CI setup (#28192)

* ci: run mobile runtime test groups on separate runners

* ci: use a lightweight runner for the mobile result gate

* ci: distribute Bun tests across both mobile runners

* ci: reuse mobile compiler state without adding runner queues

* test: verify eviction of source variants in one cache bucket

* test: baseline existing serializer limits in the capacity capture
This commit is contained in:
Neil
2026-10-13 03:35:51 -07:00
committed by GitHub
parent 2cbb71963c
commit fba7b753ec
13 changed files with 224 additions and 24 deletions
@@ -26,6 +26,7 @@ describe('CI dependency download caches', () => {
const mobile = workflow('mobile').jobs.verify.steps.find((step) =>
step.uses?.includes('install-node-dependencies')
)
expect(mobile.with['cache-pnpm-store']).toBe('false')
expect(mobile.with['cache-dependency-path'].trim().split('\n')).toEqual([
'pnpm-lock.yaml',
'mobile/pnpm-lock.yaml'
@@ -91,11 +91,11 @@ it('overlaps both typechecks with tests and collects their failures before the s
const waits = steps.filter((step) => step.wait !== undefined)
expect(waits).toHaveLength(1)
const [wait] = waits
expect(wait.wait).toEqual(['production-types', 'test-types'])
expect(wait.wait).toEqual(['production-types', 'test-types', 'ruby-tools'])
expect(wait.if).toBeUndefined()
expect(steps.indexOf(wait)).toBeGreaterThan(test)
expect(steps.indexOf(wait)).toBeLessThan(summary)
for (const id of wait.wait) {
for (const id of ['production-types', 'test-types']) {
const step = steps.find((candidate) => candidate.id === id)
expect(step.background).toBe(true)
expect(step['continue-on-error']).toBeUndefined()
@@ -104,4 +104,10 @@ it('overlaps both typechecks with tests and collects their failures before the s
expect(steps.indexOf(step)).toBeLessThan(test)
expect(step.run).toMatch(/^node /)
}
const ruby = steps.find((step) => step.id === 'ruby-tools')
expect(ruby.uses).toBe('ruby/setup-ruby@v1')
expect(ruby.background).toBe(true)
expect(ruby.if).toBe("steps.ruby-scope.outputs.should_run != 'false'")
expect(ruby['continue-on-error']).toBeUndefined()
expect(steps.indexOf(ruby)).toBeLessThan(install)
})
@@ -0,0 +1,41 @@
import { readFileSync } from 'node:fs'
import { expect, it } from 'vitest'
import { parse } from 'yaml'
it('reuses compiler state without skipping validation, and seeds it from main', () => {
const workflow = parse(readFileSync('.github/workflows/mobile.yml', 'utf8'))
for (const job of [workflow.jobs.verify, workflow.jobs['main-tests']]) {
expect(job.env.ORCA_MOBILE_TYPECHECK_CACHE_DIR).toBe(
'${{ github.workspace }}/mobile/.cache/typechecks'
)
const steps = job.steps
const cache = steps.find((step) => step.name === 'Cache mobile typecheck state')
expect(cache.uses).toBe('actions/cache@v5')
expect(cache.with.path).toBe('mobile/.cache/typechecks/*.tsbuildinfo')
expect(cache.with.key).toBe(`${cache.with['restore-keys']}${'${{ github.sha }}'}`)
for (const input of [
'runner.os',
'runner.arch',
'pnpm-lock.yaml',
'mobile/pnpm-lock.yaml',
'mobile/tsconfig*.json'
]) {
expect(cache.with['restore-keys']).toContain(input)
}
const install = steps.findIndex((step) => step.name === 'Install dependencies')
const wait = steps.find((step) => step.wait)
for (const id of ['production-types', 'test-types']) {
const check = steps.find((step) => step.id === id)
expect(check.if).toBeUndefined()
expect(check.background).toBe(true)
expect(check['continue-on-error']).toBeUndefined()
expect(steps.indexOf(cache)).toBeGreaterThan(install)
expect(steps.indexOf(cache)).toBeLessThan(steps.indexOf(check))
expect(wait.wait).toContain(id)
expect(steps.indexOf(wait)).toBeGreaterThan(steps.indexOf(check))
}
expect(steps.find((step) => step.id === 'production-types').run).toContain(
'--incremental --tsBuildInfoFile "$ORCA_MOBILE_TYPECHECK_CACHE_DIR/production.tsbuildinfo"'
)
}
})