diff --git a/.github/actions/portable-build-cache/action.yml b/.github/actions/portable-build-cache/action.yml new file mode 100644 index 0000000000..0fb8903c12 --- /dev/null +++ b/.github/actions/portable-build-cache/action.yml @@ -0,0 +1,40 @@ +name: Portable build cache +description: Reuse Turbo build outputs without serializing verification jobs. +inputs: + save: + description: Save newly built outputs after the job succeeds. + default: "false" +runs: + using: composite + steps: + - name: Resolve portable build task hashes + id: plan + shell: bash + env: + BUILD_CACHE_PREFIX: rea-portable-build-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.npmrc') }} + run: | + npm run --silent test:prepare -- --dry=json | + node --input-type=module -e ' + import { createHash } from "node:crypto"; + import { readFileSync } from "node:fs"; + const { tasks } = JSON.parse(readFileSync(0, "utf8")); + const hashes = tasks.map(({ taskId, hash }) => { + if (typeof hash !== "string") + throw new Error(`Build task ${taskId} must have an eager Turbo hash`); + return `${taskId}:${hash}`; + }).sort(); + const hash = createHash("sha256").update(hashes.join("\n")).digest("hex"); + console.log(`key=${process.env.BUILD_CACHE_PREFIX}-${hash}`); + ' >> "$GITHUB_OUTPUT" + - name: Restore portable build outputs + if: inputs.save != 'true' + uses: actions/cache/restore@v4 + with: + path: .turbo/cache/ + key: ${{ steps.plan.outputs.key }} + - name: Restore and save portable build outputs + if: inputs.save == 'true' + uses: actions/cache@v4 + with: + path: .turbo/cache/ + key: ${{ steps.plan.outputs.key }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccb36d5b22..bc2e7e28fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,6 +145,10 @@ jobs: node-version-file: .nvmrc cache: npm - run: npm ci + - name: Reuse portable build outputs across runs + uses: ./.github/actions/portable-build-cache + with: + save: "true" - run: npm run test:prepare - name: Find successful default-branch timing history id: history diff --git a/.github/workflows/real-binary-layout.yml b/.github/workflows/real-binary-layout.yml index 687f7a4b59..e8c244de6c 100644 --- a/.github/workflows/real-binary-layout.yml +++ b/.github/workflows/real-binary-layout.yml @@ -32,6 +32,7 @@ jobs: node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Acquire exact upstream libraries in an isolated runner environment shell: bash run: | diff --git a/.github/workflows/real-browser.yml b/.github/workflows/real-browser.yml index 0f380c0d2b..76ba2e4a63 100644 --- a/.github/workflows/real-browser.yml +++ b/.github/workflows/real-browser.yml @@ -22,9 +22,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 24 + node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - run: npm run verify:browser env: REA_BROWSER_EXECUTABLE: /usr/bin/google-chrome diff --git a/.github/workflows/real-evm-interface.yml b/.github/workflows/real-evm-interface.yml index 6ea22c20c0..9e4cddeb4f 100644 --- a/.github/workflows/real-evm-interface.yml +++ b/.github/workflows/real-evm-interface.yml @@ -26,6 +26,7 @@ jobs: node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Acquire unchanged fixture compiler in isolated runner storage shell: bash run: | diff --git a/.github/workflows/real-javascript-recovery.yml b/.github/workflows/real-javascript-recovery.yml index 52488eb539..4fee667d85 100644 --- a/.github/workflows/real-javascript-recovery.yml +++ b/.github/workflows/real-javascript-recovery.yml @@ -24,9 +24,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 24 + node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Fetch pinned Wakaru release into the job workspace shell: bash run: | diff --git a/.github/workflows/real-recorded-crash.yml b/.github/workflows/real-recorded-crash.yml index ef6696c466..d4410bb241 100644 --- a/.github/workflows/real-recorded-crash.yml +++ b/.github/workflows/real-recorded-crash.yml @@ -29,6 +29,7 @@ jobs: node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Install GDB on the disposable CI runner shell: bash run: | diff --git a/.github/workflows/real-web-network-captures.yml b/.github/workflows/real-web-network-captures.yml index 004677d8fb..b888674f78 100644 --- a/.github/workflows/real-web-network-captures.yml +++ b/.github/workflows/real-web-network-captures.yml @@ -28,6 +28,7 @@ jobs: - name: Use pinned package manager run: npm install --global npm@11.16.0 - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Acquire fixed upstream native profile in runner temporary storage shell: bash run: | diff --git a/.github/workflows/real-web-runtime.yml b/.github/workflows/real-web-runtime.yml index 8a307d524b..c600e895cc 100644 --- a/.github/workflows/real-web-runtime.yml +++ b/.github/workflows/real-web-runtime.yml @@ -17,9 +17,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 24 + node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - run: npm run verify:browser:runtime env: REA_BROWSER_EXECUTABLE: /usr/bin/google-chrome diff --git a/.github/workflows/real-web-source-map.yml b/.github/workflows/real-web-source-map.yml index dff9780247..483b2f7125 100644 --- a/.github/workflows/real-web-source-map.yml +++ b/.github/workflows/real-web-source-map.yml @@ -17,9 +17,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 24 + node-version-file: .nvmrc cache: npm - run: npm ci + - uses: ./.github/actions/portable-build-cache - name: Install the pinned compiler into an isolated fixture directory run: npm install --prefix "$RUNNER_TEMP/rea-web-source-map-compiler" --no-audit --no-fund --package-lock=false esbuild@0.25.10 - run: npm run verify:browser:source-maps diff --git a/docs/testing.md b/docs/testing.md index 0ffec90400..3fa490e4f7 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1015,6 +1015,13 @@ summary. Static checks, documentation, build, package verification, and real-system lanes remain separate jobs so one kind of evidence cannot stand in for another. +The build job saves portable Turbo outputs across runs. Eight Linux real-system +lanes restore this cache without waiting for the build job. The shared action +derives its key from `test:prepare --dry=json` task hashes, runner OS and +architecture, and `.npmrc`; test-only changes can reuse compiled outputs. Every +build and verification command still runs, so Turbo checks task inputs and +rebuilds misses. There is no prefix fallback to accumulate older build outputs. + Native package jobs reuse the same workflow's Turbo cache for portable compiled JavaScript, skills, and catalogs. They retain the normal build and prepack commands, which restore matching outputs or rebuild on a cache miss. Native