@@ -3,10 +3,14 @@ package conventions
33import org.gradle.api.Plugin
44import org.gradle.api.Project
55import org.gradle.api.artifacts.VersionCatalogsExtension
6+ import org.gradle.api.file.FileTree
7+ import org.gradle.configurationcache.extensions.capitalized
68import org.gradle.kotlin.dsl.extra
79import org.gradle.kotlin.dsl.getByType
10+ import org.gradle.kotlin.dsl.register
811import org.gradle.kotlin.dsl.withType
912import org.gradle.testing.jacoco.plugins.JacocoPlugin
13+ import org.gradle.testing.jacoco.tasks.JacocoReport
1014import ytemplate.android.jacoco.extractTestCoverage
1115import ytemplate.android.jacoco.jacoco
1216
@@ -17,105 +21,61 @@ import ytemplate.android.jacoco.jacoco
1721 */
1822@Suppress(" UNCHECKED_CAST" )
1923class ProjectJacocoConventionPlugin : Plugin <Project > {
20- private val project_level_limits = mutableMapOf (
21- " instruction" to 0.0 ,
22- " branch" to 0.0 ,
23- " line" to 0.0 ,
24- " complexity" to 0.0 ,
25- " method" to 0.0 ,
26- " class" to 0.0
27- )
28-
29-
30- fun Project.setProjectTestCoverageLimits (projectLimits : Map <String , Double >? = null) {
31- if (projectLimits != null ) {
32- extra.set(" limits" , projectLimits)
33- } else {
34- extra.set(" limits" , project_level_limits)
35- }
36- }
37-
3824 override fun apply (target : Project ) {
3925 with (target) {
4026 with (pluginManager) {
4127 apply (" jacoco" )
4228 }
43- tasks.register(" createMergedJacocoReport" ) {
29+
30+ tasks.register<JacocoReport >(" createMergedJacocoReport" ) {
4431 val jacocoReport = this
4532 group = " Reporting"
46- description = " Generate test coverage reports on the debug build"
47- subprojects {
48- val subproject= this
49- subproject.plugins.withType<JacocoPlugin >().configureEach {
50- if (tasks.findByName(" createDemoDebugJacocoReport" ) != null ) {
51- val moduleTask = tasks.findByName(" createDemoDebugJacocoReport" )
52- jacocoReport.dependsOn(moduleTask)
53- }
54- }
55- }
56- doLast {
57- logger.lifecycle(" Overall coverage report" )
58- val metrics = mutableMapOf<String ,Map <String ,Double >>()
59- val moduleLimits = mutableMapOf<String ,Map <String ,Double >>()
60- val failures = mutableMapOf<String ,List <String >>()
33+ description = " create Project Jacoco Report for debug builds for all submodules with jacoco plugin"
34+ logger.quiet(" ======Merging HTML Reports=========" )
35+ val javaClasses: MutableCollection <FileTree > = mutableListOf ()
36+ val kotlinClasses: MutableCollection <FileTree > = mutableListOf ()
37+ val sourceDir: MutableCollection <String > = mutableListOf ()
38+ val coverageFiles: MutableCollection <String > = mutableListOf ()
6139
62- if (! extra.has(" limits" )) {
63- setProjectTestCoverageLimits()
40+ subprojects {
41+ val subProject = this
42+ subProject.plugins.withType<JacocoPlugin >().configureEach {
43+ val moduleTask = tasks.findByName(" createDemoDebugJacocoReport" )
44+ jacocoReport.dependsOn(moduleTask)
6445 }
65- subprojects {
66- if (tasks.findByName(" createDemoDebugJacocoReport" ) != null ) {
67- val reportDir = jacoco.reportsDirectory.asFile.get()
68- val report =
69- file(" $reportDir /createDemoDebugJacocoReport/createDemoDebugJacocoReport.xml" )
70- if (report.exists()) {
71- logger.lifecycle(" Checking coverage results:$report " )
72- metrics[project.name] = report.extractTestCoverage()
73- moduleLimits[project.name] = project.extra[" limits" ] as Map <String , Double >
74- }
46+ if (subProject.plugins.findPlugin(JacocoPlugin ::class .java)!= null ) {
47+ val excludedFiles: MutableCollection <String > = mutableListOf ()
48+ if (subProject.extra.has(" excludes" )) {
49+ excludedFiles.addAll(subProject.extra.get(" excludes" ) as List <String >)
7550 }
76- }
77- metrics.forEach { (key, metricsMap) ->
78- val extractedMetricsMap = mutableMapOf<String ,Double >()
79- if (metricsMap.isNotEmpty()) {
80- val failureMap = metricsMap.filter { item ->
81- item.value < moduleLimits[key]!! [item.key]!!
82- }.map { item ->
83- extractedMetricsMap[item.key] = item.value
84- " -${item.key} coverage is: ${item.value} %, minimum is ${moduleLimits[item.key]} %"
85- }
86- if (failureMap.isNotEmpty()){
87- failures[key] = failureMap
51+ javaClasses.add(fileTree(" ${subProject.buildDir} /intermediates/javac/demoDebug/classes" ) {
52+ if (excludedFiles.isNotEmpty()) {
53+ exclude(excludedFiles)
8854 }
89- }
90- moduleLimits[key]= extractedMetricsMap
91- }
9255
56+ }.asFileTree)
57+ kotlinClasses.add(fileTree(" ${subProject.buildDir} /tmp/kotlin-classes/demoDebug" ) {
58+ if (excludedFiles.isNotEmpty()) {
59+ exclude(excludedFiles)
60+ }
61+ }.asFileTree)
9362
94- if (failures.isNotEmpty()) {
95- logger.quiet(" ======Code coverage failures=========" )
96- failures.forEach { entry ->
97- logger.quiet(" ======Module: ${entry.key} =========" )
98- entry.value.forEach { logger.quiet(it) }
99- }
100- logger.quiet(" ===========================================" )
101- }
102-
103- if (metrics.isNotEmpty()){
104- logger.quiet(" ======Code coverage success=========" )
105- metrics.forEach {entry->
106- logger.quiet(" ======Module: ${entry.key} =========" )
107- entry.value.forEach {
108- logger.quiet(" - ${it.key} coverage: ${it.value} " )
109- }
63+ sourceDir.add(" ${subProject.projectDir} /src/main/java" )
64+ sourceDir.add(" ${subProject.projectDir} /src/main/kotlin" )
65+ sourceDir.add(" ${subProject.projectDir} /src/demoDebug/java" )
66+ coverageFiles.add(" ${subProject.buildDir} /outputs/unit_test_code_coverage/demoDebugUnitTest/testDemoDebugUnitTest.exec" )
67+ coverageFiles.add(" ${subProject.buildDir} /outputs/code_coverage/demoDebugAndroidTest/connected/coverage.ec" )
11068 }
111- logger.quiet(" ===========================================" )
112- }
113-
11469 }
115-
70+ classDirectories.setFrom(files(javaClasses, kotlinClasses))
71+ additionalClassDirs.setFrom(files(sourceDir))
72+ sourceDirectories.setFrom(files(sourceDir))
73+ executionData.setFrom(files(coverageFiles))
74+ reports {
75+ xml.required.set(true )
76+ html.required.set(true )
77+ }
11678 }
117-
118-
11979 }
12080 }
12181}
0 commit comments