Use Anvil KSP instead of the Square KAPT one (#3564)
* Use Anvil KSP instead of the Square KAPT one * Fix several configuration cache, lint and test issues * Allow incremental kotlin compilation in the CI * Workaround Robolectric + Compose issue that caused `AppNotIdleException` * Update the `enterprise` commit hash * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
f344a1282c
commit
79c17f714f
54 changed files with 463 additions and 348 deletions
|
|
@ -16,22 +16,40 @@ import org.gradle.plugin.use.PluginDependency
|
|||
|
||||
/**
|
||||
* Setup Anvil plugin with the given configuration.
|
||||
* @param generateDaggerCode whether to enable general Dagger code generation using Kapt
|
||||
* @param generateDaggerFactoriesUsingAnvil whether to generate Dagger factories using Anvil instead of Kapt
|
||||
* @param generateDaggerCode whether to enable general Dagger code generation using Kapt. `false` by default.
|
||||
* @param generateDaggerFactoriesUsingAnvil whether to generate Dagger factories using Anvil instead of Kapt. `true` by default.
|
||||
* @param componentMergingStrategy how to perform component merging. This is `ComponentMergingStrategy.NONE` by default, which will prevent component merging
|
||||
* from running.
|
||||
*/
|
||||
fun Project.setupAnvil(
|
||||
generateDaggerCode: Boolean = false,
|
||||
generateDaggerFactoriesUsingAnvil: Boolean = true,
|
||||
componentMergingStrategy: ComponentMergingStrategy = ComponentMergingStrategy.NONE,
|
||||
) {
|
||||
val libs = the<LibrariesForLibs>()
|
||||
// Apply plugins and dependencies
|
||||
|
||||
// Add dagger dependency, needed for generated code
|
||||
dependencies.implementation(libs.dagger)
|
||||
|
||||
// Apply Anvil plugin and configure it
|
||||
applyPluginIfNeeded(libs.plugins.anvil)
|
||||
|
||||
project.pluginManager.withPlugin(libs.plugins.anvil.get().pluginId) {
|
||||
// Setup extension
|
||||
extensions.configure(AnvilExtension::class.java) {
|
||||
this.generateDaggerFactories.set(generateDaggerFactoriesUsingAnvil)
|
||||
this.disableComponentMerging.set(componentMergingStrategy == ComponentMergingStrategy.NONE)
|
||||
|
||||
useKsp(
|
||||
contributesAndFactoryGeneration = true,
|
||||
componentMerging = componentMergingStrategy == ComponentMergingStrategy.KSP,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (generateDaggerCode) {
|
||||
applyPluginIfNeeded(libs.plugins.kapt)
|
||||
// Needed at the top level since dagger code should be generated at a single point for performance
|
||||
dependencies.implementation(libs.dagger)
|
||||
dependencies.add("kapt", libs.dagger.compiler)
|
||||
// Needed at the top level since dagger code should be generated at a single point for performance reasons
|
||||
dependencies.add("ksp", libs.dagger.compiler)
|
||||
}
|
||||
|
||||
// These dependencies are only needed for compose library or application modules
|
||||
|
|
@ -40,14 +58,7 @@ fun Project.setupAnvil(
|
|||
// Annotations to generate DI code for Appyx nodes
|
||||
dependencies.implementation(project.project(":anvilannotations"))
|
||||
// Code generator for the annotations above
|
||||
dependencies.add("anvil", project.project(":anvilcodegen"))
|
||||
}
|
||||
|
||||
project.pluginManager.withPlugin(libs.plugins.anvil.get().pluginId) {
|
||||
// Setup extension
|
||||
extensions.configure(AnvilExtension::class.java) {
|
||||
this.generateDaggerFactories.set(generateDaggerFactoriesUsingAnvil)
|
||||
}
|
||||
dependencies.add("ksp", project.project(":anvilcodegen"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,3 +68,9 @@ private fun Project.applyPluginIfNeeded(plugin: Provider<PluginDependency>) {
|
|||
pluginManager.apply(pluginId)
|
||||
}
|
||||
}
|
||||
|
||||
enum class ComponentMergingStrategy {
|
||||
NONE,
|
||||
KAPT,
|
||||
KSP
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,16 @@
|
|||
|
||||
package extension
|
||||
|
||||
import config.AnalyticsConfig
|
||||
import ModulesConfig
|
||||
import config.AnalyticsConfig
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.kotlin.dsl.DependencyHandlerScope
|
||||
import org.gradle.kotlin.dsl.closureOf
|
||||
import org.gradle.kotlin.dsl.project
|
||||
import java.io.File
|
||||
|
||||
private fun DependencyHandlerScope.implementation(dependency: Any) = dependencies.add("implementation", dependency)
|
||||
internal fun DependencyHandler.implementation(dependency: Any) = add("implementation", dependency)
|
||||
|
|
@ -26,7 +25,7 @@ internal fun DependencyHandler.implementation(dependency: Any) = add("implementa
|
|||
private fun DependencyHandlerScope.implementation(
|
||||
dependency: Any,
|
||||
config: Action<ExternalModuleDependency>
|
||||
) = dependencies.add("implementation", dependency, closureOf<ExternalModuleDependency> { config.execute(this) })
|
||||
) = dependencies.add("implementation", dependency, closureOf<ExternalModuleDependency> { config.execute(this) })
|
||||
|
||||
private fun DependencyHandlerScope.androidTestImplementation(dependency: Any) = dependencies.add("androidTestImplementation", dependency)
|
||||
|
||||
|
|
@ -58,26 +57,6 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) {
|
|||
implementation(libs.kotlinx.collections.immutable)
|
||||
}
|
||||
|
||||
private fun DependencyHandlerScope.addImplementationProjects(
|
||||
directory: File,
|
||||
path: String,
|
||||
nameFilter: String,
|
||||
logger: Logger,
|
||||
) {
|
||||
directory.listFiles().orEmpty().also { it.sort() }.forEach { file ->
|
||||
if (file.isDirectory) {
|
||||
val newPath = "$path:${file.name}"
|
||||
val buildFile = File(file, "build.gradle.kts")
|
||||
if (buildFile.exists() && file.name == nameFilter) {
|
||||
implementation(project(newPath))
|
||||
logger.lifecycle("Added implementation(project($newPath))")
|
||||
} else {
|
||||
addImplementationProjects(file, newPath, nameFilter, logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.allLibrariesImpl() {
|
||||
implementation(project(":libraries:androidutils"))
|
||||
implementation(project(":libraries:deeplink"))
|
||||
|
|
@ -128,22 +107,21 @@ fun DependencyHandlerScope.allServicesImpl() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
implementation(project(":services:apperror:impl"))
|
||||
implementation(project(":services:appnavstate:impl"))
|
||||
implementation(project(":services:toolbox:impl"))
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.allEnterpriseImpl(rootDir: File, logger: Logger) {
|
||||
val enterpriseDir = File(rootDir, "enterprise")
|
||||
addImplementationProjects(enterpriseDir, ":enterprise", "impl", logger)
|
||||
}
|
||||
fun DependencyHandlerScope.allEnterpriseImpl(project: Project) = addAll(project, "enterprise", "impl")
|
||||
|
||||
fun DependencyHandlerScope.allFeaturesApi(rootDir: File, logger: Logger) {
|
||||
val featuresDir = File(rootDir, "features")
|
||||
addImplementationProjects(featuresDir, ":features", "api", logger)
|
||||
}
|
||||
fun DependencyHandlerScope.allFeaturesImpl(project: Project) = addAll(project, "features", "impl")
|
||||
|
||||
fun DependencyHandlerScope.allFeaturesImpl(rootDir: File, logger: Logger) {
|
||||
val featuresDir = File(rootDir, "features")
|
||||
addImplementationProjects(featuresDir, ":features", "impl", logger)
|
||||
fun DependencyHandlerScope.allFeaturesApi(project: Project) = addAll(project, "features", "api")
|
||||
|
||||
private fun DependencyHandlerScope.addAll(project: Project, prefix: String, suffix: String) {
|
||||
val subProjects = project.rootProject.subprojects.filter { it.path.startsWith(":$prefix") && it.path.endsWith(":$suffix") }
|
||||
for (p in subProjects) {
|
||||
add("implementation", p)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension
|
|||
import kotlinx.kover.gradle.plugin.dsl.KoverVariantCreateConfig
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.configurationcache.extensions.capitalized
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
|
||||
|
|
@ -142,24 +141,18 @@ fun Project.setupKover() {
|
|||
}
|
||||
}
|
||||
filters {
|
||||
includes {
|
||||
classes(
|
||||
"*Presenter",
|
||||
)
|
||||
}
|
||||
excludes {
|
||||
classes(
|
||||
"*Fake*Presenter*",
|
||||
"io.element.android.appnav.loggedin.LoggedInPresenter$*",
|
||||
// Some options can't be tested at the moment
|
||||
"io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
|
||||
// Need an Activity to use rememberMultiplePermissionsState
|
||||
"io.element.android.features.location.impl.common.permissions.DefaultPermissionsPresenter",
|
||||
"*Presenter\$present\$*",
|
||||
// Too small to be > 85% tested
|
||||
"io.element.android.libraries.fullscreenintent.impl.DefaultFullScreenIntentPermissionsPresenter",
|
||||
)
|
||||
}
|
||||
excludes.classes(
|
||||
"*Fake*Presenter*",
|
||||
"io.element.android.appnav.loggedin.LoggedInPresenter$*",
|
||||
// Some options can't be tested at the moment
|
||||
"io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*",
|
||||
// Need an Activity to use rememberMultiplePermissionsState
|
||||
"io.element.android.features.location.impl.common.permissions.DefaultPermissionsPresenter",
|
||||
"*Presenter\$present\$*",
|
||||
// Too small to be > 85% tested
|
||||
"io.element.android.libraries.fullscreenintent.impl.DefaultFullScreenIntentPermissionsPresenter",
|
||||
)
|
||||
includes.inheritedFrom("io.element.android.libraries.architecture.Presenter")
|
||||
}
|
||||
}
|
||||
variant(KoverVariant.States.variantName) {
|
||||
|
|
@ -175,33 +168,31 @@ fun Project.setupKover() {
|
|||
}
|
||||
}
|
||||
filters {
|
||||
includes {
|
||||
classes(
|
||||
"^*State$",
|
||||
)
|
||||
}
|
||||
excludes {
|
||||
classes(
|
||||
"io.element.android.appnav.root.RootNavState*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*",
|
||||
"io.element.android.libraries.matrix.api.room.RoomMembershipState*",
|
||||
"io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*",
|
||||
"io.element.android.libraries.push.impl.notifications.NotificationState*",
|
||||
"io.element.android.features.messages.impl.media.local.pdf.PdfViewerState",
|
||||
"io.element.android.features.messages.impl.media.local.LocalMediaViewState",
|
||||
"io.element.android.features.location.impl.map.MapState*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
|
||||
"io.element.android.libraries.designsystem.swipe.SwipeableActionsState*",
|
||||
"io.element.android.features.messages.impl.timeline.components.ExpandableState*",
|
||||
"io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*",
|
||||
"io.element.android.libraries.maplibre.compose.CameraPositionState*",
|
||||
"io.element.android.libraries.maplibre.compose.SaveableCameraPositionState",
|
||||
"io.element.android.libraries.maplibre.compose.SymbolState*",
|
||||
"io.element.android.features.ftue.api.state.*",
|
||||
"io.element.android.features.ftue.impl.welcome.state.*",
|
||||
)
|
||||
}
|
||||
excludes.classes(
|
||||
"*State$*", // Exclude inner classes
|
||||
"io.element.android.appnav.root.RootNavState*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.EventSendState$*",
|
||||
"io.element.android.libraries.matrix.api.room.RoomMembershipState*",
|
||||
"io.element.android.libraries.matrix.api.room.MatrixRoomMembersState*",
|
||||
"io.element.android.libraries.push.impl.notifications.NotificationState*",
|
||||
"io.element.android.features.messages.impl.media.local.pdf.PdfViewerState",
|
||||
"io.element.android.features.messages.impl.media.local.LocalMediaViewState",
|
||||
"io.element.android.features.location.impl.map.MapState*",
|
||||
"io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*",
|
||||
"io.element.android.libraries.designsystem.swipe.SwipeableActionsState*",
|
||||
"io.element.android.features.messages.impl.timeline.components.ExpandableState*",
|
||||
"io.element.android.features.messages.impl.timeline.model.bubble.BubbleState*",
|
||||
"io.element.android.libraries.maplibre.compose.CameraPositionState*",
|
||||
"io.element.android.libraries.maplibre.compose.SaveableCameraPositionState",
|
||||
"io.element.android.libraries.maplibre.compose.SymbolState*",
|
||||
"io.element.android.features.ftue.api.state.*",
|
||||
"io.element.android.features.ftue.impl.welcome.state.*",
|
||||
"io.element.android.libraries.designsystem.theme.components.bottomsheet.CustomSheetState",
|
||||
"io.element.android.libraries.mediaviewer.api.local.pdf.PdfViewerState",
|
||||
"io.element.android.libraries.textcomposer.model.TextEditorState",
|
||||
)
|
||||
includes.classes("*State")
|
||||
}
|
||||
}
|
||||
variant(KoverVariant.Views.variantName) {
|
||||
|
|
@ -218,11 +209,8 @@ fun Project.setupKover() {
|
|||
}
|
||||
}
|
||||
filters {
|
||||
includes {
|
||||
classes(
|
||||
"*ViewKt",
|
||||
)
|
||||
}
|
||||
excludes.classes("*ViewKt$*") // Exclude inner classes
|
||||
includes.classes("*ViewKt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -236,16 +224,31 @@ fun Project.applyKoverPluginToAllSubProjects() = rootProject.subprojects {
|
|||
currentProject {
|
||||
for (variant in koverVariants) {
|
||||
createVariant(variant) {
|
||||
defaultVariants()
|
||||
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() {
|
||||
addWithDependencies("gplayDebug", "debug", optional = true)
|
||||
fun KoverVariantCreateConfig.defaultVariants(project: Project) {
|
||||
if (project.name == "app") {
|
||||
addWithDependencies("gplayDebug")
|
||||
} else {
|
||||
addWithDependencies("debug", "jvm", optional = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.koverSubprojects() = project.rootProject.subprojects
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue