Improve Kover setup by using only convention plugins (#6213)
* Improve Kover setup using convention plugins. * Add a new JVM library convention plugin with Kover support
This commit is contained in:
committed by
GitHub
parent
3814085837
commit
949a12f3d2
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
|||||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
|
||||||
- name: ⚙️ Check coverage for debug variant (includes unit & screenshot tests)
|
- name: ⚙️ Check coverage for debug variant (includes unit & screenshot tests)
|
||||||
run: ./gradlew testDebugUnitTest :tests:uitests:verifyPaparazziDebug :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
|
run: ./gradlew testDebugUnitTest :tests:uitests:verifyPaparazziDebug :koverXmlReportMerged :koverHtmlReportMerged :koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
- name: 🚫 Upload kover failed coverage reports
|
- name: 🚫 Upload kover failed coverage reports
|
||||||
if: failure()
|
if: failure()
|
||||||
@@ -112,5 +112,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: app/build/reports/kover/reportGplayDebug.xml
|
files: build/reports/kover/reportMerged.xml
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|||||||
@@ -6,6 +6,5 @@
|
|||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin.jvm)
|
id("io.element.jvm-library")
|
||||||
id("com.android.lint")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,8 @@ import extension.allFeaturesImpl
|
|||||||
import extension.allLibrariesImpl
|
import extension.allLibrariesImpl
|
||||||
import extension.allServicesImpl
|
import extension.allServicesImpl
|
||||||
import extension.buildConfigFieldStr
|
import extension.buildConfigFieldStr
|
||||||
import extension.koverDependencies
|
|
||||||
import extension.locales
|
import extension.locales
|
||||||
import extension.setupDependencyInjection
|
import extension.setupDependencyInjection
|
||||||
import extension.setupKover
|
|
||||||
import extension.testCommonDependencies
|
import extension.testCommonDependencies
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -40,8 +38,6 @@ plugins {
|
|||||||
// alias(libs.plugins.gms.google.services)
|
// alias(libs.plugins.gms.google.services)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKover()
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.x"
|
namespace = "io.element.android.x"
|
||||||
|
|
||||||
@@ -295,8 +291,6 @@ dependencies {
|
|||||||
testCommonDependencies(libs)
|
testCommonDependencies(libs)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.services.toolbox.test)
|
testImplementation(projects.services.toolbox.test)
|
||||||
|
|
||||||
koverDependencies()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<GenerateBuildConfig>().configureEach {
|
tasks.withType<GenerateBuildConfig>().configureEach {
|
||||||
|
|||||||
@@ -6,20 +6,7 @@
|
|||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
plugins {
|
plugins {
|
||||||
id("java-library")
|
id("io.element.jvm-library")
|
||||||
id("com.android.lint")
|
|
||||||
alias(libs.plugins.kotlin.jvm)
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = Versions.javaVersion
|
|
||||||
targetCompatibility = Versions.javaVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain {
|
|
||||||
languageVersion = Versions.javaLanguageVersion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin.jvm)
|
id("io.element.jvm-library")
|
||||||
id("com.android.lint")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ import kotlinx.kover.gradle.plugin.dsl.CoverageUnit
|
|||||||
import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
|
import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
|
||||||
import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
|
import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
|
||||||
import kotlinx.kover.gradle.plugin.dsl.KoverVariantCreateConfig
|
import kotlinx.kover.gradle.plugin.dsl.KoverVariantCreateConfig
|
||||||
import org.gradle.api.Action
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.kotlin.dsl.apply
|
import org.gradle.kotlin.dsl.apply
|
||||||
import org.gradle.kotlin.dsl.assign
|
import org.gradle.kotlin.dsl.assign
|
||||||
|
import org.gradle.kotlin.dsl.configure
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
enum class KoverVariant(val variantName: String) {
|
enum class KoverVariant(val variantName: String) {
|
||||||
Presenters("presenters"),
|
Presenters("presenters"),
|
||||||
@@ -24,7 +25,7 @@ enum class KoverVariant(val variantName: String) {
|
|||||||
Views("views"),
|
Views("views"),
|
||||||
}
|
}
|
||||||
|
|
||||||
val koverVariants = KoverVariant.values().map { it.variantName }
|
val koverVariants = KoverVariant.entries.map { it.variantName }
|
||||||
|
|
||||||
val localAarProjects = listOf(
|
val localAarProjects = listOf(
|
||||||
":libraries:rustsdk",
|
":libraries:rustsdk",
|
||||||
@@ -32,7 +33,7 @@ val localAarProjects = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val excludedKoverSubProjects = listOf(
|
val excludedKoverSubProjects = listOf(
|
||||||
":app",
|
":appconfig",
|
||||||
":annotations",
|
":annotations",
|
||||||
":codegen",
|
":codegen",
|
||||||
":tests:testutils",
|
":tests:testutils",
|
||||||
@@ -42,24 +43,63 @@ val excludedKoverSubProjects = listOf(
|
|||||||
":libraries:core",
|
":libraries:core",
|
||||||
":libraries:coroutines",
|
":libraries:coroutines",
|
||||||
":libraries:di",
|
":libraries:di",
|
||||||
|
":tests:detekt-rules",
|
||||||
|
":tests:konsist",
|
||||||
|
":tests:testutils",
|
||||||
) + localAarProjects
|
) + localAarProjects
|
||||||
|
|
||||||
private fun Project.kover(action: Action<KoverProjectExtension>) {
|
private fun Project.kover(any: Any) {
|
||||||
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("kover", action)
|
this.dependencies.add("kover", any)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.setupKover() {
|
fun Project.setupKover() {
|
||||||
|
// If the project is excluded from Kover, don't apply anything
|
||||||
|
if (path in excludedKoverSubProjects) return
|
||||||
|
|
||||||
|
// Apply the plugin
|
||||||
|
apply(plugin = "org.jetbrains.kotlinx.kover")
|
||||||
|
|
||||||
// Create verify all task joining all existing verification tasks
|
// Create verify all task joining all existing verification tasks
|
||||||
tasks.register("koverVerifyAll") {
|
tasks.register("koverVerifyAll") {
|
||||||
group = "verification"
|
group = "verification"
|
||||||
description = "Verifies the code coverage of all subprojects."
|
description = "Verifies the code coverage of all subprojects."
|
||||||
val dependencies = listOf(":app:koverVerifyGplayDebug") + koverVariants.map { ":app:koverVerify${it.replaceFirstChar(Char::titlecase)}" }
|
val dependencies = listOf(":koverVerifyMerged") + koverVariants.map { ":app:koverVerify${it.replaceFirstChar(Char::titlecase)}" }
|
||||||
dependsOn(dependencies)
|
dependsOn(dependencies)
|
||||||
}
|
}
|
||||||
// https://kotlin.github.io/kotlinx-kover/
|
// https://kotlin.github.io/kotlinx-kover/
|
||||||
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
|
// Run `./gradlew :app:koverHtmlReport` to get report at ./app/build/reports/kover
|
||||||
// Run `./gradlew :app:koverXmlReport` to get XML report
|
// Run `./gradlew :app:koverXmlReport` to get XML report
|
||||||
kover {
|
extensions.configure<KoverProjectExtension> {
|
||||||
|
currentProject {
|
||||||
|
// Create custom variants for verification
|
||||||
|
for (variant in koverVariants) {
|
||||||
|
createVariant(variant) {
|
||||||
|
defaultVariants(project)
|
||||||
|
|
||||||
|
// Using the cache for coverage verification seems to be flaky, so we disable it for now.
|
||||||
|
val taskName = "koverCachedVerify${variant.replaceFirstChar(Char::titlecase)}"
|
||||||
|
val cachedTask = project.tasks.findByName(taskName)
|
||||||
|
cachedTask?.let {
|
||||||
|
it.outputs.upToDateWhen { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create merged variant
|
||||||
|
createVariant("merged") {
|
||||||
|
defaultVariants(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's the root project, set up kover for subprojects
|
||||||
|
if (project.path == ":") {
|
||||||
|
for (project in project.subprojects) {
|
||||||
|
if (project.path !in excludedKoverSubProjects && File(project.projectDir, "build.gradle.kts").exists()) {
|
||||||
|
kover(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reports {
|
reports {
|
||||||
filters {
|
filters {
|
||||||
excludes {
|
excludes {
|
||||||
@@ -194,54 +234,10 @@ fun Project.setupKover() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.applyKoverPluginToAllSubProjects() = rootProject.subprojects {
|
|
||||||
if (project.path !in localAarProjects) {
|
|
||||||
apply(plugin = "org.jetbrains.kotlinx.kover")
|
|
||||||
kover {
|
|
||||||
currentProject {
|
|
||||||
for (variant in koverVariants) {
|
|
||||||
createVariant(variant) {
|
|
||||||
defaultVariants(project)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project.afterEvaluate {
|
|
||||||
for (variant in koverVariants) {
|
|
||||||
// Using the cache for coverage verification seems to be flaky, so we disable it for now.
|
|
||||||
val taskName = "koverCachedVerify${variant.replaceFirstChar(Char::titlecase)}"
|
|
||||||
val cachedTask = project.tasks.findByName(taskName)
|
|
||||||
cachedTask?.let {
|
|
||||||
it.outputs.upToDateWhen { false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KoverVariantCreateConfig.defaultVariants(project: Project) {
|
fun KoverVariantCreateConfig.defaultVariants(project: Project) {
|
||||||
if (project.name == "app") {
|
if (project.path == ":app") {
|
||||||
addWithDependencies("gplayDebug")
|
addWithDependencies("gplayDebug")
|
||||||
} else {
|
} else {
|
||||||
addWithDependencies("debug", "jvm", optional = true)
|
addWithDependencies("debug", "jvm", optional = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.koverSubprojects() = project.rootProject.subprojects
|
|
||||||
.filter {
|
|
||||||
it.project.projectDir.resolve("build.gradle.kts").exists()
|
|
||||||
}
|
|
||||||
.map { it.path }
|
|
||||||
.sorted()
|
|
||||||
.filter {
|
|
||||||
it !in excludedKoverSubProjects
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Project.koverDependencies() {
|
|
||||||
project.koverSubprojects()
|
|
||||||
.forEach {
|
|
||||||
// println("Add $it to kover")
|
|
||||||
dependencies.add("kover", project(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import extension.androidConfig
|
|||||||
import extension.commonDependencies
|
import extension.commonDependencies
|
||||||
import extension.composeConfig
|
import extension.composeConfig
|
||||||
import extension.composeDependencies
|
import extension.composeDependencies
|
||||||
|
import extension.setupKover
|
||||||
import org.gradle.accessors.dm.LibrariesForLibs
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
val libs = the<LibrariesForLibs>()
|
val libs = the<LibrariesForLibs>()
|
||||||
@@ -37,6 +38,8 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupKover()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
commonDependencies(libs)
|
commonDependencies(libs)
|
||||||
composeDependencies(libs)
|
composeDependencies(libs)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import extension.androidConfig
|
|||||||
import extension.commonDependencies
|
import extension.commonDependencies
|
||||||
import extension.composeConfig
|
import extension.composeConfig
|
||||||
import extension.composeDependencies
|
import extension.composeDependencies
|
||||||
|
import extension.setupKover
|
||||||
import org.gradle.accessors.dm.LibrariesForLibs
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
val libs = the<LibrariesForLibs>()
|
val libs = the<LibrariesForLibs>()
|
||||||
@@ -37,6 +38,8 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupKover()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
commonDependencies(libs)
|
commonDependencies(libs)
|
||||||
composeDependencies(libs)
|
composeDependencies(libs)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
import extension.androidConfig
|
import extension.androidConfig
|
||||||
import extension.commonDependencies
|
import extension.commonDependencies
|
||||||
|
import extension.setupKover
|
||||||
import org.gradle.accessors.dm.LibrariesForLibs
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
val libs = the<LibrariesForLibs>()
|
val libs = the<LibrariesForLibs>()
|
||||||
@@ -33,6 +34,8 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupKover()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
commonDependencies(libs)
|
commonDependencies(libs)
|
||||||
coreLibraryDesugaring(libs.android.desugar)
|
coreLibraryDesugaring(libs.android.desugar)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import extension.applyKoverPluginToAllSubProjects
|
import extension.setupKover
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.jetbrains.kotlinx.kover") apply false
|
id("org.jetbrains.kotlinx.kover") apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
applyKoverPluginToAllSubProjects()
|
setupKover()
|
||||||
|
|||||||
28
plugins/src/main/kotlin/io.element.jvm-library.gradle.kts
Normal file
28
plugins/src/main/kotlin/io.element.jvm-library.gradle.kts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will generate the plugin "io.element.jvm-library", used in pure JVM libraries.
|
||||||
|
*/
|
||||||
|
import extension.setupKover
|
||||||
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
|
val libs = the<LibrariesForLibs>()
|
||||||
|
plugins {
|
||||||
|
id("org.jetbrains.kotlin.jvm")
|
||||||
|
id("com.autonomousapps.dependency-analysis")
|
||||||
|
id("com.android.lint")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion = Versions.javaLanguageVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKover()
|
||||||
Reference in New Issue
Block a user