From 5a8943374604049d3956947cb025f5f24381f66e Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Fri, 21 Aug 2026 12:11:11 +0200 Subject: [PATCH] Cache the crates, not the 30 GB of build output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same leak we just closed on JellyTau, fed harder from here. `target/` is 30 GB locally (25G debug, 3.1G android, 2.9G release) and was cached under two keys across five jobs, on the runner both repos share. - Cache registry/index, registry/cache and git/db only. registry/src is left out as well: 155 MB of .crate tarballs beats 1.1 GB extracted, and cargo re-extracts it for free. Verified that `cargo fetch` unpacks, so sync-android-sources.sh — which reads btleplug's Java backend out of registry/src before any build has run — still finds its sources. - Collapse cargo-host and cargo-android into one cargo-registry key. The split only existed to keep the two `target` dirs off each other; with target uncached, registry contents are target-independent. This also ends a silent miss: build-release's `test` and `build-linux` jobs shared cargo-host, so the test job claimed the key and build-linux's cache was never saved. - CARGO_INCREMENTAL=0. Never reused between runs, and the bulk of the 25 GB debug dir. - npm: cache ~/.npm instead of ui/node_modules. `npm ci` deletes node_modules before installing, so that entry was restored and thrown away unread. - Installer artifact retention 30d -> 7d; the tagged release carries them. Rust jobs now compile cold every run. sccache with a hard size cap is the way back if that starts to hurt. Co-Authored-By: Claude Opus 5 (1M context) --- .gitea/workflows/build-and-test.yml | 52 ++++++++++++++++----- .gitea/workflows/build-release.yml | 71 +++++++++++++++++++++-------- 2 files changed, 93 insertions(+), 30 deletions(-) diff --git a/.gitea/workflows/build-and-test.yml b/.gitea/workflows/build-and-test.yml index a33b174..50d9f8d 100644 --- a/.gitea/workflows/build-and-test.yml +++ b/.gitea/workflows/build-and-test.yml @@ -16,6 +16,8 @@ on: env: RUST_BACKTRACE: 1 CARGO_TERM_COLOR: always + # Incremental state is never reused between CI runs -- pure disk cost. + CARGO_INCREMENTAL: 0 jobs: test: @@ -31,18 +33,33 @@ jobs: - name: Cache Rust dependencies uses: actions/cache@v3 with: + # Registry only -- never `target`. That directory is ~30 GB locally + # (25G debug, 3.1G android, 2.9G release) and was cached under two + # keys, on a runner that JellyTau's builds share -- the same leak that + # filled its disk in August 2026. registry/src is left out too: cargo + # re-extracts it for free from registry/cache (155 MB of .crate + # tarballs vs 1.1 GB extracted). path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # One shared key across every job. The host/android split existed to + # stop the two `target` dirs clobbering each other; with target no + # longer cached, registry contents are target-independent and every + # job wants the same crates. First job to finish saves; the rest + # restore. + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-host- + ${{ runner.os }}-cargo-registry- - - name: Cache Node dependencies + - name: Cache npm downloads uses: actions/cache@v3 with: - path: ui/node_modules + # npm's download cache, not ui/node_modules: `npm ci` deletes + # node_modules before it installs, so the old cache was restored and + # then immediately thrown away. ~/.npm is what actually makes the + # reinstall fast. + path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('ui/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- @@ -100,13 +117,24 @@ jobs: - name: Cache Rust dependencies uses: actions/cache@v3 with: + # Registry only -- never `target`. That directory is ~30 GB locally + # (25G debug, 3.1G android, 2.9G release) and was cached under two + # keys, on a runner that JellyTau's builds share -- the same leak that + # filled its disk in August 2026. registry/src is left out too: cargo + # re-extracts it for free from registry/cache (155 MB of .crate + # tarballs vs 1.1 GB extracted). path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-android-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # One shared key across every job. The host/android split existed to + # stop the two `target` dirs clobbering each other; with target no + # longer cached, registry contents are target-independent and every + # job wants the same crates. First job to finish saves; the rest + # restore. + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-android- + ${{ runner.os }}-cargo-registry- # Cheap invariants that a compiler cannot see. Both failures are silent: # the app builds, installs, launches, and then finds no trainer. diff --git a/.gitea/workflows/build-release.yml b/.gitea/workflows/build-release.yml index fb8ec88..768735f 100644 --- a/.gitea/workflows/build-release.yml +++ b/.gitea/workflows/build-release.yml @@ -13,6 +13,8 @@ on: env: RUST_BACKTRACE: 1 CARGO_TERM_COLOR: always + # Incremental state is never reused between CI runs -- pure disk cost. + CARGO_INCREMENTAL: 0 jobs: test: @@ -27,13 +29,24 @@ jobs: - name: Cache Rust dependencies uses: actions/cache@v3 with: + # Registry only -- never `target`. That directory is ~30 GB locally + # (25G debug, 3.1G android, 2.9G release) and was cached under two + # keys, on a runner that JellyTau's builds share -- the same leak that + # filled its disk in August 2026. registry/src is left out too: cargo + # re-extracts it for free from registry/cache (155 MB of .crate + # tarballs vs 1.1 GB extracted). path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # One shared key across every job. The host/android split existed to + # stop the two `target` dirs clobbering each other; with target no + # longer cached, registry contents are target-independent and every + # job wants the same crates. First job to finish saves; the rest + # restore. + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-host- + ${{ runner.os }}-cargo-registry- - name: Install frontend dependencies run: npm --prefix ui ci @@ -60,13 +73,24 @@ jobs: - name: Cache Rust dependencies uses: actions/cache@v3 with: + # Registry only -- never `target`. That directory is ~30 GB locally + # (25G debug, 3.1G android, 2.9G release) and was cached under two + # keys, on a runner that JellyTau's builds share -- the same leak that + # filled its disk in August 2026. registry/src is left out too: cargo + # re-extracts it for free from registry/cache (155 MB of .crate + # tarballs vs 1.1 GB extracted). path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # One shared key across every job. The host/android split existed to + # stop the two `target` dirs clobbering each other; with target no + # longer cached, registry contents are target-independent and every + # job wants the same crates. First job to finish saves; the rest + # restore. + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-host- + ${{ runner.os }}-cargo-registry- - name: Install frontend dependencies run: npm --prefix ui ci @@ -93,7 +117,7 @@ jobs: with: name: bikecontrol-linux path: dist/linux/ - retention-days: 30 + retention-days: 7 build-arch: name: Build Arch package @@ -127,7 +151,7 @@ jobs: with: name: bikecontrol-arch path: dist/arch/ - retention-days: 30 + retention-days: 7 build-android: name: Build Android APK @@ -147,13 +171,24 @@ jobs: - name: Cache Rust dependencies uses: actions/cache@v3 with: + # Registry only -- never `target`. That directory is ~30 GB locally + # (25G debug, 3.1G android, 2.9G release) and was cached under two + # keys, on a runner that JellyTau's builds share -- the same leak that + # filled its disk in August 2026. registry/src is left out too: cargo + # re-extracts it for free from registry/cache (155 MB of .crate + # tarballs vs 1.1 GB extracted). path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-android-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # One shared key across every job. The host/android split existed to + # stop the two `target` dirs clobbering each other; with target no + # longer cached, registry contents are target-independent and every + # job wants the same crates. First job to finish saves; the rest + # restore. + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-android- + ${{ runner.os }}-cargo-registry- - name: Install frontend dependencies run: npm --prefix ui ci @@ -210,7 +245,7 @@ jobs: with: name: bikecontrol-android path: dist/android/ - retention-days: 30 + retention-days: 7 create-release: name: Create release