chore: upgrade to agp 9 and configure parallelism - #1127
Conversation
Greptile SummaryThe PR upgrades the Android build toolchain and replaces internal AGP output mutation with public artifact-copy tasks.
Confidence Score: 4/5The stale-bundle cleanup issue should be fixed before merging because a normal local release after a version bump can retain and publish an older AAB alongside the current one. The APK collector removes prior APKs, but the corresponding bundle collector only overwrites its current version-specific filename while downstream release logic accepts every AAB in the shared variant directory. Files Needing Attention: app/build.gradle.kts, .github/workflows/release.yml
|
| Filename | Overview |
|---|---|
| app/build.gradle.kts | Migrates variant configuration and artifact publication to public AGP APIs, but the bundle collector leaves stale versioned AABs in its shared output directory. |
| .github/workflows/release.yml | Redirects release verification and collection to the new output directory and consumes every matching artifact found there. |
| .github/workflows/release-internal.yml | Redirects internal APK verification and publication to the deterministic collected outputs. |
| gradle/libs.versions.toml | Updates the AGP, KSP, Hilt, and Kotlin test dependency versions for the new toolchain. |
| gradle.properties | Consolidates daemon, parallelism, caching, and configuration-cache settings. |
| app/src/test/java/to/bitkit/build/BuildOutputContractTest.kt | Adds static build-contract coverage for the migration and artifact-consumer paths. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Build[assemble / bundle variant] --> AGP[AGP artifact producer]
AGP --> APK[CollectBitkitApks]
AGP --> AAB[CollectBitkitBundle]
APK --> Output[outputs/bitkit/variant]
AAB --> Output
Output --> Local[Justfile consumers]
Output --> E2E[E2E workflows]
Output --> Release[Release verification and publication]
Reviews (1): Last reviewed commit: "chore: upgrade to agp 9 and configure pa..." | Re-trigger Greptile
| val target = outputFile.get().asFile | ||
| target.parentFile.mkdirs() | ||
|
|
||
| Files.copy( | ||
| bundleFile.get().asFile.toPath(), | ||
| target.toPath(), | ||
| StandardCopyOption.REPLACE_EXISTING, | ||
| ) |
There was a problem hiding this comment.
Stale bundles remain publishable
When versionCode changes and just release runs without cleaning, this task writes the new version-specific AAB without removing the previous one, causing the release workflow's wildcard collection to checksum and publish both bundles.
| val target = outputFile.get().asFile | |
| target.parentFile.mkdirs() | |
| Files.copy( | |
| bundleFile.get().asFile.toPath(), | |
| target.toPath(), | |
| StandardCopyOption.REPLACE_EXISTING, | |
| ) | |
| val target = outputFile.get().asFile | |
| target.parentFile.mkdirs() | |
| target.parentFile.listFiles { file -> file.extension == "aab" }?.forEach { it.delete() } | |
| Files.copy( | |
| bundleFile.get().asFile.toPath(), | |
| target.toPath(), | |
| StandardCopyOption.REPLACE_EXISTING, | |
| ) |
|
The PR description records that “the release artifact, signature, symbol and checksum validation is unverified” because “the checked-in A local
The existing stale-AAB collector behavior still permits older versioned AABs to enter checksum and publication, so it remains the blocking review item. |
Closes #1114
Refs #1113
This PR moves the build to the AGP
9.3.0/ Gradle9.5.0toolchain, replaces the internal AGP variant integrations with public artifact APIs, and declares task and Tooling API parallelism in the repo.Description
Consumes the Kotlin
2.3.21baseline landed in #1115 and touches AGP, Gradle, KSP and Hilt only. AGP 9 built-in Kotlin cannot compile Kotlin2.2.21, which is why the language upgrade went first.Artifact collection publishes copies and leaves AGP's own outputs untouched, instead of renaming in place the way the removed legacy variant hook did. Each copy task is registered as a finalizer of the artifact's final producer, so
assembleandbundleemit them with no new task name for CI to call, and the bundle copy is taken after signing. The task types sit in the app build file rather than a separate build-logic project, matching the single-module layout.The catalog keeps the Compose stability analyzer at the
0.7.5selected in #1115.0.8.0pulls AGP9.3.1onto the plugin classpath, so the effective AGP would stop matching the pinned9.3.0.9.3.0, the Gradle wrapper to9.5.0, KSP to2.3.10and Hilt to2.60.1.kotlin-androidplugin and moves compiler configuration to the top-level Kotlin compiler-options DSL, keeping JVM11and the existing language flag.resValuesbuild feature, since AGP 9 disables it by default and all three flavors set the app name throughresValue.android.nonFinalResIds=false, which AGP 9 deprecates with a default oftrue.buildConfigFielddeclarations with the public variant API. The environment andlocal.propertiesreads become lazy providers, so they are tracked configuration-cache inputs instead of eager configuration-time reads.app/build/outputs/bitkit/<variant>/under the establishedbitkit-{flavor}-{buildType}-{versionCode}-{abi}.apkandbitkit-{flavor}-{buildType}-{versionCode}.aabnames, with the ABI and version code read from artifact metadata.just run, the E2E and release workflows,README.mdand the release command doc at the collected outputs.kotlin("test")with an explicitkotlin-test-junitcatalog entry. Built-in Kotlin does not inject the version or select the JUnit variant, and without this the whole test source set fails to compile.gradle.propertiesdiff on every sync.1.23.8. It runs clean on Gradle9.5.0with no new findings.One acceptance criterion is open. The release artifact, signature, symbol and checksum validation is unverified: the checked-in
google-services.jsonhas noto.bitkitclient, so mainnet stops at the release Google Services task, and NDK28.1.13356709is not installed here. The dev release bundle covers the same collection path, andjust releaseneeds a run on a machine with both.Preview
N/A
QA Notes
Manual Tests
gradle.propertiesdiff.regression:Wallet → Send → Amount → Confirm: the dev build installed from the new output directory behaves as before.regression:just run→ dev app installs and launches on a device fromapp/build/outputs/bitkit/devDebug/.just releaseon a machine with the mainnetgoogle-services.jsonand NDK28.1.13356709→ APK, AAB, native symbols, signatures and checksums all validate under the established names.regression:release workflow run → publication picks up the collected APK and AAB and the build number parses from the file name (after merge).regression:E2E workflow run → the universal APK glob resolves under the collected outputs (after merge).Automated Checks
BuildOutputContractTest.kt: asserts no internal or legacy AGP variant APIs and nokotlin-androidplugin remain, both artifact listeners are wired, all nine generatedBuildConfigfields are still declared per variant, the five parallelism properties appear exactly once, and every artifact consumer reads the collected outputs.NativeReleaseConfigTest.ktpasses unchanged, so the native debug symbol paths and the release recipe are untouched.just compile,just test,just lintandjust buildpass on the merged chore: update kotlin and compose bom #1115 baseline. detekt reports 11 findings, the same pre-existing set as master, none in the changed files.BuildConfigwas diffed fordevDebug,tnetReleaseandmainnetReleaseagainst the AGP 8 baseline and every field matches, including the per-flavor network and the 16 locale tags. Environment overrides for the E2E, geo and Paykit flags still apply and invalidate the configuration cache.assembleDevDebugemits all fourbitkit-dev-debug-187-*APKs andbundleDevReleaseemitsbitkit-dev-release-187.aab, both alongside AGP's untouched default-named outputs. Deleting the collected directory and rebuilding recreates it.9.5.0on launcher JVM17, effective AGP9.3.0,build --dry-runresolves 426 tasks across all six variants, two consecutive runs reuse the configuration cache, and the only remaining deprecation is raised by detekt rather than this repo.just test android, local E2E,actionlint. The four edited workflows parse as YAML.