With Kover, is there a gradle convention plugin wa...
# code-coverage
k
With Kover, is there a gradle convention plugin way of making a manual list of all the kover submodules to avoid all the manual repetitiveness of doing this to get a merged report? dependencies { kover(project("anotherproject")) ....repeat for all submodules } It looks like the kotlin aggregation settings.gradle plugin is what I want but there is a warning of "It is in its infancy, it is recommended to use it only for test or pet projects" ๐Ÿ˜ž https://kotlin.github.io/kotlinx-kover/gradle-plugin/aggregated.html
h
Do you want to include all sub projects? If so, you can use this code:
Copy code
dependencies {
  for (subproject in subprojects) {
    kover(subproject)
  }
}
k
yes, but the problem is your suggested technique doesn't work if you use gradle's config cache or the new project isolation feature. I.e. to make gradle cache builds properly, you can't use subprojects. There's a subprojects{} DSL that works for the config cache, but not project isolation ๐Ÿ˜ž Looks like the aggregation plugin is the right way to do this longer term...it's just weird that they added that warning...
h
That's not true, my code works with IP
I don't use the subprojects callback but iterating, that api is safe.
k
hmm..now I'm confused...that shouldn't from my understanding ๐Ÿค” I also ran it against chatgpt so now it's mind blown
h
You can just trust me ๐Ÿ˜œ
k
lol..will try it..thanks. If nothing else, it gives us a temp workaround until that aggregation plugin is released officially...
h
Yeah, the callback api is not safe for IP/CC, but adding a project dependency to the current (root) project using the iterative method is safe. In this case, you don't access the whole project instance but only the project path and the path is safe to access, even with IP.
๐Ÿ‘ 1
k
thx...I'm surprised this isn't in the kover docs. Much easier than specifying every subproject manually as a kover dep ๐Ÿ™‚
Just to confirm, you get a merged report in build/reports/kover/html/index.html when you do this? I see a file generated but all it says is: Overall Coverage Summary No coverage information was found ๐Ÿค” This was added to the root build.gradle:
Copy code
// Kover configuration for code coverage
kover {
    reports {
        total {
            // configure merged report here
        }
    }
}

// Automatically add all subprojects with Kover plugin for coverage aggregation
afterEvaluate {
    dependencies {
        subprojects.forEach { subproject ->
            if (subproject.plugins.hasPlugin("org.jetbrains.kotlinx.kover")) {
                kover(subproject)
            }
        }
    }
}
Turns out subprojects is empty when this is added to the Android app module ๐Ÿค”
Copy code
dependencies {
   error("***** trying to include ${subprojects.joinToString(",") { it.name }}")
...
prints out
Copy code
> ***** trying to include
ahh..that is empty... should be
Copy code
rootProject.subprojects
h
You should move this aggregation code to the root project
Accessing the root/other projects is not IP safe
๐Ÿ‘ 1
k
In case anyone finds this thread in the future...ended up with this and it seems to work fine (found an old issue describing how to create a custom "main" variant)...this should be in the docs instead of the technique they recommend. coverage() is applied to any modules that add test support via a convention plugin and is also applied to the root module:
Copy code
fun Project.coverage(versionCatalog: Optional<VersionCatalog> = getLibsCatalog()) {
    with(pluginManager) {
        val catalog = versionCatalog.orElse(null) ?: run {
            logger.warn("Version catalog 'libs' not found, skipping Kover configuration")
            return
        }

        val koverPlugin = catalog.findPlugin("kover").orElse(null)?.get()?.pluginId ?: run {
            logger.warn("Kover plugin not found in version catalog, skipping Kover configuration")
            return
        }

        apply(koverPlugin)
    }

    if (project.path == ":") {
        // configure this merged reports setup only for the root
        extensions.configure<KoverProjectExtension> {
            // see <https://github.com/Kotlin/kotlinx-kover/issues/599>
            merge {
                subprojects()

                createVariant("main") {
                    add("debug", optional = true)
                    add("jvm", optional = true)
                }
            }
        }
    }

    extensions.configure<KoverProjectExtension> {
        reports {
            filters {
                excludes {
                    androidGeneratedClasses()
                    // Exclude all classes generated by Dagger Hilt in JVM modules
                    classes(
                        "*_HiltComponents*",
                        "*_HiltModules*",
                        "*_HiltInjector*",
                        "*_GeneratedInjector*",
                        "*_HiltViewModelFactory*",
                        "dagger.hilt.*",
                        "hilt_aggregated_deps.*",
                        "*_*Factory*",
                        "*_MembersInjector",
                        "*.HiltWrapper_*",
                    )
                }
            }
        }
    }
}
132 Views