diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index fc8ddd0c..61257473 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -7,10 +7,14 @@ on: env: APP_SIGN_KEYSTORE_PATH: /tmp/keystore CACHE_BUNDLER: ~/.bundler + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + api-level: [ 30 ] steps: - name: Write key file env: @@ -89,4 +93,47 @@ jobs: options: '{ "conf": "debug" }' skip-tracking: false subdirectory: fastlane - bundle-install-path: CACHE_BUNDLER \ No newline at end of file + bundle-install-path: CACHE_BUNDLER + + + - name: Ensure android directory exists + run: mkdir -p android + + - name: Setup Gradle cache + uses: gradle/gradle-build-action@v2 + + - name: List root diretory contents + run: ls -la + + - name: List android directory contents + run: ls -la android + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Run local tests for the combined coverage report (only API 30) + if: matrix.api-level == 30 + run: ./gradlew testDebugUnitTest + + - name: Generate coverage reports for Debug variants (only API 30) + if: matrix.api-level == 30 + run: ./gradlew createDebugCombinedCoverageReport + + - name: Upload App module test coverage report to Codecov + if: matrix.api-level == 30 # Only upload coverage on API level 30 + working-directory: android + run: bash <(curl -s https://codecov.io/bash) -F app -f "**/build/reports/jacoco/" + + - name: Run DataSource remote module unit and instrumentation tests and generate coverage report + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + arch: x86_64 + force-avd-creation: true + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: ./gradlew :datasource:remote:clean :datasource:remote:createDebugCombinedCoverageReport --stacktrace + + - name: Upload DataSource module test coverage report to Codecov + if: matrix.api-level == 30 # Only upload coverage on API level 30 + run: bash <(curl -s https://codecov.io/bash) -F datasource -f "**/build/reports/jacoco/" \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 27be6dda..7066ac24 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.droidconke.android.hilt) alias(libs.plugins.compose.compiler) alias(libs.plugins.droidconke.android.application.firebase) + alias(libs.plugins.droidconke.android.application.jacoco) } android { diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index a5f544e0..653e129f 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -53,6 +53,14 @@ gradlePlugin { id = "droidconke.android.application" implementationClass = "AndroidApplicationConventionPlugin" } + register("androidApplicationJacoco") { + id = "droidconke.android.application.jacoco" + implementationClass = "AndroidApplicationJacocoConventionPlugin" + } + register("androidLibraryJacoco") { + id = "droidconke.android.library.jacoco" + implementationClass = "AndroidLibraryJacocoConventionPlugin" + } register("multiplatform") { id = "droidconke.multiplatform" implementationClass = "MultiplaftormConventionPlugin" diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt new file mode 100644 index 00000000..623cb666 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationJacocoConventionPlugin.kt @@ -0,0 +1,22 @@ +import com.android.build.api.variant.ApplicationAndroidComponentsExtension +import com.android.build.gradle.internal.dsl.BaseAppModuleExtension +import com.android254.configureJacoco +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.getByType + +class AndroidApplicationJacocoConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply("jacoco") + val androidExtension = extensions.getByType() + + androidExtension.buildTypes.configureEach { + enableAndroidTestCoverage = true + enableUnitTestCoverage = true + } + + configureJacoco(extensions.getByType()) + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt new file mode 100644 index 00000000..485fed8c --- /dev/null +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryJacocoConventionPlugin.kt @@ -0,0 +1,22 @@ +import com.android.build.api.dsl.LibraryExtension +import com.android.build.api.variant.LibraryAndroidComponentsExtension +import com.android254.configureJacoco +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.getByType + +class AndroidLibraryJacocoConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply("jacoco") + val androidExtension = extensions.getByType() + + androidExtension.buildTypes.configureEach { + enableAndroidTestCoverage = true + enableUnitTestCoverage = true + } + + configureJacoco(extensions.getByType()) + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/com/android254/Jacoco.kt b/build-logic/convention/src/main/kotlin/com/android254/Jacoco.kt new file mode 100644 index 00000000..0d406d7d --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/android254/Jacoco.kt @@ -0,0 +1,100 @@ +package com.android254 + +import com.android.build.api.artifact.ScopedArtifact +import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.ScopedArtifacts +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.ListProperty +import org.gradle.api.tasks.testing.Test +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType +import org.gradle.testing.jacoco.plugins.JacocoPluginExtension +import org.gradle.testing.jacoco.plugins.JacocoTaskExtension +import org.gradle.testing.jacoco.tasks.JacocoReport +import java.util.Locale + +private val coverageExclusions = listOf( + // Android + "**/R.class", + "**/R\$*.class", + "**/BuildConfig.*", + "**/Manifest*.*", + "**/*_Hilt*.class", + "**/Hilt_*.class", +) + +private fun String.capitalize() = replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() +} + +/** + * Creates a new task that generates a combined coverage report with data from local and + * instrumented tests. + * + * `create{variant}CombinedCoverageReport` + * + * Note that coverage data must exist before running the task. This allows us to run device + * tests on CI using a different Github Action or an external device. + */ +internal fun Project.configureJacoco( + androidComponentsExtension: AndroidComponentsExtension<*, *, *>, +) { + configure { + toolVersion = "0.8.11" + } + + androidComponentsExtension.onVariants { variant -> + val myObjFactory = project.objects + val buildDir = layout.buildDirectory.get().asFile + val allJars: ListProperty = myObjFactory.listProperty(RegularFile::class.java) + val allDirectories: ListProperty = myObjFactory.listProperty(Directory::class.java) + val reportTask = + tasks.register("create${variant.name.capitalize()}CombinedCoverageReport", JacocoReport::class) { + + classDirectories.setFrom( + allJars, + allDirectories.map { dirs -> + dirs.map { dir -> + myObjFactory.fileTree().setDir(dir).exclude(coverageExclusions) + } + } + ) + reports { + xml.required.set(true) + html.required.set(true) + } + + + sourceDirectories.setFrom(files("$projectDir/src/main/java", "$projectDir/src/main/kotlin")) + + executionData.setFrom( + project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest") + .matching { include("**/*.exec") }, + + project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest") + .matching { include("**/*.ec") } + ) + } + + + variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT) + .use(reportTask) + .toGet( + ScopedArtifact.CLASSES, + { _ -> allJars }, + { _ -> allDirectories }, + ) + } + + tasks.withType().configureEach { + configure { + + isIncludeNoLocationClasses = true + + excludes = listOf("jdk.internal.*") + } + } +} \ No newline at end of file diff --git a/chai/build.gradle.kts b/chai/build.gradle.kts index cacb6da4..cb3ed8a2 100644 --- a/chai/build.gradle.kts +++ b/chai/build.gradle.kts @@ -16,6 +16,7 @@ plugins { alias(libs.plugins.droidconke.android.library) alias(libs.plugins.droidconke.android.library.compose) + alias(libs.plugins.droidconke.android.library.jacoco) alias(libs.plugins.compose.compiler) } diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..019abf71 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,23 @@ +codecov: + notify: + wait_for_ci: true + max_report_age: off + require_ci_to_pass: true +comment: + behavior: default + layout: "reach, diff, flags, files" + show_carryforward_flags: false +coverage: + precision: 1 + status: + changes: false + patch: + default: + target: 60.0 + project: + default: + enabled: true + target: 25.0 +flag_management: + default_rules: + carryforward: true \ No newline at end of file diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 3f8021e9..5fd3f5a3 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.droidconke.android.hilt) alias(libs.plugins.droidconke.android.library.firebase) alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.droidconke.android.library.jacoco) } android { diff --git a/datasource/local/build.gradle.kts b/datasource/local/build.gradle.kts index be2deea2..88a102a6 100644 --- a/datasource/local/build.gradle.kts +++ b/datasource/local/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.droidconke.android.room) alias(libs.plugins.droidconke.android.hilt) alias(libs.plugins.droidconke.android.library.firebase) + alias(libs.plugins.droidconke.android.library.jacoco) } android { diff --git a/datasource/remote/build.gradle.kts b/datasource/remote/build.gradle.kts index 1a0a677a..73725fce 100644 --- a/datasource/remote/build.gradle.kts +++ b/datasource/remote/build.gradle.kts @@ -19,6 +19,7 @@ plugins { alias(libs.plugins.droidconke.android.hilt) alias(libs.plugins.droidconke.android.library.firebase) alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.droidconke.android.library.jacoco) } android { diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index b1fbc8d2..104ef38d 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -15,6 +15,7 @@ */ plugins { alias(libs.plugins.droidconke.android.library) + alias(libs.plugins.droidconke.android.library.jacoco) } android { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d7d742fc..60fbcdf1 100755 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ android-min-sdk = "24" composecompiler = "1.5.3" coroutines = "1.7.3" coroutines_datetime = "0.4.0" +desugar_jdk_libs = "2.0.3" espresso = "3.5.1" gradleplugin = "8.4.0" gmsPlugin = "4.4.0" @@ -56,25 +57,25 @@ toml_updater = "0.3.1" [libraries] android-appCompat = { module = "androidx.appcompat:appcompat", version.ref = "app_compat" } androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidxComposeBom" } -android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } +android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "coreKtx"} android-hilt = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } android-hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } -android-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltsecond" } -android-hilt-androidx-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hiltsecond" } +android-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltsecond"} +android-hilt-androidx-compiler = { module = "androidx.hilt:hilt-compiler" ,version.ref = "hiltsecond"} android-hilt-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" } -work-runtime = { module = "androidx.work:work-runtime-ktx", version.ref = "runtime" } -hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "hiltsecond" } -hilt-common = { module = "androidx.hilt:hilt-common", version.ref = "hiltsecond" } -android-material = { module = "com.google.android.material:material", version.ref = "material" } +work-runtime = { module = "androidx.work:work-runtime-ktx", version.ref = "runtime"} +hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "hiltsecond"} +hilt-common = { module = "androidx.hilt:hilt-common", version.ref = "hiltsecond"} +android-material = { module = "com.google.android.material:material", version.ref = "material"} android-test-compose = { module = "androidx.compose.ui:ui-test-junit4" } android-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" } android-test-idling = { module = "androidx.test.espresso:espresso-idling-resource", version.ref = "espresso" } -android-test-junit4 = { module = "androidx.test.ext:junit", version.ref = "junit" } +android-test-junit4 = { module = "androidx.test.ext:junit", version.ref = "junit"} androidx-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "splash" } -coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } -coil-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil" } -compose-activity = { module = "androidx.activity:activity-compose", version.ref = "activity" } -compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "composecompiler" } +coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil"} +coil-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil"} +compose-activity = { module = "androidx.activity:activity-compose", version.ref = "activity"} +compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "composecompiler"} compose-material-3 = { module = "androidx.compose.material3:material3" } compose-materialIcons = { module = "androidx.compose.material:material-icons-extended" } compose-runtimeLivedata = { module = "androidx.compose.runtime:runtime-livedata" } @@ -84,35 +85,36 @@ compose-ui-test-junit = { module = "androidx.compose.ui:ui-test-junit4" } compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } -compose-preview-customview = { module = "androidx.customview:customview", version.ref = "preview_customview" } -compose-preview-customview-poolingcontainer = { module = "androidx.customview:customview-poolingcontainer", version.ref = "poolingcontainer" } -compose-constraintlayout = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayout" } -compose-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" } -accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "swiperefresh" } -gson-gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +compose-preview-customview = { module = "androidx.customview:customview", version.ref = "preview_customview"} +compose-preview-customview-poolingcontainer = { module = "androidx.customview:customview-poolingcontainer", version.ref = "poolingcontainer"} +compose-constraintlayout = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayout"} +compose-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle"} +accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "swiperefresh"} +desugar-jdk-libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" } +gson-gson = { module = "com.google.code.gson:gson", version.ref = "gson"} kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } -kotlin-coroutines-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "coroutines_datetime" } +kotlin-coroutines-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "coroutines_datetime"} kotlin-coroutines-play-services = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "coroutines" } -gms-play-services-auth = { module = "com.google.android.gms:play-services-auth", version.ref = "auth" } +gms-play-services-auth = { module = "com.google.android.gms:play-services-auth", version.ref = "auth"} lifecycle-livedataKtx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" } lifecycle-runtimeKtx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" } lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" } lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottie" } -paging-common = { module = "androidx.paging:paging-common-ktx", version.ref = "paging" } -paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging" } +paging-common = { module = "androidx.paging:paging-common-ktx", version.ref = "paging"} +paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging"} result-jvm = { module = "com.github.kittinunf.result:result-jvm", version.ref = "result_jvm" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } room-paging = { module = "androidx.room:room-paging", version.ref = "room" } room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } -datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" } -timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } -test-androidx-core = { module = "androidx.test:core-ktx", version.ref = "test_corektx" } -test-robolectric = { module = "org.robolectric:robolectric", version.ref = "test_robolectric" } -test-navigation = { module = "androidx.navigation:navigation-testing", version.ref = "test_navigation" } -test-mockk = { module = "io.mockk:mockk", version.ref = "test_mockk" } +datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore"} +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber"} +test-androidx-core = { module = "androidx.test:core-ktx", version.ref = "test_corektx"} +test-robolectric = { module = "org.robolectric:robolectric", version.ref = "test_robolectric"} +test-navigation = { module = "androidx.navigation:navigation-testing", version.ref = "test_navigation"} +test-mockk = { module = "io.mockk:mockk", version.ref = "test_mockk"} ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" } ktor-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } @@ -121,21 +123,21 @@ ktor-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = ktor-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor" } ktor-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" } ktor-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } -firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase_bom" } +firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase_bom"} firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" } firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" } firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" } firebase-performance = { module = "com.google.firebase:firebase-perf-ktx" } firebase-config = { module = "com.google.firebase:firebase-config-ktx" } firebase-remote-config = { module = "com.google.firebase:firebase-config-ktx", version.ref = "remote_config" } -firebase-common = { module = "com.google.firebase:firebase-common-ktx", version.ref = "firebase_common" } +firebase-common = { module = "com.google.firebase:firebase-common-ktx", version.ref = "firebase_common"} chucker-debug = { module = "com.github.chuckerteam.chucker:library", version.ref = "chucker" } chucker-release = { module = "com.github.chuckerteam.chucker:library-no-op", version.ref = "chucker" } -app-cash-turbine-turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } -junit-androidx = { module = "androidx.test.ext:junit", version.ref = "junit" } -junit-androidx-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit" } -test-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit" } +app-cash-turbine-turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine"} +junit-androidx = { module = "androidx.test.ext:junit", version.ref = "junit"} +junit-androidx-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit"} +test-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit"} junit4 = { module = "junit:junit", version.ref = "junit4" } # Dependencies of the included build-logic @@ -146,7 +148,7 @@ kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", ve ksp-gradlePlugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } [bundles] -compose = ["coil-compose", "coil-svg", "compose-activity", "compose-material-3", "compose-materialIcons", "compose-runtimeLivedata", "compose-ui", "compose-ui-util", "compose-ui-tooling", "compose-ui-tooling-preview", "paging-compose", "compose-preview-customview", "compose-preview-customview-poolingcontainer", "compose-constraintlayout", "compose-lifecycle-runtime"] +compose = ["coil-compose", "coil-svg", "compose-activity", "compose-compiler", "compose-material-3", "compose-materialIcons", "compose-runtimeLivedata", "compose-ui", "compose-ui-util", "compose-ui-tooling", "compose-ui-tooling-preview", "paging-compose", "compose-preview-customview", "compose-preview-customview-poolingcontainer", "compose-constraintlayout", "compose-lifecycle-runtime"] lifecycle = ["lifecycle-livedataKtx", "lifecycle-runtimeKtx", "lifecycle-viewmodel-compose"] room = ["room-ktx", "room-paging", "room-runtime"] ktor = ["ktor-core", "ktor-android", "ktor-json", "ktor-content-negotiation", "ktor-auth", "ktor-logging", "ktor-okhttp"] @@ -180,4 +182,6 @@ droidconke-android-application-firebase = { id = "droidconke.android.application droidconke-android-library-firebase = { id = "droidconke.android.library.firebase", version = "unspecified" } droidconke-android-application = { id = "droidconke.android.application", version = "unspecified" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +droidconke-android-application-jacoco = { id = "droidconke.android.application.jacoco", version = "unspecified" } +droidconke-android-library-jacoco = { id = "droidconke.android.library.jacoco", version = "unspecified" } droidconke-multiplatform = { id = "droidconke.multiplatform", version = "unspecified" } \ No newline at end of file diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index bc9226ed..5e261f35 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.droidconke.android.hilt) alias(notation = libs.plugins.compose.compiler) alias(libs.plugins.droidconke.android.library.compose) + alias(libs.plugins.droidconke.android.library.jacoco) } android {