218 lines
No EOL
8 KiB
Groovy
218 lines
No EOL
8 KiB
Groovy
// filter of files that shouldn't be part of the report
|
|
def androidFileFilter =
|
|
[ //jdk
|
|
'jdk.internal.*',
|
|
// data binding
|
|
'**/databinding/*.class',
|
|
'**/BR.*',
|
|
// android
|
|
'**/R.class',
|
|
'**/R$*.class',
|
|
'**/BuildConfig.*',
|
|
'**/Manifest*.*',
|
|
'**/*Test*.*',
|
|
'android/**/*.*',
|
|
// kotlin
|
|
'**/META-INF/*',
|
|
'**/*MapperImpl*.*',
|
|
'**/*$ViewInjector*.*',
|
|
'**/*$ViewBinder*.*',
|
|
'**/BuildConfig.*',
|
|
'**/*Component*.*',
|
|
'**/*BR*.*',
|
|
'**/Manifest*.*',
|
|
'**/*$Lambda$*.*',
|
|
'**/*Companion*.*',
|
|
'**/*Module*.*',
|
|
'**/*Dagger*.*',
|
|
'**/*Hilt*.*',
|
|
'**/*MembersInjector*.*',
|
|
'**/*_MembersInjector.class',
|
|
'**/*_Factory*.*',
|
|
'**/*_Provide*Factory*.*',
|
|
'**/*Extensions*.*',
|
|
// sealed and data classes
|
|
'**/*$Result.*',
|
|
'**/*$Result$*.*',
|
|
// adapters generated by moshi
|
|
'**/*JsonAdapter.*',
|
|
// room
|
|
'**/*_Impl.class',
|
|
'**/*_Impl*.*',
|
|
// hilt
|
|
'**/hilt_aggregated_deps/*'
|
|
]
|
|
|
|
|
|
/ **
|
|
* Setup Jacoco for Android module.
|
|
* - applies Plugin to the module.
|
|
* - sets up the "debug" build type for jacoco
|
|
* - creates tasks:
|
|
* - if androidTest folder exists creates a jacocoAndroidTestReport alias for the jacoco coverageReport, otherwise an empty task.
|
|
* - if test folder exists creates a jacocoUnitTestReport alias for the jacoco coverageReport, otherwise an empty task.
|
|
* - creates jacocoTestReport which runs both alias tasks created before.
|
|
*
|
|
* Note: "jacocoTestReport" is the task name which is default for Java Modules.
|
|
* /
|
|
|
|
def setupAndroidJacoco(Project module, ArrayList<String> fileFilter, String jacocoVersion) {
|
|
configure(module) {
|
|
apply plugin: "jacoco"
|
|
|
|
module.android.testOptions.unitTests.all {
|
|
jacoco.includeNoLocationClasses = true
|
|
jacoco.excludes = fileFilter
|
|
}
|
|
android.buildTypes.debug.enableAndroidTestCoverage true
|
|
android.buildTypes.debug.enableUnitTestCoverage true
|
|
|
|
jacoco.toolVersion = "$jacocoVersion"
|
|
|
|
def hasAndroidTests = new File("${module.projectDir}/src/androidTest").exists()
|
|
def hasUnitTests = new File("${module.projectDir}/src/test").exists()
|
|
if (hasUnitTests) {
|
|
task jacocoUnitTestReport(dependsOn: ["createDebugUnitTestCoverageReport"]) {
|
|
group = "verification"
|
|
}
|
|
} else {
|
|
task jacocoUnitTestReport() {
|
|
group = "verification"
|
|
}
|
|
}
|
|
if (hasAndroidTests) {
|
|
task jacocoAndroidTestReport(dependsOn: ["createDebugAndroidTestCoverageReport"]) {
|
|
group = "verification"
|
|
}
|
|
} else {
|
|
task jacocoAndroidTestReport() {
|
|
group = "verification"
|
|
}
|
|
}
|
|
|
|
task jacocoTestReport(dependsOn: ["jacocoUnitTestReport", "jacocoAndroidTestReport"]) {
|
|
group = "verification"
|
|
}
|
|
}
|
|
}
|
|
|
|
/ **
|
|
* Setup Jacoco for Java module.
|
|
* - applies Plugin to the module.
|
|
* - updates the `jacocoTestReport` task to ignore the `androidFileFilter`
|
|
* - ensures tests run before `jacocoTestReport`
|
|
* /
|
|
|
|
def setupJavaJacoco(Project module, ArrayList<String> fileFilter) {
|
|
configure(module) {
|
|
apply plugin: "jacoco"
|
|
|
|
jacocoTestReport {
|
|
dependsOn test // tests are required to run before generating the report
|
|
|
|
afterEvaluate {
|
|
classDirectories.setFrom(files(classDirectories.files.collect {
|
|
fileTree(dir: it, exclude: fileFilter)
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/ **
|
|
* Setup Jacoco for submodules based on their android or java module type
|
|
*/
|
|
subprojects { module ->
|
|
plugins.withType(JavaPlugin).whenPluginAdded {
|
|
setupJavaJacoco(module, androidFileFilter)
|
|
}
|
|
|
|
plugins.withId("com.android.application") {
|
|
setupAndroidJacoco(module, androidFileFilter, "$jacoco_version")
|
|
}
|
|
|
|
plugins.withId("com.android.library") {
|
|
setupAndroidJacoco(module, androidFileFilter, "$jacoco_version")
|
|
}
|
|
}
|
|
|
|
/ **
|
|
* Setup Aggregation tasks for Jacoco.
|
|
* - jacocoRootReport: can be used to generate the report after submodules `jacocoTestReport` has been ran at least once.
|
|
* - runTestAndJacocoRootReport: calls the `jacocoTestReport` of each submodule then calls `jacocoRootReport` for aggregation.
|
|
*
|
|
* Context, how the aggregated report works:
|
|
* The jacoco tasks created by the plugin generate .ec and .exec Execution-Data files in specific locations.
|
|
* - These Execution-Data files are all pulled into one `JacocoReport` task (`executionData.from`).
|
|
* - All the source files from all the submodules are pulled into the same `JacocoReport` task (`sourceDirectories.from`)
|
|
* - All the class files from all the submodules are pulled into the same `JacocoReport` task (`classDirectories.from`)
|
|
* Then finally the report is configured to be generated at root `build\coverage-report`
|
|
* /
|
|
configure(rootProject) {
|
|
apply plugin: "jacoco"
|
|
def testTypeName = "debug"
|
|
|
|
task runTestAndJacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
|
|
description = 'Run Tests and Generates report from all subprojects'
|
|
|
|
// add all non empty subProjects `jacocoTestReport` task as a dependency.
|
|
// note: these tasks are default Jacoco Task for Java and have been added above for Android modules.
|
|
def codeProjects = subprojects.findAll({ it.subprojects.isEmpty() })
|
|
codeProjects.forEach {
|
|
dependsOn += ["$it.path:jacocoTestReport"]
|
|
}
|
|
|
|
finalizedBy("jacocoRootReport")
|
|
}
|
|
|
|
task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
|
|
description = 'Generates report from all subprojects'
|
|
|
|
def codeProjects = subprojects.findAll({ it.subprojects.isEmpty() })
|
|
sourceDirectories.from = files(codeProjects.collect { "${it.projectDir}/src/main/java" })
|
|
|
|
def classFileTrees = codeProjects.collect {
|
|
def javaClassFilesInJavaModuleTree = fileTree(
|
|
dir: "${it.buildDir}/classes/java/main",
|
|
excludes: androidFileFilter
|
|
)
|
|
def kotlinClassFilesInJavaModuleTree = fileTree(
|
|
dir: "${it.buildDir}/classes/kotlin/main",
|
|
excludes: androidFileFilter
|
|
)
|
|
def javaClassFilesInAndroidModuleTree = fileTree(
|
|
dir: "${it.buildDir}/intermediates/javac/${testTypeName}/classes",
|
|
excludes: androidFileFilter
|
|
)
|
|
def kotlinClassFilesInAndroidModuleTree = fileTree(
|
|
dir: "${it.buildDir}/tmp/kotlin-classes/${testTypeName}",
|
|
excludes: androidFileFilter
|
|
)
|
|
|
|
files([javaClassFilesInJavaModuleTree, kotlinClassFilesInJavaModuleTree, javaClassFilesInAndroidModuleTree, kotlinClassFilesInAndroidModuleTree])
|
|
}.flatten()
|
|
classDirectories.from = files(classFileTrees)
|
|
|
|
def executionDataFiles = codeProjects.collect {
|
|
def androidTestExecutionData = fileTree(
|
|
dir: "${it.buildDir}/outputs/code_coverage/${testTypeName}AndroidTest/connected/",
|
|
includes: ["**/*.ec", "**/*.exec"]
|
|
)
|
|
def androidUnitTestExecutionData = fileTree(
|
|
dir: "${it.buildDir}/outputs/unit_test_code_coverage/",
|
|
includes: ["**/*.ec", "**/*.exec"]
|
|
)
|
|
def javaUnitTestExecutionData = "${it.buildDir}/jacoco/test.exec"
|
|
|
|
[androidTestExecutionData, androidUnitTestExecutionData, javaUnitTestExecutionData]
|
|
}.flatten()
|
|
executionData.from = files(executionDataFiles)
|
|
|
|
reports {
|
|
html {
|
|
required = true
|
|
destination file("${buildDir}/coverage-report")
|
|
}
|
|
}
|
|
}
|
|
} |