Skip to content

Commit 7ff142d

Browse files
authored
chore: speed-up pipeline (#5812)
Speed-up pipeline by: * Decoupling tests and clippy * Use pre-built binary in tests * `sccache` for caching of the builds
1 parent 4a42c4e commit 7ff142d

File tree

3 files changed

+378
-73
lines changed

3 files changed

+378
-73
lines changed

.github/workflows/rust-ci.yml

Lines changed: 253 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
# CI builds in debug (dev) for faster signal.
1010

1111
jobs:
12-
# --- Detect what changed (always runs) -------------------------------------
12+
# --- Detect what changed to detect which tests to run (always runs) -------------------------------------
1313
changed:
1414
name: Detect changed areas
1515
runs-on: ubuntu-24.04
@@ -84,8 +84,8 @@ jobs:
8484
run: cargo shear
8585

8686
# --- CI to validate on different os/targets --------------------------------
87-
lint_build_test:
88-
name: ${{ matrix.runner }} - ${{ matrix.target }}${{ matrix.profile == 'release' && ' (release)' || '' }}
87+
lint_build:
88+
name: Lint/Build — ${{ matrix.runner }} - ${{ matrix.target }}${{ matrix.profile == 'release' && ' (release)' || '' }}
8989
runs-on: ${{ matrix.runner }}
9090
timeout-minutes: 30
9191
needs: changed
@@ -94,6 +94,11 @@ jobs:
9494
defaults:
9595
run:
9696
working-directory: codex-rs
97+
env:
98+
# Speed up repeated builds across CI runs by caching compiled objects.
99+
RUSTC_WRAPPER: sccache
100+
CARGO_INCREMENTAL: "0"
101+
SCCACHE_CACHE_SIZE: 10G
97102

98103
strategy:
99104
fail-fast: false
@@ -159,20 +164,83 @@ jobs:
159164
~/.cargo/registry/index/
160165
~/.cargo/registry/cache/
161166
~/.cargo/git/db/
162-
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}
167+
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('codex-rs/rust-toolchain.toml') }}
168+
restore-keys: |
169+
cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-
163170
164-
- name: Restore target cache (except gnu-dev)
165-
id: cache_target_restore
166-
if: ${{ !(matrix.target == 'x86_64-unknown-linux-gnu' && matrix.profile != 'release') }}
171+
# Install and restore sccache cache
172+
- name: Install sccache
173+
uses: taiki-e/install-action@0c5db7f7f897c03b771660e91d065338615679f4 # v2
174+
with:
175+
tool: sccache
176+
version: 0.7.5
177+
178+
- name: Configure sccache backend
179+
shell: bash
180+
run: |
181+
set -euo pipefail
182+
if [[ -n "${ACTIONS_CACHE_URL:-}" && -n "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then
183+
echo "SCCACHE_GHA_ENABLED=true" >> "$GITHUB_ENV"
184+
echo "Using sccache GitHub backend"
185+
else
186+
echo "SCCACHE_GHA_ENABLED=false" >> "$GITHUB_ENV"
187+
echo "SCCACHE_DIR=${{ github.workspace }}/.sccache" >> "$GITHUB_ENV"
188+
echo "Using sccache local disk + actions/cache fallback"
189+
fi
190+
191+
- name: Restore sccache cache (fallback)
192+
if: ${{ env.SCCACHE_GHA_ENABLED != 'true' }}
193+
id: cache_sccache_restore
167194
uses: actions/cache/restore@v4
168195
with:
169-
path: ${{ github.workspace }}/codex-rs/target/
170-
key: cargo-target-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}
196+
path: ${{ github.workspace }}/.sccache/
197+
key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ github.run_id }}
198+
restore-keys: |
199+
sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-
200+
sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-
201+
202+
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
203+
name: Prepare APT cache directories (musl)
204+
shell: bash
205+
run: |
206+
set -euo pipefail
207+
sudo mkdir -p /var/cache/apt/archives /var/lib/apt/lists
208+
sudo chown -R "$USER:$USER" /var/cache/apt /var/lib/apt/lists
209+
210+
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
211+
name: Restore APT cache (musl)
212+
id: cache_apt_restore
213+
uses: actions/cache/restore@v4
214+
with:
215+
path: |
216+
/var/cache/apt
217+
key: apt-${{ matrix.runner }}-${{ matrix.target }}-v1
171218

