feat(matrix): Fetch AGP<->Kotlin compat dynamically#1166
feat(matrix): Fetch AGP<->Kotlin compat dynamically#1166
Conversation
Replace the static gradleToKotlin dict with a fetch of the AGP/Kotlin compatibility table from developer.android.com/build/kotlin-support. For each AGP version we now pick the highest Kotlin whose required AGP is <= ours, which is a more direct semantic fit and also catches new Kotlin minors automatically. The existing Kotlin->min-Gradle floor check (sourced from kotlinlang.org) stays in place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| val kotlinVersion = | ||
| agpToKotlin | ||
| .filter { (minAgp, _) -> agpVersion >= minAgp } | ||
| .maxByOrNull { it.first } |
There was a problem hiding this comment.
maxByOrNull selects by AGP instead of Kotlin version
Medium Severity
The comment says "Pick the latest Kotlin whose required AGP <= this AGP" but maxByOrNull { it.first } maximizes by the AGP component of the pair, not the Kotlin version (it.second). When two Kotlin versions share the same minimum AGP requirement (e.g., Kotlin 1.4 and 1.5 both require AGP 7.0), maxByOrNull returns the first encountered element at that tie — which is the lower Kotlin version. Selecting by it.second (the Kotlin version) would correctly pick the highest compatible Kotlin in all cases.
Reviewed by Cursor Bugbot for commit d3f7cb4. Configure here.
The developer.android.com/build/kotlin-support table lists upcoming Kotlin minors before they ship (e.g. Kotlin 2.4 with AGP 9.1.0 while only 2.4.0-Beta* is on Maven Central). Resolve each Kotlin minor to its latest stable patch by reading kotlin-stdlib's maven-metadata.xml and drop rows whose minor has no stable release yet, so the generated matrix never references an unpublished version. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KSP 2.1.0-1.0.29 is pinned to Kotlin compiler 2.1.0 and fails with "ksp-2.1.0-1.0.29 is too old for kotlin-2.3.21" when the test matrix runs the android-instrumentation-sample against newer Kotlin versions. Bump to 2.3.7, which is the latest KSP2 release — KSP2 is decoupled from the Kotlin compiler version and works across the Kotlin versions the matrix now picks from developer.android.com/build/kotlin-support. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pinned KSP (2.1.0-1.0.29, KSP1) is bound to the Kotlin 2.1 compiler and fails with "ksp is too old for kotlin-X" when the test matrix picks newer Kotlin versions from developer.android.com/build/kotlin-support. Bumping KSP directly breaks the default build because KSP2 requires Kotlin language version 2.0+, but the default Kotlin in Dependencies.kt is 1.8.20. Intercept plugin resolution in settings.gradle.kts: when VERSION_KOTLIN is set (i.e. the matrix is driving the build), use KSP2 2.3.7, which is decoupled from the Kotlin compiler. Otherwise leave the pinned KSP1 in place so default / pre-merge builds keep working. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The settings.gradle.kts resolutionStrategy override didn't work because plugin-alias requests through the version catalog bypass it — Gradle rejected the rewrite with "the plugin is already on the classpath with a different version". Switch to the same pattern the other Kotlin plugins use: a `BuildPluginsVersion.KSP` field sourced from VERSION_KOTLIN (KSP2 2.3.7 when Kotlin 2.x, KSP1 2.1.0-1.0.29 otherwise), applied via `version BuildPluginsVersion.KSP` on both the root `apply false` and the sample's plugins block. Verified locally that both default builds (Kotlin 1.8.20, KSP1) and the matrix path (VERSION_KOTLIN=2.3.21, KSP2) resolve and run `kspStagingReleaseKotlin` successfully. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| // Pick the latest Kotlin whose required AGP <= this AGP | ||
| val kotlinVersion = | ||
| agpToKotlin | ||
| .filter { (minAgp, _) -> agpVersion >= minAgp } |
There was a problem hiding this comment.
Bug: The semver comparison agpVersion >= minAgp will incorrectly evaluate to false for prerelease AGP versions, leading to an older Kotlin version being selected.
Severity: MEDIUM
Suggested Fix
Before the comparison, strip the prerelease label from the agpVersion object. This will ensure that versions like 9.3.0-alpha01 and 9.3.0 are treated as equivalent for the purpose of this check, preventing the incorrect selection of an older Kotlin version.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: scripts/generate-compat-matrix.main.kts#L108
Potential issue: The semver comparison `agpVersion >= minAgp` will evaluate to `false`
for prerelease AGP versions (e.g., `9.3.0-alpha01`) when the compatibility table's
`minAgp` has the same major, minor, and patch version (e.g., `9.3.0`). This is because
`minAgp` has its prerelease label stripped, while `agpVersion` does not. According to
SemVer rules, `9.3.0-alpha01` is less than `9.3.0`. This will cause the build matrix
generation script to silently select an older, incorrect Kotlin version for that
prerelease AGP entry.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 059375b. Configure here.
| alias(libs.plugins.kotlinAndroid) version BuildPluginsVersion.KOTLIN apply false | ||
| alias(libs.plugins.kapt) version BuildPluginsVersion.KOTLIN apply false | ||
| alias(libs.plugins.ksp) apply false | ||
| alias(libs.plugins.ksp) version BuildPluginsVersion.KSP apply false |
There was a problem hiding this comment.
Compose compiler plugin version not overridden for new Kotlin versions
High Severity
The composeCompiler plugin (org.jetbrains.kotlin.plugin.compose) is declared without a version override, leaving it pinned at 2.1.0 from the catalog. The other Kotlin plugins (kotlin, kotlinAndroid, kapt) all use version BuildPluginsVersion.KOTLIN, and this PR adds version BuildPluginsVersion.KSP for KSP — but composeCompiler was missed. Since the matrix now produces Kotlin 2.3.0 and 2.4.0 for all entries, the example project that conditionally applies this plugin will hit a version mismatch, as the compose compiler plugin version must match the Kotlin version.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 059375b. Configure here.


#skip-changelog
Replace the static
gradleToKotlindict inscripts/generate-compat-matrix.main.ktswith a fetch of the AGP ↔ Kotlin compatibility table from developer.android.com/build/kotlin-support. For each AGP version in the CI matrix we now pick the highest Kotlin whose required AGP is ≤ ours, which is a more direct semantic fit than the previous Gradle→Kotlin hand-picked map and also catches new Kotlin minors automatically.Follow-up to #1165, which switched the AGP↔Gradle source.
The existing Kotlin→min-Gradle floor check (sourced from kotlinlang.org via
fetchKotlinGradleCompatibility) stays in place, so if the chosen Kotlin needs a newer Gradle than AGP does, we still bump Gradle up.Verified output locally against the four AGP versions the matrix generator picks today:
Gradle versions are unchanged.