Delta Coverage
is coverage analyzing tool that computes code coverage of new/modified code based on a provided diff.
The diff content can be provided via path to patch file, URL or using embedded git(see parameters description).
Why should I use it?
- forces each developer to be responsible for its own code quality(see deltaCoverage task)
- helps to increase total code coverage(especially useful for old legacy projects)
- reduces time of code review(you don't need to waste your time to track what code is covered)
Delta Coverage plugin compatibility table:
Delta Coverage plugin | Gradle |
---|---|
2.+ | 5.6 - 8.6.+ |
1.3.+ | 5.1 - 8.4.+ |
1.0.0 - 1.2.0 | 5.1 - 8.3.+ |
The plugin should be applied to the root project.
Kotlin
plugins {
id("io.github.surpsg.delta-coverage") version "<the-plugin-version>"
}
Groovy
plugins {
id "io.github.surpsg.delta-coverage" version "<the-plugin-version>"
}
Delta Coverage plugin doesn't collect coverage data itself. It uses coverage data that is already collected by a coverage engine.
The plugin supports two coverage engines:
- JaCoCo is standard coverage engine for JVM projects.
- Intellij coverage is coverage engine that used by default in Intellij IDE. Intellij coverage could be applied to your Gradle project by applying Kover plugin. Intellij coverage is better choice for Kotlin projects.
See Configuration section to configure coverage engine.
In the examples below the minimal configuration is shown.
Kotlin
configure<io.github.surpsg.deltacoverage.gradle.DeltaCoverageConfiguration> {
diffSource.file.set("${PATH_TO_DIFF_FILE}")
violationRules.failIfCoverageLessThan(0.9)
reports {
html.set(true)
}
}
Groovy
deltaCoverageReport {
diffSource.file = file("${PATH_TO_DIFF_FILE}")
violationRules.failIfCoverageLessThan 0.9d
reports {
html.set(true)
}
}
Complete example
plugins {
id("io.github.surpsg.delta-coverage") version "2.1.0"
}
configure<io.github.surpsg.deltacoverage.gradle.DeltaCoverageConfiguration> {
coverage.engine = CoverageEngine.INTELLIJ // See parameters description for more info
git.compareWith("refs/remotes/origin/main")
violationRules.failIfCoverageLessThan(0.9)
reports {
html.set(true)
xml.set(true)
}
}
./gradlew test deltaCoverage
configure<io.github.surpsg.deltacoverage.gradle.DeltaCoverageConfiguration> {
// Configures coverage engine. Default is 'JACOCO'.
coverage {
engine = CoverageEngine.JACOCO // Required. Default is 'JACOCO'. Could be set to INTELLIJ engine.
autoApplyPlugin = true // Required. Default is 'true'. If 'true' then the corresponding coverage engine plugin is applied to a project and all it's subprojects.
}
// Required. Only one of `file`, `url` or git must be specified.
diffSource {
// Path to diff file.
file.set(file("path/to/file.diff"))
// URL to retrieve diff by.
url.set("http://domain.com/file.diff")
// Compares current HEAD and all uncommited with provided branch, revision or tag.
git.compareWith.set("refs/remotes/origin/develop")
git.useNativeGit.set(true) // Optional. Default is 'false'. If 'true' then the plugin uses native git to get diff.
}
// Required.
// For JaCoCo engine: by default '.exec' coverage binary files are configured from jacoco plugin.
// For Intellij engine: by default '.ic' coverage binary files are configured from kover plugin.
coverageBinaryFiles = files("/path/to/jacoco/exec/file.exec")
// Required. By default sources are taken from jacoco plugin(or intellij) if the plugin is applied to a project.
srcDirs = files("/path/to/sources")
// Required. By default classes are taken from jacoco plugin(or intellij) if the plugin is applied to a project.
classesDirs = files("/path/to/compiled/classes")
// Optional. Excludes classes from coverage report by set of patterns .
excludeClasses.value(listOf[
"*/com/package/ExcludeClass.class", // Excludes class "com.package.ExcludeClass"
"**/com/package/**/ExcludeClass.class", // Excludes classes like "com.package.ExcludeClass", "com.package.sub1.sub2.ExcludeClass", etc.
"**/ExcludeClass\$NestedClass.class", // Excludes nested class(es) "<any-package>.ExcludeClass.NestedClass"
"**/com/package/exclude/**/*.*" // Excludes all in package "com.package.exclude"
// See more info about pattern rules: https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/util/PatternFilterable.html
])
reports {
html.set(true) // Optional. default `false`
xml.set(true) // Optional. default `false`
console.set(true) // Optional. default `false`
csv.set(true) // [Deprecated]. Optional. default `false`
reportDir.set("dir/to/store/reports") // Optional. Default 'build/reports/coverage-reports'
}
// If violation rules are not configured, then no violations will be checked.
violationRules {
failOnViolation.set(true) // Optional. Default `false`. If `true` then task will fail if any violation is found.
// [Option 1]---------------------------------------------------------------------------------------------------
// Optional. The function sets min coverage ration for instructions, branches and lines to '0.9'.
// Sets failOnViolation to 'true'.
failIfCoverageLessThan(0.9d)
// [Option 2]---------------------------------------------------------------------------------------------------
rule(io.github.surpsg.deltacoverage.gradle.CoverageEntity.INSTRUCTION) {
// Optional. If coverage ration is set then the plugin will check coverage ratio for this entity.
minCoverageRatio.set(0.9d)
// Optional. Disabled by default. The plugin ignores violation if the entity count is less than the threshold.
entityCountThreshold.set(1234)
}
rule(io.github.surpsg.deltacoverage.gradle.CoverageEntity.LINE) {
// ...
}
rule(io.github.surpsg.deltacoverage.gradle.CoverageEntity.BRANCH) {
// ...
}
// [Option 3]---------------------------------------------------------------------------------------------------
// [.kts only] Alternative way to set violation rule.
io.github.surpsg.deltacoverage.gradle.CoverageEntity.BRANCH {
minCoverageRatio.set(0.7d)
entityCountThreshold.set(890)
}
// [Option 4]---------------------------------------------------------------------------------------------------
// Sets violation rule for all entities: LINE, BRANCH, INSTRUCTION
all {
minCoverageRatio.set(0.7d)
entityCountThreshold.set(890)
}
}
}
The plugin adds a task deltaCoverage
that has no dependencies
-
loads code coverage data specified by
deltaCoverageReport.coverageBinaryFiles
-
analyzes the coverage data and filters according to
diffSource.url
/diffSource.file
-
generates html report(if enabled:
reports.html = true
) to directoryreports.baseReportsDir
-
checks coverage ratio if
violationRules
is specified.Violations check is enabled only if there is any rule for
INSTRUCTION
,LINE
,BRANCH
has min ratio greater than0.0
.Fails the execution if the violation check is enabled and
violationRules.failOnViolation = true
Passed:
>Task :deltaCoverage
Fail on violations: true. Found violations: 0.
Failed:
> Task :deltaCoverage FAILED
Fail on violations: true. Found violations: 2.
FAILURE: Build failed with an exception.
...
> java.lang.Exception: Rule violated for bundle delta-coverage-gradle: instructions covered ratio is 0.5, but expected minimum is 0.9
Rule violated for bundle delta-coverage-gradle: lines covered ratio is 0.0, but expected minimum is 0.9
Delta Coverage
plugin generates standard JaCoCo HTML report, but highlights only modified code
+----------------------------+----------------------+--------+----------+
| Delta Coverage Stats |
+----------------------------+----------------------+--------+----------+
| Source | Class | Lines | Branches |
+----------------------------+----------------------+--------+----------+
| single-module-test-project | com.java.test.Class1 | 66.67% | 50% |
+----------------------------+----------------------+--------+----------+
| Total | | 66.67% | 50% |
+----------------------------+----------------------+--------+----------+