From ae566a670ad247e7be8c1ecded9f54483acd5d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Mon, 5 Oct 2026 18:33:23 +0200 Subject: [PATCH 1/4] [CI] Stop caching what the cache inventory says is not being used --- .github/workflows/codeql.yml | 5 ++++ .github/workflows/desktop-build.yml | 38 ++++++++++++++++------------ .github/workflows/docker-release.yml | 7 +++-- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 75fbc59f1..18bb5e8ed 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -51,6 +51,11 @@ jobs: # https://docs.github.com/en/code-security/reference/code-scanning/codeql/codeql-queries/actions-built-in-queries queries: security-extended dependency-caching: true + # A TRAP cache costs about 974 MiB per language here. On master that is worth + # paying, because the next push reuses it. On a pull request it is pure loss: + # the cache lands on refs/pull/N/merge, which no other run ever reads, so every + # new pull request leaves a dead 974 MiB entry behind. + trap-caching: ${{ github.event_name != 'pull_request' }} - name: "[C++] Install dependencies" if: matrix.language == 'cpp' && matrix.build-mode == 'manual' diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 098aabc4f..5b5be2280 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -168,7 +168,7 @@ jobs: continue-on-error: ${{ matrix.allow-failure == 'yes' }} timeout-minutes: 70 env: - CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} # directory for caching docker image and ccache + CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} # directory holding the build image and ccache, only the image subdir is cached below CCACHE_EVICTION_AGE: 7d CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy CMAKE_GENERATOR: 'Ninja' @@ -179,12 +179,18 @@ jobs: - name: "Checkout" uses: actions/checkout@v7 - - name: "Restore compiler cache (ccache)" - id: restore_ccache + # Only the image half of this cache is worth keeping. A compile on these legs runs + # inside a container, so ccache measures a 0.00 to 1.85 percent hit rate here against + # 49 to 50 percent on the macOS legs, and the roughly 420 MiB of ccache each entry + # carried was buying nothing. Caching $CACHE/image alone drops that. + # The key changes name because the cached content does: the old ccache- + # entries hold an image plus a ccache directory, and expire on their own untouched. + - name: "Restore build image cache" + id: restore_image_cache uses: actions/cache/restore@v6 with: - key: ccache-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} - path: ${{ env.CACHE }} + key: image-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} + path: ${{ env.CACHE }}/image - name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image" shell: bash @@ -250,24 +256,24 @@ jobs: RUN --server --release --package "$package" "${args[@]}" - # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342 - - name: "Delete remote compiler cache (ccache)" - if: github.ref == 'refs/heads/master' && steps.restore_ccache.outputs.cache-hit + # Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342 + - name: "Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342" + if: github.ref == 'refs/heads/master' && steps.restore_image_cache.outputs.cache-hit continue-on-error: true env: - CACHE_PRIMARY_KEY: ${{ steps.restore_ccache.outputs.cache-primary-key }} + CACHE_PRIMARY_KEY: ${{ steps.restore_image_cache.outputs.cache-primary-key }} GH_TOKEN: ${{ github.token }} run: | if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then echo "Cache deleted successfully" fi - - name: "Save updated compiler cache (ccache)" + - name: "Save updated build image cache" if: github.ref == 'refs/heads/master' uses: actions/cache/save@v6 with: - key: ${{ steps.restore_ccache.outputs.cache-primary-key }} - path: ${{ env.CACHE }} + key: ${{ steps.restore_image_cache.outputs.cache-primary-key }} + path: ${{ env.CACHE }}/image - name: "Upload artifact" id: upload_artifact @@ -410,7 +416,7 @@ jobs: - name: "[macOS] Restore compiler cache (ccache)" if: matrix.os == 'macOS' && matrix.use_ccache == 1 - id: restore_ccache + id: restore_image_cache uses: actions/cache/restore@v6 with: key: ccache-${{ matrix.runner }}_${{ matrix.override_target }}-Xcode${{ matrix.xcode }} @@ -519,10 +525,10 @@ jobs: # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342 - name: "[macOS] Delete remote compiler cache (ccache)" - if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.restore_ccache.outputs.cache-hit + if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.restore_image_cache.outputs.cache-hit continue-on-error: true env: - CACHE_PRIMARY_KEY: ${{ steps.restore_ccache.outputs.cache-primary-key }} + CACHE_PRIMARY_KEY: ${{ steps.restore_image_cache.outputs.cache-primary-key }} GH_TOKEN: ${{ github.token }} run: | if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then @@ -533,7 +539,7 @@ jobs: if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' uses: actions/cache/save@v6 with: - key: ${{ steps.restore_ccache.outputs.cache-primary-key }} + key: ${{ steps.restore_image_cache.outputs.cache-primary-key }} path: ${{ env.CCACHE_DIR }} - name: "[macOS] Sign app bundle" diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 937386940..b7c08d341 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -89,7 +89,10 @@ jobs: uses: docker/build-push-action@v7 with: cache-from: type=gha,scope=${{ env.CACHE_SCOPE }} - cache-to: ${{ case(github.ref == 'refs/heads/master', format('type=gha,mode=max,scope={0}', env.CACHE_SCOPE), '') }} + # mode=min exports only the layers of the final image. mode=max also exports + # every intermediate build layer, which for this multi-stage build is where the + # bulk of the 42 cached blobs came from, and none of it survives into the image. + cache-to: ${{ case(github.ref == 'refs/heads/master', format('type=gha,mode=min,scope={0}', env.CACHE_SCOPE), '') }} context: . platforms: ${{ matrix.platform }} push: false @@ -101,7 +104,7 @@ jobs: uses: docker/build-push-action@v7 with: cache-from: type=gha,scope=${{ env.CACHE_SCOPE }} - cache-to: type=gha,mode=max,scope=${{ env.CACHE_SCOPE }} + cache-to: type=gha,mode=min,scope=${{ env.CACHE_SCOPE }} context: . labels: | org.opencontainers.image.description=${{ env.OCI_DESCRIPTION }} From fb0a920223768322991dfdb1067d176282f633b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 6 Oct 2026 06:47:25 +0200 Subject: [PATCH 2/4] Fix cache step naming in macOS job per review --- .github/workflows/desktop-build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 5b5be2280..e352a1372 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -257,7 +257,7 @@ jobs: RUN --server --release --package "$package" "${args[@]}" # Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342 - - name: "Delete used cache to emulate a cache update. See https://github.com/actions/cache/issues/342" + - name: "[Linux] Delete used cache to emulate a cache update" if: github.ref == 'refs/heads/master' && steps.restore_image_cache.outputs.cache-hit continue-on-error: true env: @@ -416,7 +416,7 @@ jobs: - name: "[macOS] Restore compiler cache (ccache)" if: matrix.os == 'macOS' && matrix.use_ccache == 1 - id: restore_image_cache + id: restore_ccache uses: actions/cache/restore@v6 with: key: ccache-${{ matrix.runner }}_${{ matrix.override_target }}-Xcode${{ matrix.xcode }} @@ -525,10 +525,10 @@ jobs: # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342 - name: "[macOS] Delete remote compiler cache (ccache)" - if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.restore_image_cache.outputs.cache-hit + if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.restore_ccache.outputs.cache-hit continue-on-error: true env: - CACHE_PRIMARY_KEY: ${{ steps.restore_image_cache.outputs.cache-primary-key }} + CACHE_PRIMARY_KEY: ${{ steps.restore_ccache.outputs.cache-primary-key }} GH_TOKEN: ${{ github.token }} run: | if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then @@ -539,7 +539,7 @@ jobs: if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' uses: actions/cache/save@v6 with: - key: ${{ steps.restore_image_cache.outputs.cache-primary-key }} + key: ${{ steps.restore_ccache.outputs.cache-primary-key }} path: ${{ env.CCACHE_DIR }} - name: "[macOS] Sign app bundle" From e98b8f0c69cd4f9ae38a43838118fafa3898ced6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Sun, 11 Oct 2026 18:17:17 +0200 Subject: [PATCH 3/4] [CI] Load and save the docker image through the image cache --- .github/workflows/desktop-build.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index e352a1372..3fa4f5574 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -194,7 +194,14 @@ jobs: - name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image" shell: bash - run: source .ci/docker.sh --build + run: | + # --get/--save wire the $CACHE/image dir restored/saved above into the + # build: without them the image is rebuilt from scratch every run and + # the image cache saves nothing. Only persist on master; PR runs just + # reuse whatever the restore step found. + args=(--get --build) + [[ $GITHUB_REF == "refs/heads/master" ]] && args+=(--save) + source .ci/docker.sh "${args[@]}" - name: "Build debug and test" if: matrix.test != 'skip' From 84ed650ac0af822b293e2bbd2f3ee12f9f990df5 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 13 Oct 2026 07:17:37 +0200 Subject: [PATCH 4/4] [CI] Invalidate build image cache when Dockerfile changes --- .github/workflows/desktop-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 3fa4f5574..c532bc615 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -189,7 +189,7 @@ jobs: id: restore_image_cache uses: actions/cache/restore@v6 with: - key: image-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} + key: image-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }}-${{ hashFiles(format('.ci/{0}{1}/**', matrix.distro, matrix.version)) }} path: ${{ env.CACHE }}/image - name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image"