Skip to content

Commit 298bf8b

Browse files
authored
Added support for Android Gradle Plugin 9.0.0
Fixes #776 PR #777
1 parent 0ba9e9e commit 298bf8b

File tree

8 files changed

+118
-15
lines changed

8 files changed

+118
-15
lines changed

kover-gradle-plugin/src/functionalTest/kotlin/kotlinx/kover/gradle/plugin/test/functional/cases/AndroidKmpLibTests.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ import kotlinx.kover.gradle.plugin.test.functional.framework.checker.CheckerCont
88
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.TemplateTest
99

1010
internal class AndroidKmpLibTests {
11+
@TemplateTest("android-kmp-library-8", ["koverXmlReport"])
12+
fun CheckerContext.testPresenceAgp8() {
13+
xmlReport {
14+
classCounter("org.jetbrains.ExampleClass").assertPresent()
15+
classCounter("org.jetbrains.AndroidClass").assertPresent()
16+
methodCounter("org.jetbrains.AndroidClass", "covered").assertFullyCovered()
17+
}
18+
}
19+
1120
@TemplateTest("android-kmp-library", ["koverXmlReport"])
1221
fun CheckerContext.testPresence() {
1322
xmlReport {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2017-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
plugins {
6+
kotlin("multiplatform") version ("2.2.20")
7+
id("com.android.kotlin.multiplatform.library") version "8.12.0"
8+
id ("org.jetbrains.kotlinx.kover") version "0.9.1"
9+
}
10+
11+
kotlin {
12+
androidLibrary {
13+
namespace = "org.jetbrains.kover.kml.lib"
14+
compileSdk = 33
15+
minSdk = 24
16+
17+
withDeviceTestBuilder {
18+
sourceSetTreeName = "test"
19+
}
20+
21+
withHostTest { }
22+
}
23+
24+
jvm()
25+
}
26+
27+
dependencies {
28+
commonTestImplementation("junit:junit:4.13.2")
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
pluginManagement {
2+
repositories {
3+
google()
4+
mavenCentral()
5+
gradlePluginPortal()
6+
}
7+
}
8+
9+
dependencyResolutionManagement {
10+
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
11+
repositories {
12+
google()
13+
mavenCentral()
14+
gradlePluginPortal()
15+
}
16+
}
17+
18+
rootProject.name = "android-kmp-library"
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2017-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains
6+
7+
8+
import org.junit.Test
9+
10+
11+
12+
class LocalTests {
13+
@Test
14+
fun test() {
15+
AndroidClass().covered()
16+
}
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright 2017-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains
6+
7+
class AndroidClass {
8+
fun a() {
9+
println("Hello World!")
10+
}
11+
12+
fun covered() {
13+
println("Covered")
14+
}
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2017-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains
6+
7+
class ExampleClass {
8+
fun a() {
9+
println("Hello World!")
10+
}
11+
}

kover-gradle-plugin/src/functionalTest/templates/builds/android-kmp-library/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
plugins {
66
kotlin("multiplatform") version ("2.2.20")
7-
id("com.android.kotlin.multiplatform.library") version "8.12.0"
7+
id("com.android.kotlin.multiplatform.library") version "9.0.0-alpha14"
88
id ("org.jetbrains.kotlinx.kover") version "0.9.1"
99
}
1010

kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/locators/KotlinMultiPlatformLocator.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import kotlinx.kover.gradle.plugin.appliers.origin.JvmVariantOrigin
99
import kotlinx.kover.gradle.plugin.appliers.origin.AllVariantOrigins
1010
import kotlinx.kover.gradle.plugin.appliers.origin.CompilationDetails
1111
import kotlinx.kover.gradle.plugin.appliers.origin.LanguageCompilation
12-
import kotlinx.kover.gradle.plugin.commons.*
1312
import kotlinx.kover.gradle.plugin.util.*
1413
import org.gradle.api.Project
1514
import org.gradle.api.Task
@@ -39,35 +38,35 @@ internal fun Project.locateKotlinMultiplatformVariants(): AllVariantOrigins {
3938
return AllVariantOrigins(jvms, androids)
4039
}
4140

41+
// Used only for the old AGP implementation for KMP libraries (AGP < 8.x.x)
4242
private fun Project.locateAndroidVariants(kotlinExtension: DynamicBean): List<AndroidVariantOrigin> {
4343
// only one Android target is allowed, so we can take the first one
4444
val androidTarget = kotlinExtension.beanCollection("targets").firstOrNull {
4545
it["platformType"].value<String>("name") == "androidJvm"
4646
} ?: return emptyList()
4747

48+
// since AGP 9.0.0 there is no `android` extension
4849
val androidExtension = project.extensions.findByName("android")?.bean()
49-
?: throw KoverCriticalException("Kover requires extension with name 'android' for project '${project.path}' since it is recognized as Kotlin/Android project")
50+
?: return emptyList()
5051

5152
return project.androidCompilationKits(androidExtension, androidTarget)
5253
}
5354

5455
private fun Project.locateAllJvmVariants(kotlinExtension: DynamicBean): List<JvmVariantOrigin> {
55-
val jvmTargets = kotlinExtension.beanCollection("targets").filter {
56-
it["platformType"].value<String>("name") == "jvm"
57-
}
58-
if (jvmTargets.isEmpty()) {
59-
return emptyList()
60-
}
56+
val jvmTargets = kotlinExtension.beanCollection("targets").toList()
6157

6258
val result = mutableListOf<JvmVariantOrigin>()
6359
locateJvmVariant(jvmTargets)?.let { result += it }
64-
locateAndroidLibrary(jvmTargets)?.let { result += it }
60+
locateAndroidMultiplatformLibrary(jvmTargets)?.let { result += it }
61+
6562
return result
6663
}
6764

6865
private fun Project.locateJvmVariant(jvmTargets: List<DynamicBean>): JvmVariantOrigin? {
6966
val strictJvmTarget = jvmTargets.singleOrNull {
70-
!it.origin.hasSuperclass("KotlinMultiplatformAndroidLibraryTargetImpl")
67+
it["platformType"].value<String>("name") == "jvm" &&
68+
// exclude Android targets since in AGP 8.x.x it has the type 'jvm'
69+
!it.origin.hasSuperclass("KotlinMultiplatformAndroidLibraryTargetImpl")
7170
} ?: return null
7271

7372
val targetName = strictJvmTarget.value<String>("targetName")
@@ -83,12 +82,16 @@ private fun Project.locateJvmVariant(jvmTargets: List<DynamicBean>): JvmVariantO
8382
return JvmVariantOrigin(tests, compilations, targetName)
8483
}
8584

86-
private fun Project.locateAndroidLibrary(jvmTargets: List<DynamicBean>): JvmVariantOrigin? {
85+
// Locate Android multiplatform library target in AGP > 8.x.x
86+
private fun Project.locateAndroidMultiplatformLibrary(jvmTargets: List<DynamicBean>): JvmVariantOrigin? {
8787
val androidLibrary = jvmTargets.singleOrNull {
88-
it.origin.hasSuperclass("KotlinMultiplatformAndroidLibraryTargetImpl")
88+
it.origin.hasSuperclass("KotlinMultiplatformAndroidLibraryTargetImpl") && (
89+
// in AGP 8.x.x Android multiplatform library has the type 'jvm'
90+
it["platformType"].value<String>("name") == "jvm"
91+
// in AGP 9.0.0 Android multiplatform library has type 'androidJvm'
92+
|| it["platformType"].value<String>("name") == "androidJvm"
93+
)
8994
} ?: return null
90-
91-
9295
val targetName = androidLibrary.value<String>("targetName")
9396
val tests = tasks.withType<Test>().matching {
9497
it.hasSuperclass("AndroidUnitTest") && it.bean().value<String>("variantName") == "${targetName}HostTest"

0 commit comments

Comments
 (0)