172219
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
173220
name: Install musl build tools
221+
env:
222+
DEBIAN_FRONTEND: noninteractive
223+
shell: bash
224+
run: |
225+
set -euo pipefail
226+
sudo apt-get -y update -o Acquire::Retries=3
227+
sudo apt-get -y install --no-install-recommends musl-tools pkg-config
228+
229+
- name: Install cargo-chef
230+
if: ${{ matrix.profile == 'release' }}
231+
uses: taiki-e/install-action@0c5db7f7f897c03b771660e91d065338615679f4 # v2
232+
with:
233+
tool: cargo-chef
234+
version: 0.1.71
235+
236+
- name: Pre-warm dependency cache (cargo-chef)
237+
if: ${{ matrix.profile == 'release' }}
238+
shell: bash
174239
run: |
175-
sudo apt install -y musl-tools pkg-config && sudo rm -rf /var/lib/apt/lists/*
240+
set -euo pipefail
241+
RECIPE="${RUNNER_TEMP}/chef-recipe.json"
242+
cargo chef prepare --recipe-path "$RECIPE"
243+
cargo chef cook --recipe-path "$RECIPE" --target ${{ matrix.target }} --release --all-features
176244
177245
- name: cargo clippy
178246
id: clippy
@@ -191,22 +259,158 @@ jobs:
191259
find . -name Cargo.toml -mindepth 2 -maxdepth 2 -print0 \
192260
| xargs -0 -n1 -I{} bash -c 'cd "$(dirname "{}")" && cargo check --profile ${{ matrix.profile }}'
193261
262+
# Save caches explicitly; make non-fatal so cache packaging
263+
# never fails the overall job. Only save when key wasn't hit.
264+
- name: Save cargo home cache
265+
if: always() && !cancelled() && steps.cache_cargo_home_restore.outputs.cache-hit != 'true'
266+
continue-on-error: true
267+
uses: actions/cache/save@v4
268+
with:
269+
path: |
270+
~/.cargo/bin/
271+
~/.cargo/registry/index/
272+
~/.cargo/registry/cache/
273+
~/.cargo/git/db/
274+
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('codex-rs/rust-toolchain.toml') }}
275+
276+
- name: Save sccache cache (fallback)
277+
if: always() && !cancelled() && env.SCCACHE_GHA_ENABLED != 'true'
278+
continue-on-error: true
279+
uses: actions/cache/save@v4
280+
with:
281+
path: ${{ github.workspace }}/.sccache/
282+
key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ github.run_id }}
283+
284+
- name: sccache stats
285+
if: always()
286+
continue-on-error: true
287+
run: sccache --show-stats || true
288+
289+
- name: sccache summary
290+
if: always()
291+
shell: bash
292+
run: |
293+
{
294+
echo "### sccache stats — ${{ matrix.target }} (${{ matrix.profile }})";
295+
echo;
296+
echo '```';
297+
sccache --show-stats || true;
298+
echo '```';
299+
} >> "$GITHUB_STEP_SUMMARY"
300+
301+
- name: Save APT cache (musl)
302+
if: always() && !cancelled() && (matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl') && steps.cache_apt_restore.outputs.cache-hit != 'true'
303+
continue-on-error: true
304+
uses: actions/cache/save@v4
305+
with:
306+
path: |
307+
/var/cache/apt
308+
key: apt-${{ matrix.runner }}-${{ matrix.target }}-v1
309+
310+
# Fail the job if any of the previous steps failed.
311+
- name: verify all steps passed
312+
if: |
313+
steps.clippy.outcome == 'failure' ||
314+
steps.cargo_check_all_crates.outcome == 'failure'
315+
run: |
316+
echo "One or more checks failed (clippy or cargo_check_all_crates). See logs for details."
317+
exit 1
318+
319+
tests:
320+
name: Tests — ${{ matrix.runner }} - ${{ matrix.target }}
321+
runs-on: ${{ matrix.runner }}
322+
timeout-minutes: 30
323+
needs: changed
324+
if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }}
325+
defaults:
326+
run:
327+
working-directory: codex-rs
328+
env:
329+
RUSTC_WRAPPER: sccache
330+
CARGO_INCREMENTAL: "0"
331+
SCCACHE_CACHE_SIZE: 10G
332+
333+
strategy:
334+
fail-fast: false
335+
matrix:
336+
include:
337+
- runner: macos-14
338+
target: aarch64-apple-darwin
339+
profile: dev
340+
- runner: ubuntu-24.04
341+
target: x86_64-unknown-linux-gnu
342+
profile: dev
343+
- runner: ubuntu-24.04-arm
344+
target: aarch64-unknown-linux-gnu
345+
profile: dev
346+
- runner: windows-latest
347+
target: x86_64-pc-windows-msvc
348+
profile: dev
349+
- runner: windows-11-arm
350+
target: aarch64-pc-windows-msvc
351+
profile: dev
352+
353+
steps:
354+
- uses: actions/checkout@v5
355+
- uses: dtolnay/[email protected]
356+
with:
357+
targets: ${{ matrix.target }}
358+
359+
- name: Restore cargo home cache
360+
id: cache_cargo_home_restore
361+
uses: actions/cache/restore@v4
362+
with:
363+
path: |
364+
~/.cargo/bin/
365+
~/.cargo/registry/index/
366+
~/.cargo/registry/cache/
367+
~/.cargo/git/db/
368+
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('codex-rs/rust-toolchain.toml') }}
369+
restore-keys: |
370+
cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-
371+
372+
- name: Install sccache
373+
uses: taiki-e/install-action@0c5db7f7f897c03b771660e91d065338615679f4 # v2
374+
with:
375+
tool: sccache
376+
version: 0.7.5
377+
378+
- name: Configure sccache backend
379+
shell: bash
380+
run: |
381+
set -euo pipefail
382+
if [[ -n "${ACTIONS_CACHE_URL:-}" && -n "${ACTIONS_RUNTIME_TOKEN:-}" ]]; then
383+
echo "SCCACHE_GHA_ENABLED=true" >> "$GITHUB_ENV"
384+
echo "Using sccache GitHub backend"
385+
else
386+
echo "SCCACHE_GHA_ENABLED=false" >> "$GITHUB_ENV"
387+
echo "SCCACHE_DIR=${{ github.workspace }}/.sccache" >> "$GITHUB_ENV"
388+
echo "Using sccache local disk + actions/cache fallback"
389+
fi
390+
391+
- name: Restore sccache cache (fallback)
392+
if: ${{ env.SCCACHE_GHA_ENABLED != 'true' }}
393+
id: cache_sccache_restore
394+
uses: actions/cache/restore@v4
395+
with:
396+
path: ${{ github.workspace }}/.sccache/
397+
key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ github.run_id }}
398+
restore-keys: |
399+
sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-
400+
sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-
401+
194402
- uses: taiki-e/install-action@0c5db7f7f897c03b771660e91d065338615679f4 # v2
195403
with:
196404
tool: nextest
197405
version: 0.9.103
198406

199407
- name: tests
200408
id: test
201-
# Tests take too long for release builds to run them on every PR.
202-
if: ${{ matrix.profile != 'release' }}
203409
continue-on-error: true
204410
run: cargo nextest run --all-features --no-fail-fast --target ${{ matrix.target }} --cargo-profile ci-test
205411
env:
206412
RUST_BACKTRACE: 1
207413

208-
# Save caches explicitly; make non-fatal so cache packaging
209-
# never fails the overall job. Only save when key wasn't hit.
210414
- name: Save cargo home cache
211415
if: always() && !cancelled() && steps.cache_cargo_home_restore.outputs.cache-hit != 'true'
212416
continue-on-error: true
@@ -217,33 +421,43 @@ jobs:
217421
~/.cargo/registry/index/
218422
~/.cargo/registry/cache/
219423
~/.cargo/git/db/
220-
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}
424+
key: cargo-home-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('codex-rs/rust-toolchain.toml') }}
221425

222-
- name: Save target cache (except gnu-dev)
223-
if: >-
224-
always() && !cancelled() &&
225-
(steps.cache_target_restore.outputs.cache-hit != 'true') &&
226-
!(matrix.target == 'x86_64-unknown-linux-gnu' && matrix.profile != 'release')
426+
- name: Save sccache cache (fallback)
427+
if: always() && !cancelled() && env.SCCACHE_GHA_ENABLED != 'true'
227428
continue-on-error: true
228429
uses: actions/cache/save@v4
229430
with:
230-
path: ${{ github.workspace }}/codex-rs/target/
231-
key: cargo-target-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}
431+
path: ${{ github.workspace }}/.sccache/
432+
key: sccache-${{ matrix.runner }}-${{ matrix.target }}-${{ matrix.profile }}-${{ hashFiles('**/Cargo.lock') }}-${{ github.run_id }}
232433

