Skip to content

Commit

Permalink
Added ability to specify inclusion filter for source sets
Browse files Browse the repository at this point in the history
Resolves #714
  • Loading branch information
shanshin committed Jan 7, 2025
1 parent 8e47a67 commit cd71b38
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 4 deletions.
1 change: 1 addition & 0 deletions kover-gradle-plugin/api/kover-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverVariantCrea

public abstract interface class kotlinx/kover/gradle/plugin/dsl/KoverVariantSources {
public abstract fun getExcludeJava ()Lorg/gradle/api/provider/Property;
public abstract fun getExcludedOtherSourceSets ()Lorg/gradle/api/provider/SetProperty;
public abstract fun getExcludedSourceSets ()Lorg/gradle/api/provider/SetProperty;
}

Expand Down
31 changes: 29 additions & 2 deletions kover-gradle-plugin/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1122,8 +1122,6 @@ By specifying an empty filter `filters { }`, you can completely disable report f

It is possible to exclude from all reports the code declared in certain source sets.

As a side effect, the generation of Kover reports ceases to depend on the compilation tasks of these source sets.

```kotlin
kover {
currentProject {
Expand All @@ -1134,6 +1132,35 @@ kover {
}
```

In addition, it is possible to exclude classes from all source sets that are not specified.

```kotlin
kover {
currentProject {
sources {
excludedOtherSourceSets.addAll("main")
}
}
}
```

This way, only classes from the `main` source set will be included in the report, but not from others.

These filters can be combined, the `excludedSourceSets` filter has priority.
```kotlin
kover {
currentProject {
sources {
excludedOtherSourceSets.addAll("main", "extra")
excludedSourceSets.addAll("main")
}
}
}
```
In this case, only classes from the `extra` source set will be included in the report.

As a side effect of the source set exclusion, the generation of Kover reports ceases to depend on the compilation tasks of excluded source sets.

### Exclusion of test tasks
If some task does not test the coverage of application classes,
or it is necessary to exclude its coverage from reports, then specify this task in the excluded list.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2017-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.kover.gradle.plugin.test.functional.cases

import kotlinx.kover.gradle.plugin.test.functional.framework.checker.createCheckerContext
import kotlinx.kover.gradle.plugin.test.functional.framework.runner.buildFromTemplate
import kotlinx.kover.gradle.plugin.test.functional.framework.runner.runWithParams
import org.junit.jupiter.api.Test
import kotlin.test.assertTrue

