diff --git a/README.md b/README.md
index 19dc5a38..aab59533 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ Kover is a set of solutions for collecting test coverage of Kotlin code compiled
Kover Toolset:
- [Kover Gradle Plugin](#kover-gradle-plugin)
+- [Kover Maven Plugin](#kover-maven-plugin)
- [Kover CLI](#kover-cli)
- [Kover offline instrumentation](#kover-offline-instrumentation)
- [Kover JVM agent](#kover-jvm-agent)
@@ -119,6 +120,21 @@ It is in its infancy, it is recommended to use it only for test or pet projects.
Refer to the [documentation](https://kotlin.github.io/kotlinx-kover/gradle-plugin/aggregated.html) for details.
+## Kover Maven Plugin
+The Kover Maven Plugin can be applied by specifying build plugin
+```xml
+
+ org.jetbrains.kotlinx
+ kover-maven-plugin
+ 0.8.2
+
+```
+
+The list of Kover goals is specified in [this document section](https://kotlin.github.io/kotlinx-kover/maven-plugin#goals).
+
+For full information about latest stable release of Kover Gradle Plugin, please refer to the [documentation](https://kotlin.github.io/kotlinx-kover/maven-plugin).
+
+
## Kover CLI
Standalone JVM application used for offline instrumentation and generation of human-readable reports.
diff --git a/build-logic/src/main/kotlin/kotlinx/kover/conventions/kover-docs-conventions.gradle.kts b/build-logic/src/main/kotlin/kotlinx/kover/conventions/kover-docs-conventions.gradle.kts
index ad76b68e..10bf3cf2 100644
--- a/build-logic/src/main/kotlin/kotlinx/kover/conventions/kover-docs-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/kotlinx/kover/conventions/kover-docs-conventions.gradle.kts
@@ -26,7 +26,7 @@ extension.callDokkaHtml.convention(false)
tasks.register("releaseDocs") {
dependsOn(
- tasks.matching { extension.callDokkaHtml.get() && it.name == "dokkaHtml" }
+ tasks.named { it == "dokkaHtml" }.matching { extension.callDokkaHtml.get() }
)
doLast {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e300a786..3df2461c 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,11 +1,16 @@
[versions]
-intellij-coverage = "1.0.760"
+intellij-coverage = "1.0.761"
junit = "5.9.0"
kotlinx-bcv = "0.13.2"
kotlinx-dokka = "1.8.10"
args4j = "2.33"
gradle-plugin-publish = "1.2.1"
+maven-plugin-development = "0.4.3"
+maven-embedder = "3.9.8"
+maven-api = "3.0"
+maven-resolver = "1.9.21"
+maven-slf4j = "1.7.36"
[libraries]
@@ -20,9 +25,26 @@ junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref
args4j = { module = "args4j:args4j", version.ref = "args4j" }
-gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin" }
+gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin" }
+
+maven-embedder = { module = "org.apache.maven:maven-embedder", version.ref = "maven-embedder" }
+maven-compat = { module = "org.apache.maven:maven-compat", version.ref = "maven-embedder" }
+maven-slf4j-provider = { module = "org.apache.maven:maven-slf4j-provider", version.ref = "maven-embedder" }
+
+maven-plugin-annotations = { module = "org.apache.maven.plugin-tools:maven-plugin-annotations", version.ref = "maven-api" }
+maven-core = { module = "org.apache.maven:maven-core", version.ref = "maven-api" }
+maven-reporting-api = { module = "org.apache.maven.reporting:maven-reporting-api", version.ref = "maven-api" }
+
+maven-resolver-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "maven-resolver" }
+maven-resolver-file = { module = "org.apache.maven.resolver:maven-resolver-transport-file", version.ref = "maven-resolver" }
+maven-resolver-http = { module = "org.apache.maven.resolver:maven-resolver-transport-http", version.ref = "maven-resolver" }
+
+maven-slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "maven-slf4j" }
+
[plugins]
-gradle-pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "gradle-plugin-publish" }
+gradle-pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "gradle-plugin-publish" }
kotlinx-binaryCompatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinx-bcv" }
kotlinx-dokka = { id = "org.jetbrains.dokka", version.ref = "kotlinx-dokka" }
+mavenPluginDevelopment = { id = "de.benediktritter.maven-plugin-development", version.ref = "maven-plugin-development" }
+
diff --git a/kover-cli/build.gradle.kts b/kover-cli/build.gradle.kts
index 9979effb..ea7688f3 100644
--- a/kover-cli/build.gradle.kts
+++ b/kover-cli/build.gradle.kts
@@ -24,7 +24,7 @@ plugins {
id("kover-release-conventions")
}
-extensions.configure {
+koverPublication {
description.set("Command Line Interface for Kotlin Coverage Toolchain")
}
@@ -65,7 +65,7 @@ repositories {
mavenCentral()
}
-extensions.configure {
+koverDocs {
docsDirectory.set("cli")
description.set("Kover Command Line Interface")
}
diff --git a/kover-features-jvm/api/kover-features-jvm.api b/kover-features-jvm/api/kover-features-jvm.api
index bc735c6c..062886be 100644
--- a/kover-features-jvm/api/kover-features-jvm.api
+++ b/kover-features-jvm/api/kover-features-jvm.api
@@ -106,6 +106,7 @@ public final class kotlinx/kover/features/jvm/KoverLegacyFeatures {
public final fun generateXmlReport (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Lkotlinx/kover/features/jvm/ClassFilters;)V
public final fun instrument (Ljava/io/File;Ljava/util/List;Lkotlinx/kover/features/jvm/ClassFilters;Z)V
public final fun verify (Ljava/util/List;Ljava/io/File;Lkotlinx/kover/features/jvm/ClassFilters;Ljava/util/List;Ljava/util/List;)Ljava/util/List;
+ public final fun violationMessage (Ljava/util/List;)Ljava/lang/String;
}
public abstract interface class kotlinx/kover/features/jvm/OfflineInstrumenter {
diff --git a/kover-features-jvm/build.gradle.kts b/kover-features-jvm/build.gradle.kts
index 4f320a90..1f9a3817 100644
--- a/kover-features-jvm/build.gradle.kts
+++ b/kover-features-jvm/build.gradle.kts
@@ -25,7 +25,7 @@ plugins {
id("kover-release-conventions")
}
-extensions.configure {
+koverPublication {
description.set("Implementation of calling the main features of Kover programmatically")
}
diff --git a/kover-features-jvm/src/main/java/kotlinx/kover/features/jvm/KoverLegacyFeatures.kt b/kover-features-jvm/src/main/java/kotlinx/kover/features/jvm/KoverLegacyFeatures.kt
index 7b22402e..f5731ff5 100644
--- a/kover-features-jvm/src/main/java/kotlinx/kover/features/jvm/KoverLegacyFeatures.kt
+++ b/kover-features-jvm/src/main/java/kotlinx/kover/features/jvm/KoverLegacyFeatures.kt
@@ -183,6 +183,30 @@ public object KoverLegacyFeatures {
return result
}
+
+ public fun violationMessage(violations: List): String {
+ if (violations.isEmpty()) {
+ return ""
+ }
+ val messageBuilder = StringBuilder()
+
+ violations.forEach { rule ->
+ val namedRule = if (rule.rule.name.isNotEmpty()) "Rule '${rule.rule.name}'" else "Rule"
+
+ if (rule.violations.size == 1) {
+ messageBuilder.appendLine("$namedRule violated: ${rule.violations[0].format(rule)}")
+ } else {
+ messageBuilder.appendLine("$namedRule violated:")
+
+ rule.violations.forEach { bound ->
+ messageBuilder.append(" ")
+ messageBuilder.appendLine(bound.format(rule))
+ }
+ }
+ }
+
+ return messageBuilder.toString()
+ }
}
/**
@@ -251,3 +275,30 @@ public data class ClassFilters(
*/
public val excludeInheritedFrom: Set
)
+
+private fun BoundViolation.format(rule: RuleViolations): String {
+ val directionText = if (isMax) "maximum" else "minimum"
+
+ val metricText = when (bound.coverageUnits) {
+ CoverageUnit.LINE -> "lines"
+ CoverageUnit.INSTRUCTION -> "instructions"
+ CoverageUnit.BRANCH -> "branches"
+ }
+
+ val valueTypeText = when (bound.aggregationForGroup) {
+ AggregationType.COVERED_COUNT -> "covered count"
+ AggregationType.MISSED_COUNT -> "missed count"
+ AggregationType.COVERED_PERCENTAGE -> "covered percentage"
+ AggregationType.MISSED_PERCENTAGE -> "missed percentage"
+ }
+
+ val entityText = when (rule.rule.groupBy) {
+ GroupingBy.APPLICATION -> ""
+ GroupingBy.CLASS -> " for class '$entityName'"
+ GroupingBy.PACKAGE -> " for package '$entityName'"
+ }
+
+ val expectedValue = if (isMax) bound.maxValue else bound.minValue
+
+ return "$metricText $valueTypeText$entityText is $value, but expected $directionText is $expectedValue"
+}
diff --git a/kover-gradle-plugin/build.gradle.kts b/kover-gradle-plugin/build.gradle.kts
index 68d9433a..d5bd0b3e 100644
--- a/kover-gradle-plugin/build.gradle.kts
+++ b/kover-gradle-plugin/build.gradle.kts
@@ -189,13 +189,13 @@ tasks.dokkaHtml {
}
}
-extensions.configure {
+koverDocs {
docsDirectory.set("gradle-plugin")
description.set("Kover Gradle Plugin")
callDokkaHtml.set(true)
}
-extensions.configure {
+koverPublication {
description.set("Kover Gradle Plugin - Kotlin code coverage")
//`java-gradle-plugin` plugin already creates publication with name `pluginMaven`
addPublication.set(false)
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tasks/reports/KoverDoVerifyTask.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tasks/reports/KoverDoVerifyTask.kt
index 859be5de..627ffc65 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tasks/reports/KoverDoVerifyTask.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tasks/reports/KoverDoVerifyTask.kt
@@ -4,8 +4,8 @@
package kotlinx.kover.gradle.plugin.tasks.reports
+import kotlinx.kover.features.jvm.KoverLegacyFeatures
import kotlinx.kover.gradle.plugin.commons.VerificationRule
-import kotlinx.kover.gradle.plugin.tools.generateErrorMessage
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.*
@@ -24,7 +24,7 @@ internal abstract class KoverDoVerifyTask @Inject constructor(@get:Internal over
val enabledRules = rules.get().filter { it.isEnabled }
val violations = tool.get().verify(enabledRules, context())
- val errorMessage = generateErrorMessage(violations)
+ val errorMessage = KoverLegacyFeatures.violationMessage(violations)
resultFile.get().asFile.writeText(errorMessage)
}
diff --git a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tools/Verification.kt b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tools/Verification.kt
index 226af0c7..9d1186f7 100644
--- a/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tools/Verification.kt
+++ b/kover-gradle-plugin/src/main/kotlin/kotlinx/kover/gradle/plugin/tools/Verification.kt
@@ -41,57 +41,3 @@ internal data class CoverageRequest(
val header: String?,
val lineFormat: String,
): Serializable
-
-internal fun generateErrorMessage(violations: List): String {
- if (violations.isEmpty()) {
- return ""
- }
- val messageBuilder = StringBuilder()
-
- violations.forEach { rule ->
- val namedRule = if (rule.rule.name.isNotEmpty()) "Rule '${rule.rule.name}'" else "Rule"
-
- if (rule.violations.size == 1) {
- messageBuilder.appendLine("$namedRule violated: ${rule.violations[0].format(rule)}")
- } else {
- messageBuilder.appendLine("$namedRule violated:")
-
- rule.violations.forEach { bound ->
- messageBuilder.append(" ")
- messageBuilder.appendLine(bound.format(rule))
- }
- }
- }
-
- return messageBuilder.toString()
-}
-
-private fun BoundViolation.format(rule: RuleViolations): String {
- val directionText = if (isMax) "maximum" else "minimum"
-
- val metricText = when (bound.coverageUnits) {
- FeatureCoverageUnit.LINE -> "lines"
- FeatureCoverageUnit.INSTRUCTION -> "instructions"
- FeatureCoverageUnit.BRANCH -> "branches"
- }
-
- val valueTypeText = when (bound.aggregationForGroup) {
- FeatureAggregationType.COVERED_COUNT -> "covered count"
- FeatureAggregationType.MISSED_COUNT -> "missed count"
- FeatureAggregationType.COVERED_PERCENTAGE -> "covered percentage"
- FeatureAggregationType.MISSED_PERCENTAGE -> "missed percentage"
- }
-
- val entityText = when (rule.rule.groupBy) {
- GroupingBy.APPLICATION -> ""
- GroupingBy.CLASS -> " for class '$entityName'"
- GroupingBy.PACKAGE -> " for package '$entityName'"
- }
-
- val expectedValue = if (isMax) bound.maxValue else bound.minValue
-
- return "$metricText $valueTypeText$entityText is $value, but expected $directionText is $expectedValue"
-}
-
-private typealias FeatureCoverageUnit = kotlinx.kover.features.jvm.CoverageUnit
-private typealias FeatureAggregationType = kotlinx.kover.features.jvm.AggregationType
\ No newline at end of file
diff --git a/kover-jvm-agent/build.gradle.kts b/kover-jvm-agent/build.gradle.kts
index 4ea34375..bc7de345 100644
--- a/kover-jvm-agent/build.gradle.kts
+++ b/kover-jvm-agent/build.gradle.kts
@@ -22,11 +22,11 @@ plugins {
id("kover-release-conventions")
}
-extensions.configure {
+koverPublication {
description.set("Kover JVM instrumentation agent")
}
-extensions.configure {
+koverDocs {
docsDirectory.set("jvm-agent")
description.set("Kover JVM instrumentation agent")
}
diff --git a/kover-maven-plugin/build.gradle.kts b/kover-maven-plugin/build.gradle.kts
new file mode 100644
index 00000000..eaca601d
--- /dev/null
+++ b/kover-maven-plugin/build.gradle.kts
@@ -0,0 +1,101 @@
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+
+/*
+ * Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ kotlin("jvm")
+ id("kover-publishing-conventions")
+ id("kover-docs-conventions")
+ id("kover-release-conventions")
+
+ alias(libs.plugins.mavenPluginDevelopment)
+}
+
+
+repositories {
+ mavenCentral()
+}
+
+sourceSets {
+ create("functionalTest")
+}
+
+// name of configuration for functionalTest source set with implementation dependencies
+val functionalTestImplementation = "functionalTestImplementation"
+
+
+dependencies {
+ implementation(project(":kover-features-jvm"))
+ implementation(project(":kover-jvm-agent"))
+
+ snapshotRelease(project(":kover-features-jvm"))
+ snapshotRelease(project(":kover-jvm-agent"))
+
+ compileOnly(libs.maven.plugin.annotations)
+ compileOnly(libs.maven.core)
+ implementation(libs.maven.reporting.api)
+
+ functionalTestImplementation(libs.maven.embedder)
+ functionalTestImplementation(libs.maven.compat)
+
+
+ functionalTestImplementation(libs.maven.resolver.basic)
+ functionalTestImplementation(libs.maven.resolver.file)
+ functionalTestImplementation(libs.maven.resolver.http)
+ functionalTestImplementation(libs.maven.slf4j.api)
+ functionalTestImplementation(libs.maven.slf4j.provider)
+
+
+ functionalTestImplementation(kotlin("test"))
+ functionalTestImplementation(libs.junit.jupiter)
+ functionalTestImplementation(libs.junit.params)
+}
+
+mavenPlugin {
+ goalPrefix = "kover"
+}
+
+kotlin {
+ jvmToolchain {
+ languageVersion.set(JavaLanguageVersion.of(8))
+ }
+}
+
+val functionalTest by tasks.registering(Test::class) {
+ group = LifecycleBasePlugin.VERIFICATION_GROUP
+ testClassesDirs = sourceSets["functionalTest"].output.classesDirs
+ classpath = sourceSets["functionalTest"].runtimeClasspath
+
+ // use JUnit 5
+ useJUnitPlatform()
+
+ dependsOn(tasks.collectRepository)
+
+ val localRepository = layout.buildDirectory.dir("maven-collected")
+ doFirst {
+ systemProperties["kotlinVersion"] = embeddedKotlinVersion
+ systemProperties["koverVersion"] = version
+
+ val dir = localRepository.get().asFile
+ dir.deleteRecursively()
+ dir.mkdirs()
+
+ tasks.collectRepository.get().repositories.forEach { repository ->
+ repository.copyRecursively(dir)
+ }
+
+ systemProperties["snapshotRepository"] = dir.absolutePath
+ }
+}
+
+tasks.check {
+ dependsOn(functionalTest)
+}
+
+koverDocs {
+ docsDirectory.set("maven-plugin")
+ description.set("Kover Maven Plugin")
+ callDokkaHtml.set(false)
+}
diff --git a/kover-maven-plugin/docs/index.md b/kover-maven-plugin/docs/index.md
new file mode 100644
index 00000000..7a61f4d3
--- /dev/null
+++ b/kover-maven-plugin/docs/index.md
@@ -0,0 +1,376 @@
+# Kover Maven Plugin
+
+Maven plugin to measure test coverage and generate human-readable reports with coverage values.
+
+## Table of contents
+ * [Requirements](#requirements)
+ * [Current limitations](#current-limitations)
+ * [Quickstart](#quickstart)
+ * [Maven Goals](#goals)
+ * [Multi-module projects](#multi-module-projects)
+ * [Configuration](#configuration)
+ * [Coverage values](#coverage-values)
+ * [Examples](#examples)
+
+## Requirements
+- Maven 3.0 or higher
+- Java 1.8 or higher for Maven runtime
+
+## Current limitations
+- only instrumentation of tests in `test` goal is supported; `it-tests` tests are not supported yet
+- if several Kover JVM agents are specified when running the tests, then only the first one will work. This situation may happen when the plugin is used during `site` lifecycle (see in examples below), so use such a setup with caution.
+- simultaneous use of several instrumentation agents can lead to unpredictable consequences and unstable operation
+
+## Quickstart
+To use Kover coverage measurement it is necessary to add plugin `org.jetbrains.kotlinx:kover-maven-plugin:0.8.2` to build configuration in `pom.xml` and create executions for used goals.
+
+With the following configuration HTML and XML reports will be generated, and verification rules will be checked on `verify` phase:
+```xml
+
+
+
+
+
+
+
+ org.jetbrains.kotlinx
+ kover-maven-plugin
+ 0.8.2
+
+
+
+ instr
+
+ instrumentation
+
+
+
+
+
+ kover-xml
+
+ report-xml
+
+
+
+
+
+ kover-html
+
+ report-html
+
+
+
+
+
+ kover-verify
+
+ verify
+
+
+
+
+
+
+```
+
+## Goals
+Kover Maven Plugin provides the following goals:
+ - `instrumentation` - activate the measurement of the coverage in tests
+ - `report-xml` - generate XML coverage report in JaCoCo format
+ - `report-html` - generate HTML coverage report
+ - `report-ic` - generate binary coverage report in intellij coverage agent format
+ - `verify` - check specified coverage rules
+ - `log` - print coverage values to the Maven log
+
+## Multi-module projects
+If the project consists of several modules, then the source classes and tests can be distributed across several modules.
+
+In this case, it becomes necessary to generate reports for several modules at once.
+
+In order to activate the creation of reports on several projects, you need to add this configuration flag:
+`true` into the Kover Plugin `configuration` block.
+
+Then, the classes in the report will be collected for all modules specified in the `dependencies` block, except for those for which the scope is `test`.
+And the coverage will be collected from tests located in modules that are also in the `dependencies` block, including dependencies with the `test` scope.
+
+See the full [example project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/merged-report).
+
+## Configuration
+
+All available configuration options are shown below:
+```xml
+
+
+ org.jetbrains.kotlinx
+ kover-maven-plugin
+ 0.8.2
+
+
+
+ instr
+
+ instrumentation
+
+
+
+
+
+ kover-xml
+
+ report-xml
+
+
+
+
+
+ kover-html
+
+ report-html
+
+
+
+
+
+ kover-verify
+
+ verify
+
+
+
+
+
+ kover-ic
+
+ report-ic
+
+
+
+
+
+ kover-log
+
+ log
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+ com.example.*,excluded.from.instrumentation.*
+
+
+
+ argLine
+
+
+
+
+
+
+
+
+
+
+
+
+ com.example.*.ExcludedByName,com.example.*.serializables.*$Companion
+
+
+
+
+ *.Generated
+
+
+
+
+
+
+
+
+
+
+
+ java.lang.AutoCloseable
+
+
+
+
+ test-utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+ ${project.basedir}/external/report.ic
+
+
+
+
+ html
+
+
+
+
+ My title
+
+
+
+ UTF-8
+
+
+
+ ${project.build.directory}/custom.ic
+
+
+
+ ${project.build.directory}/custom.xml
+
+
+
+
+ APPLICATION
+
+
+
+
+ BRANCH
+
+
+
+
+
+
+ MISSED_COUNT
+
+
+
+
+
+
+
+ Full coverage is {value}%
+
+
+
+ true
+
+
+
+
+
+
+
+
+ package covered lines
+
+
+
+
+ PACKAGE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MISSED_COUNT
+
+
+
+
+
+ LINE
+
+
+
+
+ 90
+
+
+
+
+ 10
+
+
+
+
+
+
+```
+
+### Coverage values
+During verification, the entire code is divided into units for which Kover determines whether it was covered (executed) or skipped (not executed).
+For example, an entire line from source code or a specific JVM instruction from compiled byte-code can be executed or not.
+
+All units are grouped into one or more groups.
+Based on amount of the executed and non-executed code units, one number (coverage value) will be calculated for each group using the aggregation function.
+
+Type `CoverageUnit` determines for which types of units the coverage will be measured.
+It can be:
+- `LINE`. This is a default value.
+- `INSTRUCTION`.
+- `BRANCH`.
+
+For comparison with the specified boundaries, the number of covered (executed) or skipped (not executed) units should be aggregated into one number.
+`AggregationType` determines exactly how the current measurement value will be calculated:
+- `COVERED_COUNT` - the total number of units of code that were executed.
+- `MISSED_COUNT` - the total number of units of code that were not executed.
+- `COVERED_PERCENTAGE` - is the number of covered units divided by the number of all units and multiplied by 100. This is a default value.
+- `MISSED_PERCENTAGE` - is the number of uncovered units divided by the number of all units and multiplied by 100.
+
+To calculate the coverage value, units are grouped by various entities.
+By default, all application units of code are grouped by a single application entity, so one coverage value is calculated for the entire application using the aggregating function.
+
+But you can group code units by other named entities.
+The `GroupingEntityType` type is used for this:
+- `APPLICATION` - one current coverage value for the entire application will be calculated. This is a default value.
+- `CLASS` - the coverage value will be calculated individually for each class. So the bounds will be checked for each class.
+- `PACKAGE` - the coverage value will be calculated individually for all classes in each package. So the bounds will be checked for each package.
+
+## Examples
+- Enable all Kover goals in Kotlin project: [directory](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/all-goals)
+- Specifying common filters for all reports and verification rules: [directory](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/filters-common)
+- Override filters in verification rules: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/filters-rules)
+- Use externally generated binary IC report to merge coverage: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/additional-binary-report)
+- Override standard parameter of surefire plugin to pass arguments to JVM: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/change-agent-line)
+- Change paths to the XML, HTML and IC reports: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/change-paths)
+- Create merged (aggregated) report: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/merged-report)
+- Using Kover Maven Plugin in `site` lifecycle (`reporting` block) [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/site)
+- Skip Kover goals by configuration: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/skip-config)
+- Adding coverage verification rules: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/verify-error)
+- Print warning instead of verification error: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/verify-warn)
+- Configure coverage logging: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/logs)
+- Exclude class from instrumentation: [project](https://github.com/Kotlin/kotlinx-kover/tree/main/kover-maven-plugin/examples/exclude-instrumentation)
diff --git a/kover-maven-plugin/examples/additional-binary-report/additional.ic b/kover-maven-plugin/examples/additional-binary-report/additional.ic
new file mode 100644
index 00000000..e4b962af
--- /dev/null
+++ b/kover-maven-plugin/examples/additional-binary-report/additional.ic
@@ -0,0 +1,125 @@
+%kotlin.annotation.AnnotationRetention/org.junit.platform.engine.reporting.ReportEntry:org.junit.jupiter.engine.descriptor.MethodExtensionContextXorg.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService-org.junit.jupiter.api.extension.TestInstancesIorg.junit.jupiter.engine.execution.ExtensionValuesStore$MemoizingSupplierForg.junit.jupiter.engine.execution.JupiterEngineExecutionContext$State0org.junit.platform.launcher.core.LauncherFactory,org.apache.maven.surefire.report.RunListener'org.apache.maven.surefire.util.RunOrderGorg.junit.platform.engine.support.discovery.SelectorResolver$Match$Type1org.apache.maven.surefire.util.RunOrderCalculator-org.apache.maven.surefire.testset.TestRequesthorg.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall$VoidMethodInterceptorCall0org.junit.platform.launcher.core.DefaultLauncher3org.junit.platform.engine.EngineDiscoveryListener$14org.junit.jupiter.engine.extension.DisabledCondition/org.junit.platform.commons.function.Try$Success:org.junit.platform.launcher.listeners.LegacyReportingUtilsDorg.junit.platform.engine.support.discovery.SelectorResolver$Context>org.apache.maven.surefire.booter.CommandReader$CommandRunnable2org.junit.jupiter.engine.extension.TimeoutDuration8org.junit.jupiter.engine.extension.RepeatedTestExtension%kotlin.collections.AbstractCollection0org.junit.platform.engine.TestDescriptor$Visitor"kotlin.annotation.AnnotationTarget0org.junit.platform.engine.EngineDiscoveryRequestPorg.apache.maven.surefire.shade.org.apache.commons.io.output.StringBuilderWriter%org.junit.jupiter.api.TestMethodOrder8org.junit.jupiter.engine.descriptor.LifecycleMethodUtils+org.junit.platform.commons.util.StringUtils=org.junit.platform.engine.support.hierarchical.NodeTreeWalker9org.junit.jupiter.engine.descriptor.ClassExtensionContext0org.junit.jupiter.api.extension.ParameterContext/org.apache.maven.surefire.util.DirectoryScannerorg.junit.jupiter.api.AfterEach5org.apache.maven.surefire.util.internal.DumpFileUtils;org.apache.maven.surefire.booter.ForkedBooter$PingScheduler5org.junit.jupiter.engine.extension.ExtensionRegistrarorg.junit.platform.engine.support.hierarchical.Node$Invocation4org.apache.maven.surefire.booter.MainCliOptionsAware0kotlin.collections.CollectionsKt___CollectionsKt;org.apache.maven.surefire.testset.ResolvedTest$ClassMatcher1org.junit.jupiter.api.extension.ParameterResolver[org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution$DefaultContext:org.junit.jupiter.api.extension.ExtensionContext$Namespace'kotlinx.kover.maven.plugin.testing.Main;org.junit.platform.engine.support.hierarchical.ResourceLock%org.junit.platform.launcher.core.Rootorg.junit.jupiter.api.Disabledorg.junit.jupiter.api.AfterAll8org.junit.jupiter.engine.discovery.MethodOrderingVisitorVorg.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutororg.junit.jupiter.api.BeforeAll6org.junit.jupiter.api.extension.ExtensionContext$Store:org.junit.platform.engine.support.hierarchical.LockManager7org.junit.jupiter.engine.extension.TimeoutConfiguration2org.apache.maven.surefire.testset.TestListResolver8org.junit.jupiter.engine.extension.TimeoutDurationParser+org.junit.platform.engine.DiscoverySelector;org.junit.jupiter.engine.config.DefaultJupiterConfigurationWorg.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService$TestTask.org.apache.maven.surefire.util.ReflectionUtils#org.opentest4j.TestAbortedException+org.junit.jupiter.api.parallel.ResourceLock6org.apache.maven.surefire.report.ConsoleOutputReceiver*org.junit.jupiter.api.DisplayNameGenerator=org.apache.maven.surefire.junitplatform.JUnitPlatformProvider:org.apache.maven.surefire.booter.SurefireClassLoadersAwareSorg.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation2org.apache.maven.surefire.report.SimpleReportEntry3org.apache.maven.surefire.booter.DumpErrorSingleton6org.apache.maven.surefire.providerapi.AbstractProvider1org.junit.platform.engine.discovery.ClassSelectorCorg.junit.jupiter.engine.extension.TimeoutExtension$TimeoutProviderDorg.junit.jupiter.engine.discovery.MethodSelectorResolver$MethodType3org.apache.maven.surefire.booter.BooterDeserializer8org.junit.platform.engine.support.descriptor.ClassSource'org.junit.platform.commons.function.Try,org.apache.maven.surefire.util.ScannerFilterkotlin.enums.EnumEntriesJVMKt(org.junit.platform.engine.UniqueIdFormatForg.apache.maven.surefire.report.ConsoleOutputCapture$NullOutputStream4org.junit.jupiter.engine.execution.ExecutableInvoker1org.apache.maven.surefire.booter.TypeEncodedValueForg.junit.jupiter.engine.config.DisplayNameGeneratorParameterConverter8org.junit.jupiter.engine.execution.TestInstancesProvider4org.apache.maven.surefire.testset.GenericTestPattern+org.opentest4j.IncompleteExecutionExceptionorg.junit.jupiter.api.extension.TestInstancePreDestroyCallbackRorg.apache.maven.surefire.shade.org.apache.commons.io.output.ByteArrayOutputStreamAorg.junit.platform.commons.logging.LoggerFactory$DelegatingLogger/org.junit.platform.commons.util.CollectionUtils3org.junit.jupiter.engine.extension.TimeoutExtension$org.junit.platform.engine.TestSourceIorg.junit.platform.engine.support.hierarchical.ExclusiveResource$LockMode4org.junit.jupiter.engine.descriptor.DisplayNameUtilsorg.junit.jupiter.engine.descriptor.TestInstanceLifecycleUtils@org.junit.platform.launcher.core.LauncherConfigurationParametersKorg.junit.platform.launcher.core.ServiceLoaderTestExecutionListenerRegistry>org.junit.platform.engine.support.hierarchical.Node$SkipResult2org.apache.maven.surefire.testset.TestArtifactInfo6org.apache.maven.surefire.report.ReporterConfigurationForg.junit.jupiter.engine.discovery.MethodSelectorResolver$MethodType$3Forg.junit.jupiter.engine.discovery.MethodSelectorResolver$MethodType$2/org.apache.maven.surefire.booter.KeyValueSource.org.apache.maven.surefire.booter.CommandReaderForg.junit.jupiter.engine.discovery.MethodSelectorResolver$MethodType$1Borg.junit.platform.engine.support.hierarchical.NodeTestTaskContext-org.junit.platform.commons.util.Preconditions)org.junit.platform.commons.logging.Logger6org.apache.maven.surefire.booter.TestArtifactInfoAware!org.junit.jupiter.api.DisplayName,org.apache.maven.surefire.booter.ProcessInfo2org.junit.jupiter.api.extension.BeforeEachCallbackorg.junit.jupiter.engine.discovery.predicates.IsTestableMethod)org.apache.maven.surefire.util.ScanResult1org.junit.jupiter.api.extension.AfterEachCallback8org.junit.jupiter.engine.discovery.ClassSelectorResolver6org.junit.platform.launcher.core.DefaultLauncherConfig8org.junit.platform.engine.support.hierarchical.NodeUtils>org.junit.platform.launcher.core.TestExecutionListenerRegistry@org.junit.jupiter.engine.extension.TestReporterParameterResolver@org.junit.jupiter.api.extension.InvocationInterceptor$Invocation1org.apache.maven.surefire.booter.TestRequestAware:org.junit.jupiter.api.extension.TestInstanceFactoryContext/org.junit.platform.launcher.PostDiscoveryFilterNorg.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService4org.apache.maven.surefire.booter.BaseProviderFactoryAorg.junit.jupiter.engine.support.JupiterThrowableCollectorFactoryorg.junit.jupiter.api.Test0org.junit.platform.commons.util.ClassLoaderUtils@org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder8org.junit.jupiter.engine.execution.ConstructorInvocation;org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor%org.junit.platform.launcher.TagFilterkotlin.enums.EnumEntriesKt9org.apache.maven.surefire.booter.ClassLoaderConfiguration2org.apache.maven.surefire.booter.PropertiesWrapper-org.apache.maven.surefire.booter.ForkedBooter6org.apache.maven.plugin.surefire.log.api.ConsoleLoggergorg.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver$DefaultInitializationContext4org.apache.maven.surefire.booter.IsolatedClassLoader:org.junit.jupiter.engine.execution.BeforeEachMethodAdapter-org.junit.platform.engine.TestExecutionResult*org.junit.jupiter.engine.JupiterTestEngine@org.junit.platform.engine.support.hierarchical.ExclusiveResource*org.junit.jupiter.api.extension.Extensions)org.apache.maven.surefire.suite.RunResult1org.junit.jupiter.api.extension.RegisterExtensionkotlin.enums.EnumEntries:org.junit.jupiter.api.extension.TestInstantiationException5org.junit.jupiter.api.extension.InvocationInterceptor(org.junit.platform.launcher.EngineFilter3org.junit.jupiter.api.extension.TestInstanceFactory"org.junit.platform.engine.UniqueId/org.junit.platform.commons.util.ReflectionUtils>org.junit.platform.commons.util.PreconditionViolationException6org.apache.maven.surefire.booter.ProviderConfiguration3org.apache.maven.surefire.util.internal.ObjectUtilsKorg.apache.maven.surefire.report.ConsoleOutputCapture$ForwardingPrintStream9org.junit.jupiter.api.extension.ConditionEvaluationResult3org.apache.maven.surefire.booter.ForkingRunListenerRorg.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation5org.apache.maven.surefire.booter.MasterProcessCommand/org.junit.platform.commons.function.Try$Failure4org.junit.platform.engine.discovery.UniqueIdSelectorkotlin.annotation.Target3org.junit.platform.engine.support.hierarchical.Node-kotlinx.kover.maven.plugin.testing.MainKtTest(org.apache.maven.surefire.booter.Commandorg.junit.jupiter.api.Tag9org.junit.jupiter.engine.discovery.MethodSelectorResolver)org.junit.platform.engine.CompositeFilter?org.junit.jupiter.api.extension.ExtensionConfigurationExceptionkotlin.jvm.internal.Intrinsics