kotlinx.kover.gradle.aggregation.project.KoverProjectGradlePlugin.kt Maven / Gradle / Ivy
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.kover.gradle.aggregation.project
import kotlinx.kover.gradle.aggregation.commons.artifacts.*
import kotlinx.kover.gradle.aggregation.commons.names.KoverPaths.binReportName
import kotlinx.kover.gradle.aggregation.commons.names.KoverPaths.binReportsRootPath
import kotlinx.kover.gradle.aggregation.commons.names.PluginId.KOTLIN_JVM_PLUGIN_ID
import kotlinx.kover.gradle.aggregation.commons.names.PluginId.KOTLIN_MULTIPLATFORM_PLUGIN_ID
import kotlinx.kover.gradle.aggregation.commons.names.SettingsNames
import kotlinx.kover.gradle.aggregation.commons.utils.bean
import kotlinx.kover.gradle.aggregation.commons.utils.hasSuper
import kotlinx.kover.gradle.aggregation.project.instrumentation.JvmOnFlyInstrumenter
import kotlinx.kover.gradle.aggregation.project.tasks.ArtifactGenerationTask
import kotlinx.kover.gradle.aggregation.settings.dsl.intern.KoverProjectExtensionImpl
import kotlinx.kover.gradle.plugin.commons.KOTLIN_ANDROID_PLUGIN_ID
import kotlinx.kover.gradle.plugin.commons.KoverCriticalException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.attributes.Usage
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.withType
import java.io.File
internal class KoverProjectGradlePlugin : Plugin {
override fun apply(target: Project) {
val projectExtension = target.configureExtension()
target.configureInstrumentation(projectExtension)
target.configureArtifactGeneration()
}
private fun Project.configureExtension(): KoverProjectExtensionImpl {
val projectExtension = extensions.create("kover")
projectExtension.instrumentation.excludedClasses.convention(emptySet())
projectExtension.instrumentation.includedClasses.convention(emptySet())
return projectExtension
}
private fun Project.configureInstrumentation(projectExtension: KoverProjectExtensionImpl) {
val koverJarDependency = configurations.getByName(SettingsNames.DEPENDENCY_AGENT)
val jarConfig = configurations.create("agentJarSource") {
asConsumer()
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KoverUsageAttr.VALUE))
attribute(KoverContentAttr.ATTRIBUTE, KoverContentAttr.AGENT_JAR)
}
extendsFrom(koverJarDependency)
}
JvmOnFlyInstrumenter.instrument(tasks.withType(), jarConfig, projectExtension.instrumentation)
}
private fun Project.configureArtifactGeneration() {
val taskGraph = gradle.taskGraph
val artifactFile = layout.buildDirectory.file("kover/kover.artifact")
// we create task immediately because of mustRunAfter
val generateArtifactTask = tasks.create("koverGenerateArtifact")
generateArtifactTask.outputFile.set(artifactFile)
// add tests
val testTasks = tasks.withType().matching { task ->
taskGraph.hasTask(task.path)
}
val binReportFiles = project.layout.buildDirectory.dir(binReportsRootPath())
.map { dir -> testTasks.map { dir.file(binReportName(it.name)) } }
val exts = extensions
val pluginManager = pluginManager
val projectPath = path
val compilations = project.layout.buildDirectory.map {
val compilations = when {
pluginManager.hasPlugin(KOTLIN_JVM_PLUGIN_ID) || pluginManager.hasPlugin(KOTLIN_ANDROID_PLUGIN_ID) -> {
val kotlin = exts.findByName("kotlin")?.bean()
?: throw KoverCriticalException("Kotlin JVM extension not found")
kotlin["target"]["compilations"].sequence()
}
pluginManager.hasPlugin(KOTLIN_MULTIPLATFORM_PLUGIN_ID) -> {
val kotlin = exts.findByName("kotlin")?.bean()
?: throw KoverCriticalException("Kotlin JVM multiplatform not found")
kotlin["targets"].sequence()
.filter {
val platformType = it["platformType"]["name"].value()
platformType == "jvm" || platformType == "androidJvm"
}.flatMap {
it["compilations"].sequence()
}
}
else -> emptySequence()
}
compilations.filter { compilation ->
val compilationName = compilation["name"].value()
if (compilationName == "test" || compilationName.endsWith("Test")) return@filter false
val taskPath = projectPath + (if (projectPath == Project.PATH_SEPARATOR) "" else Project.PATH_SEPARATOR) + compilation["compileTaskProvider"]["name"].value()
taskGraph.hasTask(taskPath)
}
}
val compilationMap = compilations.map { allCompilations ->
allCompilations.associate { compilation ->
val sourceDirs = compilation["allKotlinSourceSets"].sequence()
.flatMap { sourceSet -> sourceSet["kotlin"]["srcDirs"].sequence().map { it.value() } }
.toSet()
val outputDirs = compilation["output"]["classesDirs"].value().files
compilation["name"].value() to CompilationInfo(sourceDirs, outputDirs)
}
}
// TODO describe the trick
tasks.withType().configureEach {
generateArtifactTask.mustRunAfter(this)
}
tasks.withType().configureEach {
if (this.hasSuper("KotlinCompilationTask")) {
generateArtifactTask.mustRunAfter(this)
}
}
tasks.withType().configureEach {
generateArtifactTask.mustRunAfter(this)
}
generateArtifactTask.compilations.putAll(compilationMap)
generateArtifactTask.reportFiles.from(binReportFiles)
configurations.register("KoverArtifactProducer") {
asProducer()
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KoverUsageAttr.VALUE))
attribute(KoverContentAttr.ATTRIBUTE, KoverContentAttr.LOCAL_ARTIFACT)
}
outgoing.artifact(artifactFile) {
// Before resolving this configuration, it is necessary to execute the task of generating an artifact
builtBy(generateArtifactTask)
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy