From 058f54d95db0489fe0a6cd0b65f8afdd9cb160a9 Mon Sep 17 00:00:00 2001 From: Christoph Kattmann Date: Sun, 6 Sep 2026 20:36:41 +0200 Subject: [PATCH 1/4] fix(component-test): let deploy test jobs reuse the Gradle build cache [ENERGY-2742] The test job cached Gradle only through actions/setup-java's cache: 'gradle', which keys on a hash of the dependency files and, on an exact primary-key hit, does not save. The build-cache-1 inside that archive is therefore a frozen snapshot that never accumulates task outputs, so every deploy re-runs KSP and both Kotlin compiles from scratch. service-energy production deploy 2026-09-06 (run 34027976026): 'Test project' 6m33s, 'BUILD SUCCESSFUL in 6m 31s', '11 actionable tasks: 11 executed', nothing FROM-CACHE; :kspKotlin ~63s, :compileKotlin ~45s, :kspTestKotlin ~30s, :compileTestKotlin ~30s. The pull-request workflow restores the same tasks FROM-CACHE because it keys actions/cache on the commit and saves after a non-exact restore. Mirror that here: drop setup-java's cache input, restore with a per-commit key plus '-gradle-deploy-' and '-gradle-' fallbacks, and save only when the restore was not an exact hit. --- .github/workflows/component-test-kotlin.yml | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/component-test-kotlin.yml b/.github/workflows/component-test-kotlin.yml index 84a8d6a9..c8a19517 100644 --- a/.github/workflows/component-test-kotlin.yml +++ b/.github/workflows/component-test-kotlin.yml @@ -71,7 +71,22 @@ jobs: with: distribution: "corretto" java-version: ${{ inputs.java-version }} - cache: 'gradle' + # setup-java's own `cache: gradle` keys on a hash of the dependency files and skips saving on an + # exact hit, so the build-cache-1 inside it is a frozen snapshot: every deploy re-runs KSP and + # both Kotlin compiles from scratch. Key on the commit instead, like pull-request-kotlin.yml, + # and fall back to the previous deploy (and to any main-scoped Gradle cache) so task outputs + # accumulate and unchanged compilation comes back FROM-CACHE. + - name: Restore Gradle cache + id: gradle-cache + uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-deploy-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-gradle-deploy- + ${{ runner.os }}-gradle- - name: Test project env: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} @@ -93,3 +108,11 @@ jobs: /home/runner/.gradle/daemon/**/daemon-*.out.log retention-days: 2 overwrite: true + - name: Save Gradle cache + if: ${{ always() && steps.gradle-cache.outputs.cache-hit != 'true' }} + uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-deploy-${{ github.sha }} From bea2d40edfbac15c6bae82ac149415570513bdfb Mon Sep 17 00:00:00 2001 From: Christoph Kattmann Date: Sun, 4 Oct 2026 13:42:41 +0200 Subject: [PATCH 2/4] docs(component-test): explain the deploy Gradle cache key Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014AaR9VvceeKm4EFQLLHX3s --- .github/workflows/component-test-kotlin.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/component-test-kotlin.yml b/.github/workflows/component-test-kotlin.yml index 3a631b8c..51352a97 100644 --- a/.github/workflows/component-test-kotlin.yml +++ b/.github/workflows/component-test-kotlin.yml @@ -80,11 +80,8 @@ jobs: with: distribution: "corretto" java-version: ${{ inputs.java-version }} - # setup-java's own `cache: gradle` keys on a hash of the dependency files and skips saving on an - # exact hit, so the build-cache-1 inside it is a frozen snapshot: every deploy re-runs KSP and - # both Kotlin compiles from scratch. Key on the commit instead, like pull-request-kotlin.yml, - # and fall back to the previous deploy (and to any main-scoped Gradle cache) so task outputs - # accumulate and unchanged compilation comes back FROM-CACHE. + # Keyed on the commit so a production deploy restores the cache saved by the staging deploy of the same SHA. + # Falls back to the previous deploy so dependencies are still warm. - name: Restore Gradle cache id: gradle-cache uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 From f920f66ca11f6b2fd673e01108f8f9e399fb2936 Mon Sep 17 00:00:00 2001 From: Christoph Kattmann Date: Sun, 4 Oct 2026 15:37:45 +0200 Subject: [PATCH 3/4] feat(component-test): make the deploy Gradle build cache opt-in Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014AaR9VvceeKm4EFQLLHX3s --- .github/workflows/component-test-kotlin.yml | 9 ++++++++- .github/workflows/deploy-kotlin-v2.yml | 6 ++++++ .github/workflows/deploy-kotlin.yml | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/component-test-kotlin.yml b/.github/workflows/component-test-kotlin.yml index 51352a97..c428c251 100644 --- a/.github/workflows/component-test-kotlin.yml +++ b/.github/workflows/component-test-kotlin.yml @@ -38,6 +38,11 @@ on: type: string default: "--parallel --build-cache" description: 'Additional Gradle arguments' + cache-gradle-build-outputs: + required: false + type: boolean + default: false + description: "Cache Gradle task outputs per commit so a production deploy can reuse the test run of the same SHA from staging. Uses a ~1 GB cache archive per deploy." secrets: GHL_USERNAME: required: true @@ -80,10 +85,12 @@ jobs: with: distribution: "corretto" java-version: ${{ inputs.java-version }} + cache: ${{ !inputs.cache-gradle-build-outputs && 'gradle' || '' }} # Keyed on the commit so a production deploy restores the cache saved by the staging deploy of the same SHA. # Falls back to the previous deploy so dependencies are still warm. - name: Restore Gradle cache id: gradle-cache + if: ${{ inputs.cache-gradle-build-outputs }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: | @@ -115,7 +122,7 @@ jobs: retention-days: 2 overwrite: true - name: Save Gradle cache - if: ${{ always() && steps.gradle-cache.outputs.cache-hit != 'true' }} + if: ${{ always() && inputs.cache-gradle-build-outputs && steps.gradle-cache.outputs.cache-hit != 'true' }} uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 with: path: | diff --git a/.github/workflows/deploy-kotlin-v2.yml b/.github/workflows/deploy-kotlin-v2.yml index c3820996..cbfc4faa 100644 --- a/.github/workflows/deploy-kotlin-v2.yml +++ b/.github/workflows/deploy-kotlin-v2.yml @@ -56,6 +56,11 @@ on: type: string default: "--parallel --build-cache" description: 'Additional Gradle arguments' + cache-gradle-build-outputs: + required: false + type: boolean + default: false + description: "Cache Gradle task outputs per commit so the production deploy of a SHA can reuse the staging test run (~1 GB cache archive per deploy)." region: required: false type: string @@ -256,6 +261,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} java-version: ${{ inputs.java-version }} gradle-args: ${{ inputs.gradle-args }} + cache-gradle-build-outputs: ${{ inputs.cache-gradle-build-outputs }} secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} diff --git a/.github/workflows/deploy-kotlin.yml b/.github/workflows/deploy-kotlin.yml index c49b94dc..c05956c7 100644 --- a/.github/workflows/deploy-kotlin.yml +++ b/.github/workflows/deploy-kotlin.yml @@ -56,6 +56,11 @@ on: type: string default: "--parallel --build-cache" description: 'Additional Gradle arguments' + cache-gradle-build-outputs: + required: false + type: boolean + default: false + description: "Cache Gradle task outputs per commit so the production deploy of a SHA can reuse the staging test run (~1 GB cache archive per deploy)." region: required: false type: string @@ -244,6 +249,7 @@ jobs: gradle-module: ${{ inputs.gradle-module }} java-version: ${{ inputs.java-version }} gradle-args: ${{ inputs.gradle-args }} + cache-gradle-build-outputs: ${{ inputs.cache-gradle-build-outputs }} secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} From f9f6291485452fc6c04755cbedb6f834f3b152a7 Mon Sep 17 00:00:00 2001 From: Christoph Kattmann Date: Mon, 5 Oct 2026 13:46:27 +0200 Subject: [PATCH 4/4] feat(component-test): store the deploy Gradle cache on S3 on ARC Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01C1bF6Xi6hHBry6WzgP3tCN --- .github/workflows/component-test-kotlin.yml | 33 ++++++++++++++++++--- .github/workflows/deploy-kotlin-v2.yml | 2 ++ .github/workflows/deploy-kotlin.yml | 2 ++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/component-test-kotlin.yml b/.github/workflows/component-test-kotlin.yml index c428c251..116a2766 100644 --- a/.github/workflows/component-test-kotlin.yml +++ b/.github/workflows/component-test-kotlin.yml @@ -50,6 +50,12 @@ on: GHL_PASSWORD: required: true description: 'Github Password (Gradle plugin)' + GH_ACTION_ACCESS_KEY_ID: + required: false + description: "AWS access key for the S3 cache bucket, used on ARC. Without it ARC runs use the GitHub cache." + GH_ACTION_SECRET_ACCESS_KEY: + required: false + description: "AWS secret key for the S3 cache bucket, used on ARC. Without it ARC runs use the GitHub cache." permissions: contents: read @@ -77,6 +83,8 @@ jobs: needs: setup runs-on: ${{ needs.setup.outputs.runner-name }} timeout-minutes: 30 + env: + S3_CACHE: ${{ inputs.use-arc-runners && secrets.GH_ACTION_ACCESS_KEY_ID != '' }} steps: - name: Checkout uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 @@ -90,9 +98,9 @@ jobs: # Falls back to the previous deploy so dependencies are still warm. - name: Restore Gradle cache id: gradle-cache - if: ${{ inputs.cache-gradle-build-outputs }} + if: ${{ inputs.cache-gradle-build-outputs && env.S3_CACHE != 'true' }} uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5 - with: + with: &gradle-cache-restore path: | ~/.gradle/caches ~/.gradle/wrapper @@ -100,6 +108,18 @@ jobs: restore-keys: | ${{ runner.os }}-gradle-deploy- ${{ runner.os }}-gradle- + - name: Restore Gradle cache (S3) + id: gradle-cache-s3 + if: ${{ inputs.cache-gradle-build-outputs && env.S3_CACHE == 'true' }} + uses: runs-on/cache/restore@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 + env: &s3-cache-env + RUNS_ON_S3_BUCKET_CACHE: monta-github-ci-cache + RUNS_ON_RUNNER_NAME: "" + AWS_ACCESS_KEY_ID: ${{ secrets.GH_ACTION_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.GH_ACTION_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: "" + AWS_REGION: eu-west-1 + with: *gradle-cache-restore - name: Test project env: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} @@ -122,10 +142,15 @@ jobs: retention-days: 2 overwrite: true - name: Save Gradle cache - if: ${{ always() && inputs.cache-gradle-build-outputs && steps.gradle-cache.outputs.cache-hit != 'true' }} + if: ${{ always() && inputs.cache-gradle-build-outputs && env.S3_CACHE != 'true' && steps.gradle-cache.outputs.cache-hit != 'true' }} uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5 - with: + with: &gradle-cache-save path: | ~/.gradle/caches ~/.gradle/wrapper key: ${{ runner.os }}-gradle-deploy-${{ github.sha }} + - name: Save Gradle cache (S3) + if: ${{ always() && inputs.cache-gradle-build-outputs && env.S3_CACHE == 'true' && steps.gradle-cache-s3.outputs.cache-hit != 'true' }} + uses: runs-on/cache/save@88d90644011a3a9957fd141a106f5a94f9794203 # v5.0.7 + env: *s3-cache-env + with: *gradle-cache-save diff --git a/.github/workflows/deploy-kotlin-v2.yml b/.github/workflows/deploy-kotlin-v2.yml index cbfc4faa..dcf9078a 100644 --- a/.github/workflows/deploy-kotlin-v2.yml +++ b/.github/workflows/deploy-kotlin-v2.yml @@ -265,6 +265,8 @@ jobs: secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} + GH_ACTION_ACCESS_KEY_ID: ${{ secrets.GH_ACTION_ACCESS_KEY_ID }} + GH_ACTION_SECRET_ACCESS_KEY: ${{ secrets.GH_ACTION_SECRET_ACCESS_KEY }} build: name: Build uses: ./.github/workflows/component-build.yml diff --git a/.github/workflows/deploy-kotlin.yml b/.github/workflows/deploy-kotlin.yml index c05956c7..59e8b9a1 100644 --- a/.github/workflows/deploy-kotlin.yml +++ b/.github/workflows/deploy-kotlin.yml @@ -253,6 +253,8 @@ jobs: secrets: GHL_USERNAME: ${{ secrets.GHL_USERNAME }} GHL_PASSWORD: ${{ secrets.GHL_PASSWORD }} + GH_ACTION_ACCESS_KEY_ID: ${{ secrets.GH_ACTION_ACCESS_KEY_ID }} + GH_ACTION_SECRET_ACCESS_KEY: ${{ secrets.GH_ACTION_SECRET_ACCESS_KEY }} build: name: Build uses: ./.github/workflows/component-build.yml