Linked Questions

Popular Questions

I'm working on a multi-module app that uses Gradle convention plugins to simplify its Gradle build scripts. We have a number of plugins that we apply without problems. So the basic structure should be correct.

I'm trying now to add a plugin that sets up Jacoco, but I'm struggling to figure out how to do that. I have a very simple plugin for pure JVM modules that works as expected:

open class JvmJacocoReportPlugin : Plugin<Project> {

    override fun apply(target: Project) {
        target.run {
            pluginManager.apply(JACOCO_PLUGIN)
            configureJacoco()
        }
    }

    private fun Project.configureJacoco() {
        tasks.withType<JacocoReport>().configureEach {
            dependsOn(tasks.withType<Test>())

            reports {
                xml.required.set(true)
                csv.required.set(false)
                html.required.set(true)
                html.outputLocation.set(layout.buildDirectory.dir(REPORT_DIRECTORY_NAME))
            }
        }
    }

    companion object {
        const val JACOCO_PLUGIN = "org.gradle.jacoco"
        const val REPORT_DIRECTORY_NAME = "jacoco-report"
    }
}

My slightly different plugin for Android modules looks like this:

class JacocoReportPlugin : JvmJacocoReportPlugin() {

    override fun apply(target: Project) {
        super.apply(target)
        target.run {

            // if I don't register it for Android modules, the task is not present 
            target.tasks.register<JacocoReport>("jacocoTestReport") {
                dependsOn(tasks.withType<Test>())
            }

            if (target.isLibrary()) {
                target.extensions.getByType<LibraryExtension>().apply {
                    buildTypes {
                        getByName("debug") {
                            enableUnitTestCoverage = true
                            enableAndroidTestCoverage = false
                        }
                    }
                }
            }

            if (target.isApplication()) {
                target.extensions.getByType<ApplicationExtension>().apply {
                    buildTypes {
                        getByName("debug") {
                            enableUnitTestCoverage = true
                            enableAndroidTestCoverage = false
                        }
                    }
                }
            }
        }
    }

    private fun Project.isApplication() = plugins.hasPlugin("com.android.application")
    private fun Project.isLibrary() = plugins.hasPlugin("com.android.library")
}

We have a convention plugin for Android libraries and applications, as well as one for pure JVM libraries, where these plugins get applied like this:

class AndroidLibraryConventionPlugin : Plugin<Project> {

    override fun apply(target: Project) = target.run {
        
        (...)
        
        pluginManager.apply(JacocoReportPlugin::class.java)
       
    }

    (...)
}

This works fine for pure JVM modules. Reports are generated. But for Android library or application modules, I can manage to create the task, but I get no reports.

There is very little info online about setting up Jacoco using such a plugin structure, so I'm at a loss here. What am I missing here?

Related Questions