internal class SourceSetsTests {

@Test
fun testExclude() {
val template = buildFromTemplate("sourcesets-multi")

template.kover {
currentProject {
sources.excludedSourceSets.addAll("main", "foo")
}
}

val gradleBuild = template.generate()
val buildResult = gradleBuild.runWithParams(":koverXmlReport")

gradleBuild.createCheckerContext(buildResult).xmlReport {
assertTrue(buildResult.isSuccessful, "Build should be successful")
classCounter("kotlinx.kover.examples.sourcesets.MainClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.FooClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.ExtraClass").assertPresent()
}
}

@Test
fun testInclude() {
val template = buildFromTemplate("sourcesets-multi")

template.kover {
currentProject {
sources.excludedOtherSourceSets.addAll("extra")
}
}

val gradleBuild = template.generate()
val buildResult = gradleBuild.runWithParams(":koverXmlReport")

gradleBuild.createCheckerContext(buildResult).xmlReport {
assertTrue(buildResult.isSuccessful, "Build should be successful")
classCounter("kotlinx.kover.examples.sourcesets.MainClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.FooClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.ExtraClass").assertPresent()
}
}

@Test
fun testInclude2() {
val template = buildFromTemplate("sourcesets-multi")

template.kover {
currentProject {
sources.excludedOtherSourceSets.addAll("extra", "foo")
}
}

val gradleBuild = template.generate()
val buildResult = gradleBuild.runWithParams(":koverXmlReport")

gradleBuild.createCheckerContext(buildResult).xmlReport {
assertTrue(buildResult.isSuccessful, "Build should be successful")
classCounter("kotlinx.kover.examples.sourcesets.MainClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.FooClass").assertPresent()
classCounter("kotlinx.kover.examples.sourcesets.ExtraClass").assertPresent()
}
}

@Test
fun testMixed() {
val template = buildFromTemplate("sourcesets-multi")

template.kover {
currentProject {
sources {
excludedOtherSourceSets.addAll("extra", "foo")
excludedSourceSets.add("foo")
}
}
}

val gradleBuild = template.generate()
val buildResult = gradleBuild.runWithParams(":koverXmlReport")

gradleBuild.createCheckerContext(buildResult).xmlReport {
assertTrue(buildResult.isSuccessful, "Build should be successful")
classCounter("kotlinx.kover.examples.sourcesets.MainClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.FooClass").assertAbsent()
classCounter("kotlinx.kover.examples.sourcesets.ExtraClass").assertPresent()
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ private class CounterImpl(
assertNull(values, "Counter '$symbol' with type '$type' isn't absent")
}

override fun assertPresent() {
assertNotNull(values, "Counter for '$symbol' with type '$type' isn't present in report")
}

override fun assertFullyMissed() {
assertNotNull(values, "Counter '$symbol' with type '$type' isn't fully missed because it absent")
assertTrue(values.missed > 0, "Counter '$symbol' with type '$type' isn't fully missed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ internal interface ProjectAnalysisData {
internal interface Counter {
fun assertAbsent()

fun assertPresent()

fun assertFullyMissed()

fun assertCovered()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@

package kotlinx.kover.gradle.plugin.test.functional.framework.runner

import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
import kotlinx.kover.gradle.plugin.test.functional.framework.common.BuildSlice
import kotlinx.kover.gradle.plugin.test.functional.framework.common.ScriptLanguage
import kotlinx.kover.gradle.plugin.test.functional.framework.common.isDebugEnabled
import kotlinx.kover.gradle.plugin.test.functional.framework.common.logInfo
import kotlinx.kover.gradle.plugin.test.functional.framework.common.uri
import kotlinx.kover.gradle.plugin.test.functional.framework.configurator.ProjectScope
import kotlinx.kover.gradle.plugin.test.functional.framework.mirroring.printGradleDsl
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.*
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.buildSrc
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.patchSettingsFile
Expand All @@ -31,6 +36,8 @@ internal interface BuildSource {

fun from(rootProjectDir: File)

fun kover(config: KoverProjectExtension.(ProjectScope) -> Unit)

fun generate(): GradleBuild
}

Expand All @@ -54,6 +61,8 @@ private class BuildSourceImpl(val snapshotRepos: List<String>, val koverVersion:

private var copy: Boolean = false

private val koverBlocks: MutableList<(ScriptLanguage, String) -> String> = mutableListOf()

override var buildName: String = "default"

override var buildType: String = "default"
Expand All @@ -70,6 +79,12 @@ private class BuildSourceImpl(val snapshotRepos: List<String>, val koverVersion:
copy = false
}

override fun kover(config: KoverProjectExtension.(ProjectScope) -> Unit) {
koverBlocks += { language, gradle ->
printGradleDsl<KoverProjectExtension, ProjectScope>(language, gradle, "kover", config)
}
}

override fun generate(): GradleBuild {
val actualDir = dir ?: throw Exception("No source was specified for the build")
val targetDir = if (copy) {
Expand All @@ -88,6 +103,9 @@ private class BuildSourceImpl(val snapshotRepos: List<String>, val koverVersion:
val buildSrcScript = targetDir.buildSrc?.build
buildSrcScript?.patchKoverDependency(koverVersion)

val buildScript = targetDir.build
buildScript.addKoverBlocks(koverBlocks)

return GradleBuildImpl(targetDir, copy, buildName, buildType)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,17 @@ internal fun File.patchKoverDependency(koverVersion: String) {
}
}
}

internal fun File.addKoverBlocks(koverBlocks: MutableList<(ScriptLanguage, String) -> String>) {
if (koverBlocks.isEmpty()) return

val language = if (name.endsWith(".kts")) ScriptLanguage.KTS else ScriptLanguage.GROOVY

val builder = StringBuilder()
koverBlocks.forEach { block ->
builder.appendLine()
builder.append(block(language, "8.12"))
builder.appendLine()
}
appendText(builder.toString())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
kotlin("jvm") version "2.1.0"
id("org.jetbrains.kotlinx.kover") version "0.7.0"
}

sourceSets.create("extra")
sourceSets.create("foo")

dependencies {
testImplementation(kotlin("test"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
rootProject.name = "example-source-multi"

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kotlinx.kover.examples.sourcesets

class ExtraClass {
fun function() {
println("Example")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kotlinx.kover.examples.sourcesets

class FooClass {
fun function() {
println("Example")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kotlinx.kover.examples.sourcesets

class MainClass {
fun function() {
println("Example")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kotlinx.kover.examples.sourcesets

import kotlin.test.Test

class TestClasses {
@Test
fun test() {
// no-tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private fun KoverVariantSources.wrap(project: Project): KoverMergingVariantSourc
return object : KoverMergingVariantSources {
override val excludeJava: Property<Boolean> = this@wrap.excludeJava
override val excludedSourceSets: SetProperty<String> = this@wrap.excludedSourceSets
override val excludedOtherSourceSets: SetProperty<String> = this@wrap.excludedOtherSourceSets
override val project: Project = project
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import kotlinx.kover.gradle.plugin.commons.VariantOriginAttr
import kotlinx.kover.gradle.plugin.dsl.internal.KoverVariantConfigImpl
import kotlinx.kover.gradle.plugin.appliers.origin.JvmVariantOrigin
import kotlinx.kover.gradle.plugin.commons.JVM_VARIANT_NAME
import kotlinx.kover.gradle.plugin.dsl.KoverVariantSources
import kotlinx.kover.gradle.plugin.dsl.internal.KoverProjectExtensionImpl
import kotlinx.kover.gradle.plugin.tools.CoverageTool
import org.gradle.api.Project
Expand Down Expand Up @@ -48,9 +49,26 @@ internal class JvmVariantArtifacts(
}

fromOrigin(variantOrigin) { compilationName ->
compilationName !in variantConfig.sources.excludedSourceSets.get()
&& compilationName != "test"
compilationIsExcluded(compilationName, variantConfig.sources)
}
}

private fun compilationIsExcluded(compilationName: String, variant: KoverVariantSources): Boolean {
if (compilationName in variant.excludedSourceSets.get()) {
return false
}

val included = variant.excludedOtherSourceSets.get()
// if `test` is not included so we need to check it
if (compilationName == "test" && "test" !in included) {
return false
}

if (included.isNotEmpty() && compilationName !in included) {
return false
}

return true
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ public interface KoverVariantConfig {
*
* // exclude source classes of specified source sets from all reports
* excludedSourceSets.addAll(excludedSourceSet)
*
* // exclude classes of all non-specified source sets from all reports.
* excludedOtherSourceSets.addAll(includedSourceSet)
* ```
*/
public fun sources(block: Action<KoverVariantSources>)
Expand Down Expand Up @@ -152,6 +155,9 @@ public interface KoverVariantConfig {
*
* // exclude source classes of specified source sets from all reports
* excludedSourceSets.addAll(excludedSourceSet)
*
* // exclude classes of all non-specified source sets from all reports.
* excludedOtherSourceSets.addAll(includedSourceSet)
* ```
*/
@KoverGradlePluginDsl
Expand All @@ -165,6 +171,13 @@ public interface KoverVariantSources {
* Exclude source classes of specified source sets from all reports
*/
public val excludedSourceSets: SetProperty<String>

/**
* Exclude classes of all non-specified source sets from all reports.
*
* Classes from source sets that are not listed here will not be included in the report.
*/
public val excludedOtherSourceSets: SetProperty<String>
}

/**
Expand Down
Loading

0 comments on commit cd71b38

Please sign in to comment.