kotlinx.kover.gradle.plugin.locators.Android.kt Maven / Gradle / Ivy
/*
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.kover.gradle.plugin.locators
import kotlinx.kover.gradle.plugin.commons.AndroidFallbacks
import kotlinx.kover.gradle.plugin.commons.AndroidFlavor
import kotlinx.kover.gradle.plugin.commons.AndroidVariantCompilationKit
import kotlinx.kover.gradle.plugin.commons.CompilationUnit
import kotlinx.kover.gradle.plugin.commons.KoverCriticalException
import kotlinx.kover.gradle.plugin.commons.KoverIllegalConfigException
import kotlinx.kover.gradle.plugin.dsl.internal.KoverProjectExtensionImpl
import kotlinx.kover.gradle.plugin.util.DynamicBean
import kotlinx.kover.gradle.plugin.util.bean
import kotlinx.kover.gradle.plugin.util.hasSuperclass
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.withType
internal fun Project.afterAndroidPluginApplied(afterAndroid: () -> Unit) {
val androidComponents = project.extensions.findByName("androidComponents")?.bean()
?: throw KoverCriticalException("Kover requires extension with name 'androidComponents' for project '${project.path}' since it is recognized as Kotlin+Android project")
val callback = Action {
project.afterEvaluate {
afterAndroid()
}
}
if (androidComponents.hasFunction("finalizeDsl", callback)) {
/*
Assumption: `finalizeDsl` is called in the `afterEvaluate` action, in which build variants are created.
Therefore, if an action is added to the queue inside it, it will be executed only after variants are created
*/
androidComponents("finalizeDsl", callback)
} else {
// for old versions < 7.0 an action is added to the AAA queue.
// Since this code is executed after the applying of AGP, there is a high probability that the action will fall into the `afterEvaluate` queue after the actions of the AGP
project.afterEvaluate {
afterAndroid()
}
}
}
/**
* Locate Android compilation kits for the given Kotlin Target.
*/
internal fun Project.androidCompilationKits(
androidExtension: DynamicBean,
koverExtension: KoverProjectExtensionImpl,
kotlinTarget: DynamicBean
): List {
val variants = if ("applicationVariants" in androidExtension) {
androidExtension.beanCollection("applicationVariants")
} else {
androidExtension.beanCollection("libraryVariants")
}
val fallbacks = findFallbacks(androidExtension)
return variants.map {
extractAndroidKit(androidExtension, koverExtension, kotlinTarget, fallbacks, it)
}
}
private fun Project.extractAndroidKit(
androidExtension: DynamicBean,
koverExtension: KoverProjectExtensionImpl,
kotlinTarget: DynamicBean,
fallbacks: AndroidFallbacks,
variant: DynamicBean
): AndroidVariantCompilationKit {
val variantName = variant.value("name")
val compilations = provider {
mapOf("main" to extractCompilationOrEmpty(koverExtension, kotlinTarget, variantName))
}
val unitTestVariantName = variant.beanOrNull("unitTestVariant")?.value("name")
val tests = tasks.withType().matching { test ->
// if `unitTestVariant` not specified for application/library variant then unit tests are disabled for it
unitTestVariantName != null
// skip all tests from instrumentation if Kover Plugin is disabled for the project
&& !koverExtension.disabled
// skip this test if it disabled by name
&& test.name !in koverExtension.tests.tasksNames
// use only Android unit tests (local tests)
&& test.hasSuperclass("AndroidUnitTest")
// only tests of current application build variant
&& test.bean().value("variantName") == unitTestVariantName
}
val buildTypeName = variant["buildType"].value("name")
val flavors = variant.beanCollection("productFlavors").map { flavor ->
val flavorName = flavor.value("name")
val dimension = flavor.valueOrNull("dimension")
?: throw KoverIllegalConfigException("Product flavor '$flavorName' must have at least one flavor dimension. Android Gradle Plugin with version < 3.0.0 not supported")
AndroidFlavor(dimension, flavorName)
}
// merge flavors to get missing dimensions for variant
val missingDimensions = findMissingDimensions(androidExtension, variant)
return AndroidVariantCompilationKit(variantName, buildTypeName, flavors, fallbacks, missingDimensions, tests, compilations)
}
private fun findMissingDimensions(androidExtension: DynamicBean, variant: DynamicBean): Map {
val missingDimensionsForVariant = mutableMapOf()
// default config has the lowest priority
missingDimensionsForVariant +=
androidExtension["defaultConfig"].value
© 2015 - 2025 Weber Informatics LLC | Privacy Policy