From b66359ab8db6b1125272c83bd8f0da53cae15f3a Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Wed, 15 Nov 2023 17:17:13 -0500 Subject: [PATCH] Implement Circuit DSL (#637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easy to add circuit up to a project. ```kotlin slack { features { circuit() } } ``` --- docs/dsl.md | 6 + .../kotlin/slack/gradle/SlackExtension.kt | 103 +++++++++++++++++- .../main/kotlin/slack/gradle/SlackVersions.kt | 3 + 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/docs/dsl.md b/docs/dsl.md index 78115743e..ba5763b7a 100644 --- a/docs/dsl.md +++ b/docs/dsl.md @@ -25,6 +25,12 @@ slack { ## Features +### Circuit + +The Circuit feature automatically sets up [Circuit](https://github.com/slackhq/circuit) in the project. This includes +controls for different Circuit artifacts and code gen. The default `circuit()` call will just enable Circuit's +runtime + code gen. + ### Dagger The Dagger feature automatically sets up both Dagger and Anvil. This includes optional parameters to control whether or diff --git a/slack-plugin/src/main/kotlin/slack/gradle/SlackExtension.kt b/slack-plugin/src/main/kotlin/slack/gradle/SlackExtension.kt index 1b27d472f..71d5d7469 100644 --- a/slack-plugin/src/main/kotlin/slack/gradle/SlackExtension.kt +++ b/slack-plugin/src/main/kotlin/slack/gradle/SlackExtension.kt @@ -230,6 +230,12 @@ constructor( } } + if (featuresHandler.circuitHandler.codegen.getOrElse(false)) { + markKspNeeded("Circuit") + dependencies.add(aptConfiguration(), "com.slack.circuit:circuit-codegen") + dependencies.add("compileOnly", "com.slack.circuit:circuit-codegen-annotations") + } + if (featuresHandler.autoValue.getOrElse(false)) { markKaptNeeded("AutoValue") dependencies.add("compileOnly", SlackDependencies.Auto.Value.annotations) @@ -351,6 +357,9 @@ constructor( // Dagger features internal val daggerHandler = objects.newInstance() + // Circuit features + internal val circuitHandler = objects.newInstance() + /** Enables AutoService on this project. */ internal abstract val autoService: Property @@ -385,6 +394,32 @@ constructor( this.androidExtension = androidExtension } + /** + * Configures Circuit on this project. + * + * @param codegen configures code gen on this project, including KSP setup and annotations. True + * by default. + * @param runtime configures the circuit-runtime dependencies, including screen/ui/presenter. True + * by default. + * @param commonBundle configures the project-common dependencies, defined by the circuit-common + * bundle ID in `libs.versions.toml`. True by default. + * @param foundation configures the circuit-foundation dependency, false by default. + * @param action optional configuration block for further Circuit config, such as CircuitX. + */ + public fun circuit( + codegen: Boolean = true, + runtime: Boolean = true, + commonBundle: Boolean = true, + foundation: Boolean = false, + action: Action = Action {}, + ) { + circuitHandler.codegen.set(codegen) + circuitHandler.runtime.set(runtime) + circuitHandler.commonBundle.set(commonBundle) + circuitHandler.foundation.set(foundation) + action.execute(circuitHandler) + } + /** * Enables dagger for this project. * @@ -517,11 +552,11 @@ constructor( internal fun applyTo(project: Project) { composeHandler.applyTo(project, slackProperties) + circuitHandler.applyTo(project, slackProperties) } } @SlackExtensionMarker -@Suppress("UnnecessaryAbstractClass") public abstract class MoshiHandler { internal abstract val moshi: Property internal abstract val moshiAdapters: Property @@ -578,8 +613,70 @@ public abstract class MoshiHandler { } } +/** DSL for configuring Circuit. */ +@SlackExtensionMarker +public abstract class CircuitHandler @Inject constructor(objects: ObjectFactory) { + /** Sets up circuit code gen, includes annotations and KSP setup. */ + public val codegen: Property = objects.property().convention(false) + /** Includes the circuit-runtime dep (including screen, ui, presenter). */ + public val runtime: Property = objects.property().convention(false) + /** Includes the circuit-foundation dep. */ + public val foundation: Property = objects.property().convention(false) + /** + * When enabled, includes a common bundle as defined by the `circuit-common` bundle ID in + * `libs.versions.toml`. + */ + public val commonBundle: Property = objects.property().convention(false) + public val circuitx: CircuitXHandler = objects.newInstance() + + /** DSL entrypoint for CircuitX dependencies. */ + public fun circuitx(action: Action) { + action.execute(circuitx) + } + + internal fun applyTo(project: Project, slackProperties: SlackProperties) { + if (runtime.getOrElse(false)) { + project.dependencies.add("implementation", "com.slack.circuit:circuit-runtime") + project.dependencies.add("implementation", "com.slack.circuit:circuit-runtime-presenter") + project.dependencies.add("implementation", "com.slack.circuit:circuit-runtime-ui") + project.dependencies.add("testImplementation", "com.slack.circuit:circuit-test") + } + if (foundation.getOrElse(false)) { + project.dependencies.add("implementation", "com.slack.circuit:circuit-foundation") + } + if (commonBundle.getOrElse(false)) { + slackProperties.versions.bundles.commonCircuit.ifPresent { + project.dependencies.add("implementation", it) + } + } + + circuitx.applyTo(project) + } + + @SlackExtensionMarker + public abstract class CircuitXHandler @Inject constructor(objects: ObjectFactory) { + /** Correpsonds to the circuitx-android artifact. */ + public val android: Property = objects.property().convention(false) + /** Correpsonds to the circuitx-gesture-navigation artifact. */ + public val gestureNav: Property = objects.property().convention(false) + /** Correpsonds to the circuitx-overlays artifact. */ + public val overlays: Property = objects.property().convention(false) + + internal fun applyTo(project: Project) { + if (android.getOrElse(false)) { + project.dependencies.add("implementation", "com.slack.circuit:circuitx-android") + } + if (gestureNav.getOrElse(false)) { + project.dependencies.add("implementation", "com.slack.circuit:circuitx-gesture-navigation") + } + if (overlays.getOrElse(false)) { + project.dependencies.add("implementation", "com.slack.circuit:circuitx-overlays") + } + } + } +} + @SlackExtensionMarker -@Suppress("UnnecessaryAbstractClass") public abstract class DaggerHandler @Inject constructor(objects: ObjectFactory) { internal val enabled: Property = objects.property().convention(false) internal val useDaggerCompiler: Property = objects.property().convention(false) @@ -661,7 +758,6 @@ public abstract class DaggerHandler @Inject constructor(objects: ObjectFactory) } @SlackExtensionMarker -@Suppress("UnnecessaryAbstractClass") public abstract class ComposeHandler @Inject constructor( @@ -722,7 +818,6 @@ constructor( } @SlackExtensionMarker -@Suppress("UnnecessaryAbstractClass") public abstract class AndroidHandler @Inject constructor( diff --git a/slack-plugin/src/main/kotlin/slack/gradle/SlackVersions.kt b/slack-plugin/src/main/kotlin/slack/gradle/SlackVersions.kt index 8eb13c014..1936105e8 100644 --- a/slack-plugin/src/main/kotlin/slack/gradle/SlackVersions.kt +++ b/slack-plugin/src/main/kotlin/slack/gradle/SlackVersions.kt @@ -88,6 +88,9 @@ internal class SlackVersions(val catalog: VersionCatalog) { val commonTest: Optional> by lazy { catalog.findBundle("common-test") } + val commonCircuit: Optional> by lazy { + catalog.findBundle("common-circuit") + } } internal fun getValue(key: String): String {