From 2cd6840ec3031ad375fbed381efb9c8eba08a480 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 12:30:20 +0100 Subject: [PATCH 1/8] fix(ci): Fallback to AGP release notes for Gradle version lookup When an AGP version (e.g. 9.2.0) is not yet listed in the compatibility table at about-agp, fetch the minimum Gradle version from the AGP release notes page instead of falling back to the latest table entry. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 47 ++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index 270b5427b..4629cc839 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -63,10 +63,12 @@ class GenerateMatrix : CliktCommand() { val (currentVersions, latestVersion) = fetchAgpCompatibilityTable(agpVersions) buildMap { for (agpVersion in agpVersions) { - put( - agpVersion, - legacyVersions[agpVersion] ?: currentVersions[agpVersion] ?: latestVersion, - ) + val gradleVersion = + legacyVersions[agpVersion] + ?: currentVersions[agpVersion] + ?: fetchGradleVersionFromReleaseNotes(agpVersion) + ?: latestVersion + put(agpVersion, gradleVersion) } } } catch (e: Exception) { @@ -346,6 +348,43 @@ class GenerateMatrix : CliktCommand() { return gradleVersions to latest.value } + + /** + * Fetches the minimum required Gradle version from the AGP release notes page. + * This is used as a fallback when the AGP version is not yet listed in the compatibility table. + * + * @param agpVersion the AGP version to look up + * @return the minimum required Gradle version, or null if the release notes page doesn't exist + */ + private fun fetchGradleVersionFromReleaseNotes(agpVersion: Version): Version? { + // Release notes URLs are per-minor version and always use patch 0 + // e.g. agp-9-2-0-release-notes covers all 9.2.x versions + val url = + "https://developer.android.com/build/releases/agp-${agpVersion.major}-${agpVersion.minor}-0-release-notes" + val html = + try { + URL(url).readText() + } catch (e: Throwable) { + echo("Warning: Could not fetch release notes from $url") + return null + } + val doc = Jsoup.parse(html) + val tables = doc.select("table") + for (table in tables) { + for (row in table.select("tr")) { + val cells = row.select("td").map { it.text() } + if (cells.size >= 2 && cells[0].contains("Gradle", ignoreCase = true)) { + return try { + Version.parse(cells[1], strict = false) + } catch (e: Throwable) { + echo("Warning: Could not parse Gradle version '${cells[1]}' from release notes") + null + } + } + } + } + return null + } } GenerateMatrix().main(args) From d676e04763979c99cd23736fa2cc302f45ebc9de Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 12:42:09 +0100 Subject: [PATCH 2/8] fix(ci): Format script and add Kotlin 2.3.10 for Gradle 9.5+ AGP 9.2.0-alpha06 depends on Kotlin 2.3.10, so Gradle 9.5+ needs to use that version instead of 2.1.0 to avoid dependency resolution conflicts. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index 4629cc839..556906df8 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -94,6 +94,7 @@ class GenerateMatrix : CliktCommand() { mapOf( "7.5".toVersion(strict = false) to "1.8.20", "9.0.0".toVersion(strict = false) to "2.1.0", + "9.5.0".toVersion(strict = false) to "2.3.10", ) // TODO: make it dynamic too val kotlinVersion = "2.1.0".toVersion() @@ -350,8 +351,8 @@ class GenerateMatrix : CliktCommand() { } /** - * Fetches the minimum required Gradle version from the AGP release notes page. - * This is used as a fallback when the AGP version is not yet listed in the compatibility table. + * Fetches the minimum required Gradle version from the AGP release notes page. This is used as a + * fallback when the AGP version is not yet listed in the compatibility table. * * @param agpVersion the AGP version to look up * @return the minimum required Gradle version, or null if the release notes page doesn't exist From ddf6db3f112e650bae5c3b2c5353dcfa5a7e3887 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 12:53:50 +0100 Subject: [PATCH 3/8] fix(ci): Use pre-release key for Kotlin 2.3.10 Gradle mapping 9.5.0-milestone-5 < 9.5.0 in semver (pre-releases have lower precedence), so use 9.5.0-0 as the map key to ensure milestone versions match. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index 556906df8..b39aa7661 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -88,13 +88,11 @@ class GenerateMatrix : CliktCommand() { } // TODO: for now this is manual, but we could try get it from Gradle's github in the future - val gradleToGroovy = - mapOf("7.5".toVersion(strict = false) to "1.2", "8.11".toVersion(strict = false) to "1.7.1") val gradleToKotlin = mapOf( "7.5".toVersion(strict = false) to "1.8.20", "9.0.0".toVersion(strict = false) to "2.1.0", - "9.5.0".toVersion(strict = false) to "2.3.10", + "9.5.0-0".toVersion(strict = false) to "2.3.10", ) // TODO: make it dynamic too val kotlinVersion = "2.1.0".toVersion() @@ -131,10 +129,6 @@ class GenerateMatrix : CliktCommand() { ) // TODO: if needed we can test against different Java versions put("java", "17") - val groovy = gradleToGroovy.entries.findLast { finalGradle >= it.key }?.value - if (groovy != null) { - put("groovy", groovy) - } val kotlin = gradleToKotlin.entries.findLast { finalGradle >= it.key }?.value if (kotlin != null) { put("kotlin", kotlin) From 079ba77e88cd21ce00d88dfa62c397f07290ea0d Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 13:13:23 +0100 Subject: [PATCH 4/8] fix(ci): Try Kotlin 2.3.0 for Gradle 9.5+ Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index b39aa7661..1998b4998 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -92,7 +92,7 @@ class GenerateMatrix : CliktCommand() { mapOf( "7.5".toVersion(strict = false) to "1.8.20", "9.0.0".toVersion(strict = false) to "2.1.0", - "9.5.0-0".toVersion(strict = false) to "2.3.10", + "9.5.0-0".toVersion(strict = false) to "2.3.0", ) // TODO: make it dynamic too val kotlinVersion = "2.1.0".toVersion() From 2a5d32246b55a00082758740abc270f11c85a776 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 13:38:06 +0100 Subject: [PATCH 5/8] fix(ci): Dynamically set Kotlin language version based on compiler Kotlin 2.3+ dropped support for language version 1.8. Use 2.0 when building with Kotlin 2.3+, otherwise keep 1.8. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugin-build/build.gradle.kts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugin-build/build.gradle.kts b/plugin-build/build.gradle.kts index 2e0bd82d9..bfd91c74d 100644 --- a/plugin-build/build.gradle.kts +++ b/plugin-build/build.gradle.kts @@ -5,7 +5,7 @@ import java.util.Properties import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.config.KotlinCompilerVersion import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 -import org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8 +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -91,8 +91,15 @@ tasks.withType().configureEach { compilerOptions { jvmTarget.set(JVM_11) - languageVersion.set(KOTLIN_1_8) - apiVersion.set(KOTLIN_1_8) + // Kotlin supports current + 3 previous language versions. + // We want 1.8, but if the compiler no longer supports it, use the oldest it does support. + // e.g. Kotlin 2.1 oldest=1.8, Kotlin 2.3 oldest=2.0 + val compilerParts = KotlinCompilerVersion.VERSION.split(".") + val compilerFlat = compilerParts[0].toInt() * 10 + compilerParts[1].toInt() + val oldestFlat = maxOf(compilerFlat - 3, 18) // 18 = Kotlin 1.8 + val kotlinLangVersion = KotlinVersion.valueOf("KOTLIN_${oldestFlat / 10}_${oldestFlat % 10}") + languageVersion.set(kotlinLangVersion) + apiVersion.set(kotlinLangVersion) } } From f36ff24253323da70e80a49b1da4adcc076ce661 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 13:57:31 +0100 Subject: [PATCH 6/8] fix(ci): Continue searching tables when version parse fails in release notes Fixed-issues tables can have cells like "Android Gradle Plugin" that match the "Gradle" check but aren't version strings. Continue the loop instead of returning null so the actual compatibility table is found. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index 1998b4998..85b8f8bd4 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -369,11 +369,12 @@ class GenerateMatrix : CliktCommand() { for (row in table.select("tr")) { val cells = row.select("td").map { it.text() } if (cells.size >= 2 && cells[0].contains("Gradle", ignoreCase = true)) { - return try { - Version.parse(cells[1], strict = false) + try { + return Version.parse(cells[1], strict = false) } catch (e: Throwable) { - echo("Warning: Could not parse Gradle version '${cells[1]}' from release notes") - null + // Non-version cell (e.g. "Android Gradle Plugin" in fixed-issues tables), + // keep searching other rows/tables + continue } } } From 9a535894c9c9de1daeaea58112696915eccb28ef Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 14:10:44 +0100 Subject: [PATCH 7/8] fix(ci): Validate table headers and match exact "Gradle" cell in release notes Skip tables without "version" in headers (e.g. fixed-issues tables) and match cells[0] exactly as "Gradle" instead of contains-check to avoid false matches like "Android Gradle Plugin". Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-compat-matrix.main.kts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/generate-compat-matrix.main.kts b/scripts/generate-compat-matrix.main.kts index 85b8f8bd4..95f600e1f 100755 --- a/scripts/generate-compat-matrix.main.kts +++ b/scripts/generate-compat-matrix.main.kts @@ -366,15 +366,17 @@ class GenerateMatrix : CliktCommand() { val doc = Jsoup.parse(html) val tables = doc.select("table") for (table in tables) { + val headers = table.select("tr").firstOrNull()?.select("th")?.map { it.text() } ?: continue + // The compatibility table has "Minimum version" and "Default version" columns + if (headers.none { it.contains("version", ignoreCase = true) }) continue for (row in table.select("tr")) { val cells = row.select("td").map { it.text() } - if (cells.size >= 2 && cells[0].contains("Gradle", ignoreCase = true)) { - try { - return Version.parse(cells[1], strict = false) + if (cells.size >= 2 && cells[0].trim().equals("Gradle", ignoreCase = true)) { + return try { + Version.parse(cells[1], strict = false) } catch (e: Throwable) { - // Non-version cell (e.g. "Android Gradle Plugin" in fixed-issues tables), - // keep searching other rows/tables - continue + echo("Warning: Could not parse Gradle version '${cells[1]}' from release notes") + null } } } From e0f8495cdb04294d7cf50536fff9c06f1be82ca9 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 27 Mar 2026 14:21:02 +0100 Subject: [PATCH 8/8] compile against a static AGP version --- .github/workflows/test-matrix-agp-gradle.yaml | 1 - plugin-build/build.gradle.kts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test-matrix-agp-gradle.yaml b/.github/workflows/test-matrix-agp-gradle.yaml index d2c3abed0..a4b7d9f26 100644 --- a/.github/workflows/test-matrix-agp-gradle.yaml +++ b/.github/workflows/test-matrix-agp-gradle.yaml @@ -51,7 +51,6 @@ jobs: name: Test Matrix - AGP ${{ matrix.agp }} - Gradle ${{ matrix.gradle }} - Java ${{ matrix.java }} - Kotlin ${{ matrix.kotlin }} env: VERSION_AGP: ${{ matrix.agp }} - VERSION_GROOVY: ${{ matrix.groovy }} VERSION_KOTLIN: ${{ matrix.kotlin }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} diff --git a/plugin-build/build.gradle.kts b/plugin-build/build.gradle.kts index bfd91c74d..3b99d9cd4 100644 --- a/plugin-build/build.gradle.kts +++ b/plugin-build/build.gradle.kts @@ -31,7 +31,7 @@ val fixtureClasspath: Configuration by configurations.creating dependencies { compileOnly(libs.gradleApi) - compileOnly(Libs.AGP) + compileOnly(libs.agp) compileOnly(libs.proguard) implementation(libs.asm)