diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 75494dc3e..7df1f1d82 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 c97b48342..3546b69ed 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -176,7 +176,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' @@ -187,12 +187,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 }}/.ccache + key: image-${{ matrix.distro }}${{ matrix.version }}${{ matrix.variant }} + path: ${{ env.CACHE }}/image - name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image" shell: bash @@ -313,24 +319,24 @@ jobs: # comes from the client event itself (COCKATRICE_SENTRY_RELEASE). sentry-cli debug-files upload --org cockatrice --project cockatrice-desktop "${paths[@]}" - # 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: "[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: - 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 }}/.ccache + key: ${{ steps.restore_image_cache.outputs.cache-primary-key }} + path: ${{ env.CACHE }}/image - name: "Upload artifact" id: upload_artifact @@ -491,7 +497,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 }} @@ -815,10 +821,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 @@ -829,7 +835,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 }}