Skip to content

Instantly share code, notes, and snippets.

@mtilbrook-dev
Last active November 12, 2018 03:04
Show Gist options
  • Save mtilbrook-dev/40ba7dcb721e387c5c1256a7c09b0841 to your computer and use it in GitHub Desktop.
Save mtilbrook-dev/40ba7dcb721e387c5c1256a7c09b0841 to your computer and use it in GitHub Desktop.
Mix Source JaCoCo task file
// Forked from https://github.com/artem-zinnatullin/qualitymatters/blob/6e9f45912e79895f63274e5fd64ac2c7fc489f19/build.gradle
// I just added some multi-module bits and the kotlin debug path for mixed source `src/java`
ext.enableJacoco = { Project project ->
// Requires Jacoco plugin in build classpath.
apply plugin: 'jacoco'
project.android.testOptions {
unitTests {
includeAndroidResources = true
}
}
project.dependencies {
testImplementation("org.jacoco:org.jacoco.ant:0.8.2")
androidTestImplementation("org.jacoco:org.jacoco.ant:0.8.2")
}
android.lintOptions {
ignoreTestSources true
}
project.jacoco {
toolVersion = "0.8.2"
}
project.tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
// Enables code coverage for JVM tests.
// Android Gradle Plugin out of the box supports only code coverage for instrumentation tests.
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName
if (!productFlavorName) {
sourceName = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
def coverageTaskName = "${testTaskName}Coverage"
def fileFilter = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
// Kotlin specific, Jacoco can not handle several "$" in class name.
'**/*$inlined$*.*',
'**/*Module.*', // Modules for Dagger.
'**/*Dagger*.*', // Dagger auto-generated code.
'**/*MembersInjector*.*', // Dagger auto-generated code.
'**/*_Provide*Factory*.*',
]
def debugTree = fileTree(
dir: "${project.buildDir}/intermediates/classes/${productFlavorName}/debug",
excludes: fileFilter
)
def kotlinDebugTree = fileTree(
dir: "${project.buildDir}/tmp/kotlin-classes/${sourceName}",
excludes: fileFilter
)
def mainSrc = [
'src/main/java',
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
def classDirs = files([debugTree], [kotlinDebugTree])
def additionalSrcDirs = files(mainSrc)
def srcDirs = files(mainSrc)
def execData = fileTree(
dir: project.buildDir,
includes: [
"jacoco/${testTaskName}.exec",
'outputs/code-coverage/connected/*coverage.ec'
]
)
def configureTask = { JacocoReportBase report ->
report.classDirectories = classDirs
report.additionalSourceDirs = additionalSrcDirs
report.sourceDirectories = srcDirs
report.executionData = execData
}
// Create coverage task of form 'testFlavorTypeUnitTestCoverage' depending on 'testFlavorTypeUnitTest'
def coverage = task "${coverageTaskName}"(type: JacocoReport, dependsOn: "$testTaskName") {
group = 'Reporting'
description = "Generate Jacoco coverage reports for the ${sourceName.capitalize()} build."
reports {
xml.enabled = true
html.enabled = true
}
}
configureTask(coverage)
def checkTaskName = "${testTaskName}CoverageCheck"
def checkTask = task "$checkTaskName"(type: JacocoCoverageVerification, dependsOn: "${coverageTaskName}") {
group = 'Reporting Violations'
description = "Validate Jacoco coverage rules for the ${sourceName.capitalize()} build."
violationRules {
rule {
limit {
minimum = 0.5
}
}
}
}
configureTask(checkTask)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment