vanniktech / gradle-android-junit-jacoco-plugin

Gradle plugin that generates JaCoCo reports from an Android Gradle Project
http://vanniktech.com
Apache License 2.0
400 stars 76 forks source link

Add JacocoCoverageVerification task configuration #171

Open mattinger opened 4 years ago

mattinger commented 4 years ago

It would be awesome if the plugin would also include configuration of the appropriate tasks of type JacocoCoverageVerification. Right now, i have to kind of hack around this by doing lazy creation of the task (due to the use of afterEvaluate to define the tasks in the plugin. I can then find the reporting task and copy the configuration from that into the verification task that gets created.

Obviously this is hokey, and would be better done in the plugin.

afterEvaluate {
        if (depth > 0 && !skippedProjects.contains(name)) {
            tasks.create("jacocoCoverageVerificationDebug") {
                doLast {
                    val reportTask =
                        tasks.findByName("jacocoTestReportDebug") as org.gradle.testing.jacoco.tasks.JacocoReport

                    val verify = tasks.findByName("__jacocoCoverageVerificationDebug") as? JacocoCoverageVerification
                        ?: tasks.create<JacocoCoverageVerification>("__jacocoCoverageVerificationDebug") {

                            executionData(reportTask.executionData)
                            sourceDirectories.setFrom(reportTask.sourceDirectories)
                            classDirectories.setFrom(reportTask.classDirectories)
                            additionalSourceDirs.setFrom(reportTask.additionalSourceDirs)
                            additionalClassDirs.setFrom(reportTask.additionalClassDirs)

                            violationRules {
                                rule {
                                    limit {
                                        counter = "LINE"
                                        minimum = "0.5".toBigDecimal()
                                    }
                                }
                                rule {
                                    limit {
                                        counter = "BRANCH"
                                        minimum = "0.4".toBigDecimal()
                                    }
                                }
                            }

                            setOnlyIf { true }
                        }

                    if (reportTask.executionData.find { it.exists() } != null) {
                        reportTask.generate()
                    }

                    if (reportTask.executionData.find { it.exists() } != null) {
                        verify.check()
                    }
                }
            }
        }
    }
vanniktech commented 4 years ago

Feel free to create a PR!

mattinger commented 4 years ago

I can likely do that. I just have to get approval for submission (lawyers)

vanniktech commented 4 years ago

Sure!

bittelc commented 4 years ago

@braedongough could you please review

bittelc commented 4 years ago

@dominiquejb plz have braedongough review

CyxouD commented 1 year ago

Hi @mattinger. I know it is pretty old, but did you have the opportunity to get approval?

CyxouD commented 1 year ago

I couldn't make @mattinger solution work. Firstly, I had to delete 'val' keywords and 'as? ...' conversion since I use Groovy instead of Kotlin, after this it told me about missing property skippedProjects, I deleted it. After that, I changed to my product flavor. Eventually, it tells me that build is successful for this task, but it doesn't correctly check limits (it doesn't report errors).

To make it work, I used the solution from this root build gradle which is described in this video which eventually tells me Rule violated for bundle app: instructions covered ratio is 0.3, but expected minimum is 0.8 as expected. The code in my case added to root's build.gradle. Note that I use my product flavor Mock in 3 places, so you need to change it to your flavor or delete it if your don't use flavors in your project

subprojects {
    afterEvaluate() {
        tasks.register('verifyCodeCoverageMockDebug', JacocoCoverageVerification) {
            dependsOn 'jacocoTestReportMockDebug'

            sourceDirectories.from = file("${project.projectDir}/src/main/java") // main source set
            classDirectories.from = files(JacocoUtil.getKotlinFileTree(project))
            executionData.from = fileTree(dir: project.buildDir, includes: [
                    '**/*.exec', // unit tests
                    '**/*.ec' // ui tests
            ])

            violationRules {
                rule {
                    limit {
                        minimum = 0.8 // 30%
                    }
                }
            }
        }
    }
}

class JacocoUtil {
    static ConfigurableFileTree getKotlinFileTree(Project project) {
        return project.fileTree(
                // Where generated Kotlin classes are located
                dir: "$project.buildDir/tmp/kotlin-classes/mockDebug",
                // Exclude everything that is not created by you, e.g. created by HILT
                excludes: [
                        '**/BuildConfig.*',
                        '**/*$*',
                        '**/Hilt_*.class',
                        'hilt_**',
                        'dagger/hilt/**',
                        '**/*JsonAdapter.*'
                ]
        )
    }
}