Skip to content

chore: upgrade to agp 9 and configure parallelism - #1127

Open
guzino wants to merge 1 commit into
synonymdev:masterfrom
guzino:chore/agp-9-upgrade
Open

chore: upgrade to agp 9 and configure parallelism#1127
guzino wants to merge 1 commit into
synonymdev:masterfrom
guzino:chore/agp-9-upgrade

Conversation

@guzino

@guzino guzino commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Closes #1114
Refs #1113

This PR moves the build to the AGP 9.3.0 / Gradle 9.5.0 toolchain, 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.21 baseline landed in #1115 and touches AGP, Gradle, KSP and Hilt only. AGP 9 built-in Kotlin cannot compile Kotlin 2.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 assemble and bundle emit 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.5 selected in #1115. 0.8.0 pulls AGP 9.3.1 onto the plugin classpath, so the effective AGP would stop matching the pinned 9.3.0.

  • Upgrades AGP to 9.3.0, the Gradle wrapper to 9.5.0, KSP to 2.3.10 and Hilt to 2.60.1.
  • Removes the kotlin-android plugin and moves compiler configuration to the top-level Kotlin compiler-options DSL, keeping JVM 11 and the existing language flag.
  • Enables the resValues build feature, since AGP 9 disables it by default and all three flavors set the app name through resValue.
  • Drops android.nonFinalResIds=false, which AGP 9 deprecates with a default of true.
  • Replaces the legacy buildConfigField declarations with the public variant API. The environment and local.properties reads become lazy providers, so they are tracked configuration-cache inputs instead of eager configuration-time reads.
  • Replaces the removed internal output-renaming hooks with two tasks that listen to the public APK and bundle artifacts. Copies land in app/build/outputs/bitkit/<variant>/ under the established bitkit-{flavor}-{buildType}-{versionCode}-{abi}.apk and bitkit-{flavor}-{buildType}-{versionCode}.aab names, with the ABI and version code read from artifact metadata.
  • Repoints just run, the E2E and release workflows, README.md and the release command doc at the collected outputs.
  • Replaces kotlin("test") with an explicit kotlin-test-junit catalog 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.
  • Declares the daemon, parallel, Tooling API parallel, caching and configuration-cache properties once each, which is what stops Android Studio regenerating a local gradle.properties diff on every sync.
  • Leaves detekt at 1.23.8. It runs clean on Gradle 9.5.0 with no new findings.

One acceptance criterion is open. The release artifact, signature, symbol and checksum validation is unverified: the checked-in google-services.json has no to.bitkit client, so mainnet stops at the release Google Services task, and NDK 28.1.13356709 is not installed here. The dev release bundle covers the same collection path, and just release needs a run on a machine with both.

Preview

N/A

QA Notes

Manual Tests

  • 1. Android Studio → open project: sync succeeds and leaves no local gradle.properties diff.
  • 2. regression: Wallet → Send → Amount → Confirm: the dev build installed from the new output directory behaves as before.
  • 3. regression: just run → dev app installs and launches on a device from app/build/outputs/bitkit/devDebug/.
  • 4. just release on a machine with the mainnet google-services.json and NDK 28.1.13356709 → APK, AAB, native symbols, signatures and checksums all validate under the established names.
  • 5. regression: release workflow run → publication picks up the collected APK and AAB and the build number parses from the file name (after merge).
  • 6. regression: E2E workflow run → the universal APK glob resolves under the collected outputs (after merge).

Automated Checks

  • Build contract added in BuildOutputContractTest.kt: asserts no internal or legacy AGP variant APIs and no kotlin-android plugin remain, both artifact listeners are wired, all nine generated BuildConfig fields are still declared per variant, the five parallelism properties appear exactly once, and every artifact consumer reads the collected outputs.
  • NativeReleaseConfigTest.kt passes unchanged, so the native debug symbol paths and the release recipe are untouched.
  • Local: just compile, just test, just lint and just build pass 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.
  • Generated BuildConfig was diffed for devDebug, tnetRelease and mainnetRelease against 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.
  • Artifact collection verified locally: assembleDevDebug emits all four bitkit-dev-debug-187-* APKs and bundleDevRelease emits bitkit-dev-release-187.aab, both alongside AGP's untouched default-named outputs. Deleting the collected directory and rebuilding recreates it.
  • Toolchain verified locally: Gradle 9.5.0 on launcher JVM 17, effective AGP 9.3.0, build --dry-run resolves 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.
  • Not run locally: just test android, local E2E, actionlint. The four edited workflows parse as YAML.
  • CI: standard build, unit test and detekt checks run by the PR bot. This is a fork PR, so the run needs maintainer approval before the required checks report.

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

The PR upgrades the Android build toolchain and replaces internal AGP output mutation with public artifact-copy tasks.

  • Upgrades AGP, Gradle, KSP, Hilt, and Kotlin test dependency wiring.
  • Migrates BuildConfig generation and Kotlin compiler configuration to AGP 9-compatible APIs.
  • Publishes deterministically named APK and AAB copies and redirects local, CI, release, and documentation consumers.
  • Enables Gradle task, Tooling API, cache, and configuration-cache parallelism.

Confidence Score: 4/5

The 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

Important Files Changed

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]
Loading

Reviews (1): Last reviewed commit: "chore: upgrade to agp 9 and configure pa..." | Re-trigger Greptile

Comment thread app/build.gradle.kts
Comment on lines +448 to +455
val target = outputFile.get().asFile
target.parentFile.mkdirs()

Files.copy(
bundleFile.get().asFile.toPath(),
target.toPath(),
StandardCopyOption.REPLACE_EXISTING,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Suggested change
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,
)

@ovitrif
ovitrif self-requested a review July 31, 2026 21:07
@ovitrif ovitrif self-assigned this Jul 31, 2026
@ovitrif ovitrif added this to the 2.5.0 milestone Jul 31, 2026

@ovitrif ovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One blocking release issue remains: the bundle collector can leave stale versioned AABs eligible for checksum and publication, as reported by the Greptile review bot.

@ovitrif

ovitrif commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

The PR description records that “the release artifact, signature, symbol and checksum validation is unverified” because “the checked-in google-services.json has no to.bitkit client.”

A local just release run I did at f04406e resolves that stated gap because it completes successfully with the mainnet google-services.json and the required NDK, producing the established versioned outputs:

  • None of the four APK outputs has a missing or invalid signature.
  • The AAB includes the required signature.
  • The native-symbol ZIP contains no invalid entries.
  • All eight expected Rust symbol libraries preserve .debug_info.
  • Each of the six release artifacts has the required SHA-256 checksum.

The existing stale-AAB collector behavior still permits older versioned AABs to enter checksum and publication, so it remains the blocking review item.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: upgrade to agp 9 and configure parallelism

2 participants