name.remal.gradle_plugins.plugins.code_quality.jacoco.JacocoSettingsPlugin.kt Maven / Gradle / Ivy
package name.remal.gradle_plugins.plugins.code_quality.jacoco
import name.remal.gradle_plugins.dsl.*
import name.remal.gradle_plugins.dsl.extensions.*
import name.remal.gradle_plugins.plugins.java.JavaAnyPluginId
import name.remal.gradle_plugins.utils.getPredefinedDynamicVersionProperty
import name.remal.version.Version
import name.remal.warn
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionContainer
import org.gradle.api.plugins.JavaBasePlugin.CHECK_TASK_NAME
import org.gradle.api.plugins.JavaBasePlugin.VERIFICATION_GROUP
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.testing.Test
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
import org.gradle.testing.jacoco.tasks.JacocoCoverageVerification
import org.gradle.testing.jacoco.tasks.JacocoMerge
import org.gradle.testing.jacoco.tasks.JacocoReport
import org.gradle.testing.jacoco.tasks.JacocoReportBase
@Plugin(
id = "name.remal.jacoco-settings",
description = "Plugin that configures 'jacoco' plugin if it's applied.",
tags = ["java", "jacoco", "coverage", "test"]
)
@WithPlugins(JacocoPluginId::class, JavaAnyPluginId::class)
@SimpleTestAdditionalGradleScript("""
dependencies { testCompile 'junit:junit:4.12' }
test {
useJUnit()
testLogging {
showExceptions = true
showCauses = true
showStackTraces = true
exceptionFormat = 'FULL'
stackTraceFilters = ['GROOVY']
}
}
file('src/test/java/T.java').with {
parentFile.mkdirs()
write('public class T { @org.junit.Test public void test() {} }', 'UTF-8')
}
""")
class JacocoSettingsPlugin : BaseReflectiveProjectPlugin() {
@PluginAction
fun ExtensionContainer.`Update Jacoco version`(project: Project) {
val jacoco = this[JacocoPluginExtension::class.java]
val toolVersionStr = jacoco.toolVersion
if (toolVersionStr.isNullOrEmpty()) {
jacoco.toolVersion = project.getPredefinedDynamicVersionProperty("jacoco-core")
} else {
val toolVersion = Version.parseOrNull(toolVersionStr)
val buildVersion = Version.parseOrNull(project.getPredefinedDynamicVersionProperty("jacoco-core"))
if (toolVersion != null && buildVersion != null) {
if (toolVersion < buildVersion) {
jacoco.toolVersion = buildVersion.toString()
}
}
}
}
@PluginAction
fun TaskContainer.`Turn ON all reports`(extensions: ExtensionContainer) {
all(JacocoReport::class.java) { task ->
task.reports.all {
it.isEnabled = true
}
}
}
@PluginAction
fun TaskContainer.`Turn OFF fail on violation`() {
all(JacocoCoverageVerification::class.java) {
it.violationRules.isFailOnViolation = false
}
}
@PluginAction("If jacoco task has not execution files set, it crashes. So let's use temp empty execution file by default.")
fun TaskContainer.tempExecutionFileByDefault(project: Project, sourceSets: SourceSetContainer) {
all(JacocoReportBase::class.java) {
it.doSetup(Int.MAX_VALUE) {
tryCompatibleMethodOrWarn { it.prepareExecutionData() }
tryCompatibleMethodOrWarn {
if (it.sourceDirectoriesCompatible.isEmpty) it.sourceDirectoriesCompatible = sourceSets.main.allJava.sourceDirectories
if (it.classDirectoriesCompatible.isEmpty) it.classDirectoriesCompatible = sourceSets.main.output
}
tryCompatibleMethodOrWarn { it.applyExcludeFromCodeCoverage() }
}
}
all(JacocoMerge::class.java) {
it.doSetup(Int.MAX_VALUE) {
tryCompatibleMethodOrWarn { it.prepareExecutionData() }
}
}
}
@PluginAction
fun TaskContainer.`Setup jacoco for all Test tasks`(extensions: ExtensionContainer, tasks: TaskContainer) {
all(Test::class.java) { testTask ->
if (JacocoTaskExtension::class.java !in testTask.extensions) {
val jacoco = extensions[JacocoPluginExtension::class.java]
jacoco.applyTo(testTask)
}
val reportTask = tasks.getOrCreate(testTask.jacocoReportTaskName, JacocoReport::class.java).also { task ->
task as JacocoReport
task.mustRunAfter(testTask)
task.group = VERIFICATION_GROUP
task.description = "Generates code coverage report for the ${testTask.name} task."
task.executionData(testTask)
all(CHECK_TASK_NAME) { it.dependsOn(task) }
task.onlyIf { testTask.isInTaskGraph }
}
tasks.getOrCreate(testTask.jacocoCoverageVerificationTaskName, JacocoCoverageVerification::class.java).also { task ->
task as JacocoCoverageVerification
task.mustRunAfter(testTask)
task.mustRunAfter(reportTask)
task.group = VERIFICATION_GROUP
task.description = "Verifies code coverage metrics based on specified rules for the ${testTask.name} task."
task.executionData(testTask)
all(CHECK_TASK_NAME) { it.dependsOn(task) }
task.onlyIf { testTask.isInTaskGraph }
}
}
}
private inline fun tryCompatibleMethodOrWarn(callback: () -> Unit) {
try {
callback()
} catch (e: CompatibleMethodNotFoundException) {
logger.warn(e)
}
}
}