233-
# Fail the job if any of the previous steps failed.
234-
- name: verify all steps passed
235-
if: |
236-
steps.clippy.outcome == 'failure' ||
237-
steps.cargo_check_all_crates.outcome == 'failure' ||
238-
steps.test.outcome == 'failure'
434+
- name: sccache stats
435+
if: always()
436+
continue-on-error: true
437+
run: sccache --show-stats || true
438+
439+
- name: sccache summary
440+
if: always()
441+
shell: bash
239442
run: |
240-
echo "One or more checks failed (clippy, cargo_check_all_crates, or test). See logs for details."
443+
{
444+
echo "### sccache stats — ${{ matrix.target }} (tests)";
445+
echo;
446+
echo '```';
447+
sccache --show-stats || true;
448+
echo '```';
449+
} >> "$GITHUB_STEP_SUMMARY"
450+
451+
- name: verify tests passed
452+
if: steps.test.outcome == 'failure'
453+
run: |
454+
echo "Tests failed. See logs for details."
241455
exit 1
242456
243457
# --- Gatherer job that you mark as the ONLY required status -----------------
244458
results:
245459
name: CI results (required)
246-
needs: [changed, general, cargo_shear, lint_build_test]
460+
needs: [changed, general, cargo_shear, lint_build, tests]
247461
if: always()
248462
runs-on: ubuntu-24.04
249463
steps:
@@ -252,7 +466,8 @@ jobs:
252466
run: |
253467
echo "general: ${{ needs.general.result }}"
254468
echo "shear : ${{ needs.cargo_shear.result }}"
255-
echo "matrix : ${{ needs.lint_build_test.result }}"
469+
echo "lint : ${{ needs.lint_build.result }}"
470+
echo "tests : ${{ needs.tests.result }}"
256471
257472
# If nothing relevant changed (PR touching only root README, etc.),
258473
# declare success regardless of other jobs.
@@ -264,4 +479,10 @@ jobs:
264479
# Otherwise require the jobs to have succeeded
265480
[[ '${{ needs.general.result }}' == 'success' ]] || { echo 'general failed'; exit 1; }
266481
[[ '${{ needs.cargo_shear.result }}' == 'success' ]] || { echo 'cargo_shear failed'; exit 1; }
267-
[[ '${{ needs.lint_build_test.result }}' == 'success' ]] || { echo 'matrix failed'; exit 1; }
482+
[[ '${{ needs.lint_build.result }}' == 'success' ]] || { echo 'lint_build failed'; exit 1; }
483+
[[ '${{ needs.tests.result }}' == 'success' ]] || { echo 'tests failed'; exit 1; }
484+
485+
- name: sccache summary note
486+
if: always()
487+
run: |
488+
echo "Per-job sccache stats are attached to each matrix job's Step Summary."

0 commit comments

Comments
 (0)