Skip to content

Commit

Permalink
Improved Kover Settings plugin
Browse files Browse the repository at this point in the history
- fixed small bug with non-existing binary report files
- added ability to skip projects
- added ability to limit instrumented class globally and locally in a project
- added ability to exclude test task from instrumentation in a project config
- implement feature to check verification rule on every project

PR #689

Co-authored-by: Leonid Startsev <sandwwraith@users.noreply.github.com>
  • Loading branch information
shanshin and sandwwraith authored Oct 3, 2024
1 parent eaf3a92 commit 1acc054
Show file tree
Hide file tree
Showing 37 changed files with 922 additions and 97 deletions.
26 changes: 26 additions & 0 deletions kover-gradle-plugin/api/kover-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,24 @@ public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/Bo
public abstract fun getMinValue ()Lorg/gradle/api/provider/Property;
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/InstrumentationSettings {
public abstract fun getExcludedClasses ()Lorg/gradle/api/provider/SetProperty;
public abstract fun getIncludedClasses ()Lorg/gradle/api/provider/SetProperty;
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/KoverProjectExtension {
public abstract fun getInstrumentation ()Lkotlinx/kover/gradle/aggregation/settings/dsl/ProjectInstrumentationSettings;
public abstract fun instrumentation (Lorg/gradle/api/Action;)V
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/KoverSettingsExtension {
public abstract fun enableCoverage ()V
public abstract fun getInstrumentation ()Lkotlinx/kover/gradle/aggregation/settings/dsl/InstrumentationSettings;
public abstract fun getReports ()Lkotlinx/kover/gradle/aggregation/settings/dsl/ReportsSettings;
public abstract fun getSkipProjects ()Lorg/gradle/api/provider/SetProperty;
public abstract fun instrumentation (Lorg/gradle/api/Action;)V
public abstract fun reports (Lorg/gradle/api/Action;)V
public fun skipProjects ([Ljava/lang/String;)V
}

public final class kotlinx/kover/gradle/aggregation/settings/dsl/KoverSettingsExtensionKt {
Expand All @@ -28,6 +42,17 @@ public final class kotlinx/kover/gradle/aggregation/settings/dsl/KoverSettingsEx
public static synthetic fun minBound$default (Lkotlinx/kover/gradle/aggregation/settings/dsl/VerificationRuleSettings;ILkotlinx/kover/gradle/plugin/dsl/CoverageUnit;Lkotlinx/kover/gradle/plugin/dsl/AggregationType;ILjava/lang/Object;)V
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/ProjectInstrumentationSettings {
public abstract fun getDisabledForTestTasks ()Lorg/gradle/api/provider/SetProperty;
public abstract fun getExcludedClasses ()Lorg/gradle/api/provider/SetProperty;
public abstract fun getIncludedClasses ()Lorg/gradle/api/provider/SetProperty;
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/ProjectVerificationRuleSettings : kotlinx/kover/gradle/aggregation/settings/dsl/VerificationRuleSettings {
public abstract fun getProjectName ()Ljava/lang/String;
public abstract fun getProjectPath ()Ljava/lang/String;
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/ReportFiltersSettings {
public fun clearFilters ()V
public abstract fun getExcludedClasses ()Lorg/gradle/api/provider/SetProperty;
Expand Down Expand Up @@ -56,6 +81,7 @@ public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/Ve
}

public abstract interface class kotlinx/kover/gradle/aggregation/settings/dsl/VerifySettings {
public abstract fun eachProjectRule (Lorg/gradle/api/Action;)V
public abstract fun getRules ()Lorg/gradle/api/provider/ListProperty;
public abstract fun getWarningInsteadOfFailure ()Lorg/gradle/api/provider/Property;
public abstract fun rule (Ljava/lang/String;Lorg/gradle/api/Action;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kotlinx.kover.gradle.plugin.test.functional.cases

import kotlinx.kover.gradle.plugin.test.functional.framework.checker.CheckerContext
import kotlinx.kover.gradle.plugin.test.functional.framework.starter.TemplateTest
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
Expand Down Expand Up @@ -132,8 +133,35 @@ Rule violated: lines covered percentage is 50.000000, but expected maximum is 10
fun CheckerContext.testVerifyMin() {
taskOutput("koverVerify") {
assertTrue(contains("Rule 'CLI parameters' violated:\n" +
" lines covered percentage is 7.407400, but expected minimum is 100\n" +
" lines covered percentage is 7.407400, but expected maximum is 5"))
" lines covered percentage is 7.407400, but expected maximum is 5\n" +
" lines covered percentage is 7.407400, but expected minimum is 100"))
}
}

@TemplateTest("settings-plugin-verify-each", ["check", "-Dorg.gradle.unsafe.isolated-projects=true", "--configuration-cache", "--build-cache"])
fun CheckerContext.testVerifyEach() {
taskOutput("koverProjectVerify") {
assertContains(this, "Kover Verification Error\n" +
"Rule 'Coverage for project 'subproject'' violated: lines covered percentage is 50.000000, but expected minimum is 100\n" +
"\n" +
"Rule 'Coverage for project 'subproject2'' violated: lines covered percentage is 66.666700, but expected minimum is 100")
}
}

@TemplateTest("settings-plugin-instrumentation", ["check", "koverXmlReport", "-Dorg.gradle.unsafe.isolated-projects=true", "--configuration-cache", "--build-cache"])
fun CheckerContext.testInstrumentationConfiguring() {
xmlReport {
// all classes matches to pattern '*Class' should be excluded from instrumentation
classCounter("tests.settings.root.RootClass").assertFullyMissed()
classCounter("tests.settings.subproject.SubprojectClass").assertFullyMissed()

// all classes from subproject2 should be uncovered as 'test' task isn't instrumented
classCounter("tests.settings.subproject2.Subproject2Class").assertFullyMissed()
classCounter("tests.settings.subproject2.Tested").assertFullyMissed()

// other classes should be covered
classCounter("tests.settings.root.Tested").assertFullyCovered()
classCounter("tests.settings.subproject.Tested").assertFullyCovered()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
kotlin("jvm") version ("2.0.0")
}

dependencies {
testImplementation(kotlin("test"))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}

plugins {
id("org.jetbrains.kotlinx.kover.aggregation") version "SNAPSHOT"
}

extensions.configure<kotlinx.kover.gradle.aggregation.settings.dsl.KoverSettingsExtension> {
enableCoverage()

instrumentation.excludedClasses.add("*Class")
}

buildCache {
local {
directory = "$settingsDir/build-cache"
}
}

rootProject.name = "settings-plugin-verify"

include(":subproject")
include(":subproject2")
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.root

import java.lang.AutoCloseable

class RootClass {
fun action() {
println("It's root class")
}
}

class Tested {
fun action() {
println("It's tested root class")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.root

import kotlin.test.Test

class RootTest {
@Test
fun test() {
RootClass().action()
Tested().action()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
kotlin("jvm")
}

dependencies {
testImplementation(kotlin("test"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.subproject

class SubprojectClass {
fun action() {
println("It's class from the subproject")
}
}

class Tested {
fun action() {
println("It's tested subproject class")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.subproject

import kotlin.test.Test

class SubprojectTest {
@Test
fun test() {
SubprojectClass().action()
Tested().action()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import kotlinx.kover.gradle.aggregation.settings.dsl.*

plugins {
kotlin("jvm")
}

dependencies {
testImplementation(kotlin("test"))
}

extensions.configure<KoverProjectExtension> {
instrumentation.disabledForTestTasks.add("test")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.subproject2

class Subproject2Class {
fun action() {
println("It's class from the subproject2")
}
}

class Tested {
fun action() {
println("It's tested subproject2 class")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.subproject2

import kotlin.test.Test

class Subproject2Test {
@Test
fun test() {
Subproject2Class().action()
Tested().action()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
kotlin("jvm") version ("2.0.0")
}

dependencies {
implementation(project(":subproject"))
implementation(project(":ignored"))

testImplementation(kotlin("test"))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
kotlin("jvm")
}

dependencies {
testImplementation(kotlin("test"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.ignored

class SubprojectClass {
fun action() {
println("It's class from the subproject")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package tests.settings.ignored

import kotlin.test.Test

class SubprojectTest {
@Test
fun test() {
SubprojectClass().action()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}

import kotlinx.kover.gradle.aggregation.settings.dsl.*

plugins {
id("org.jetbrains.kotlinx.kover.aggregation") version "SNAPSHOT"
}

extensions.configure<kotlinx.kover.gradle.aggregation.settings.dsl.KoverSettingsExtension> {
enableCoverage()

skipProjects(
// skip root project and everything works ok
// skip by path
":",
// skip by project name
"ignored"
)

reports {
verify {
warningInsteadOfFailure = true

eachProjectRule {
minBound(100)
}
}
}
}

buildCache {
local {
directory = "$settingsDir/build-cache"
}
}

rootProject.name = "settings-plugin-verify"

include(":subproject")
include(":subproject2")
include(":ignored")
Loading

0 comments on commit 1acc054

Please sign in to comment.