Findings from a CI audit (2026-09-16 → 09-23). #15 (layer cache) is complementary and not repeated here.
1. Prune the JDK matrix
matrix.json lists JDK 17, 21, 22, 23, 24, 25, 26 × Node 22, 24 × 2 arches, so 28 image builds + 14 manifest merges per deploy, and 9–10 legs per PR. Open PR #14 adds 27 (32 builds). JDK 22, 23 and 24 are out of support. Keeping LTS (17, 21, 25) plus the default (26) gives 16 builds, ≈ 40 % less deploy time, and fewer images to pull on each host redeploy.
2. Bake what consumers compile against; drop what they don't
- The image ships
platforms;android-36.1, but the Gradle consumers use compileSdk 37. AGP downloads platform 37 at build time into the container filesystem, not a volume, so it is lost on every container recreate and re-downloaded by the first job afterwards.
- The image ships NDK 30 + cmake 3.22.1 (several GB). No consumer uses
externalNativeBuild or the NDK today. Make it opt-in (a separate -ndk tag), or drop it.
check-sdk-updates never proposed platform 37, although consumers had moved to it. It should track the highest platform that any stable build-tools supports.
3. check-sdk-updates PRs never get CI
The weekly job opens and force-pushes its PR with GITHUB_TOKEN, so build.yml never runs on it. Both PR builds this week needed a manual re-run (attempt 2), and #14 has been open since 09-14. Opening and pushing with the org App token (actions/create-github-app-token) fixes this.
4. Outlier worth a look
One PR re-run had the JDK 17 leg's build step at 27 min, while the other 9 legs took 79–101 s. It is most likely an sdkmanager download stall. A timeout-minutes on the build step, plus a retry around sdkmanager, would stop a single leg from holding the PR for half an hour.
5. Shared Gradle dependencies across runners (bigger change, optional)
Each runner has its own runner-gradle-N volume, so dependencies download 3× and a build-cache hit only happens on the machine that built it. Options:
- a read-only dependency cache seeded nightly (
GRADLE_RO_DEP_CACHE);
- a Gradle build-cache node on the host (
docker run gradle/build-cache-node) that runners point to via an init script.
LRU-evicting individual files out of modules-2 (as cleanup.sh does) can also leave metadata pointing at deleted artifacts. Evicting whole files-2.1/<group> directories would be safer.
Estimated benefit
- (1) ≈ 40 % shorter deploys.
- (2) several GB smaller image, faster host redeploys, and no post-redeploy SDK download.
- (3) removes manual re-runs.
- (5) ~2–3× higher cross-runner build-cache hit rate (to be measured).
Filed by an automated CI/CD scout.
Findings from a CI audit (2026-09-16 → 09-23). #15 (layer cache) is complementary and not repeated here.
1. Prune the JDK matrix
matrix.jsonlists JDK 17, 21, 22, 23, 24, 25, 26 × Node 22, 24 × 2 arches, so 28 image builds + 14 manifest merges per deploy, and 9–10 legs per PR. Open PR #14 adds 27 (32 builds). JDK 22, 23 and 24 are out of support. Keeping LTS (17, 21, 25) plus the default (26) gives 16 builds, ≈ 40 % less deploy time, and fewer images to pull on each host redeploy.2. Bake what consumers compile against; drop what they don't
platforms;android-36.1, but the Gradle consumers use compileSdk 37. AGP downloads platform 37 at build time into the container filesystem, not a volume, so it is lost on every container recreate and re-downloaded by the first job afterwards.externalNativeBuildor the NDK today. Make it opt-in (a separate-ndktag), or drop it.check-sdk-updatesnever proposed platform 37, although consumers had moved to it. It should track the highest platform that any stable build-tools supports.3.
check-sdk-updatesPRs never get CIThe weekly job opens and force-pushes its PR with
GITHUB_TOKEN, sobuild.ymlnever runs on it. Both PR builds this week needed a manual re-run (attempt 2), and #14 has been open since 09-14. Opening and pushing with the org App token (actions/create-github-app-token) fixes this.4. Outlier worth a look
One PR re-run had the JDK 17 leg's build step at 27 min, while the other 9 legs took 79–101 s. It is most likely an sdkmanager download stall. A
timeout-minuteson the build step, plus a retry aroundsdkmanager, would stop a single leg from holding the PR for half an hour.5. Shared Gradle dependencies across runners (bigger change, optional)
Each runner has its own
runner-gradle-Nvolume, so dependencies download 3× and a build-cache hit only happens on the machine that built it. Options:GRADLE_RO_DEP_CACHE);docker run gradle/build-cache-node) that runners point to via an init script.LRU-evicting individual files out of
modules-2(ascleanup.shdoes) can also leave metadata pointing at deleted artifacts. Evicting wholefiles-2.1/<group>directories would be safer.Estimated benefit
Filed by an automated CI/CD scout.