Skip to content

Commit

Permalink
chore: Establish build-logic module for centralized dependency manage…
Browse files Browse the repository at this point in the history
…ment.
  • Loading branch information
azrael8576 committed Nov 30, 2023
1 parent 21f953b commit c4597ce
Show file tree
Hide file tree
Showing 25 changed files with 739 additions and 0 deletions.
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,7 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")

// Timber
implementation(libs.timber)
}
38 changes: 38 additions & 0 deletions build-logic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Convention Plugins

The `build-logic` folder defines project-specific convention plugins, used to keep a single
source of truth for common module configurations.

This approach is heavily based on
[https://developer.squareup.com/blog/herding-elephants/](https://developer.squareup.com/blog/herding-elephants/)
and
[https://github.com/jjohannes/idiomatic-gradle](https://github.com/jjohannes/idiomatic-gradle).

By setting up convention plugins in `build-logic`, we can avoid duplicated build script setup,
messy `subproject` configurations, without the pitfalls of the `buildSrc` directory.

`build-logic` is an included build, as configured in the root
[`settings.gradle.kts`](../settings.gradle.kts).

Inside `build-logic` is a `convention` module, which defines a set of plugins that all normal
modules can use to configure themselves.

`build-logic` also includes a set of `Kotlin` files used to share logic between plugins themselves,
which is most useful for configuring Android components (libraries vs applications) with shared
code.

These plugins are *additive* and *composable*, and try to only accomplish a single responsibility.
Modules can then pick and choose the configurations they need.
If there is one-off logic for a module without shared code, it's preferable to define that directly
in the module's `build.gradle`, as opposed to creating a convention plugin with module-specific
setup.

Current list of convention plugins:

- [`pq.android.application`](convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt),
[`pq.android.library`](convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt),
[`pq.android.test`](convention/src/main/kotlin/AndroidTestConventionPlugin.kt):
Configures common Android and Kotlin options.
- [`pq.android.application.compose`](convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt),
[`pq.android.library.compose`](convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt):
Configures Jetpack Compose options
1 change: 1 addition & 0 deletions build-logic/convention/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
66 changes: 66 additions & 0 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
`kotlin-dsl`
}

group = "com.wei.picquest.buildlogic"

// Configure the build-logic plugins to target JDK 17
// This matches the JDK used to build the project, and is not related to what is running on device.
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
}

dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.ksp.gradlePlugin)
}

gradlePlugin {
plugins {
register("androidApplicationCompose") {
id = "pq.android.application.compose"
implementationClass = "AndroidApplicationComposeConventionPlugin"
}
register("androidApplication") {
id = "pq.android.application"
implementationClass = "AndroidApplicationConventionPlugin"
}
register("androidLibraryCompose") {
id = "pq.android.library.compose"
implementationClass = "AndroidLibraryComposeConventionPlugin"
}
register("androidLibrary") {
id = "pq.android.library"
implementationClass = "AndroidLibraryConventionPlugin"
}
register("androidFeature") {
id = "pq.android.feature"
implementationClass = "AndroidFeatureConventionPlugin"
}
register("androidTest") {
id = "pq.android.test"
implementationClass = "AndroidTestConventionPlugin"
}
register("androidHilt") {
id = "pq.android.hilt"
implementationClass = "AndroidHiltConventionPlugin"
}
register("androidFlavors") {
id = "pq.android.application.flavors"
implementationClass = "AndroidApplicationFlavorsConventionPlugin"
}
register("jvmLibrary") {
id = "pq.jvm.library"
implementationClass = "JvmLibraryConventionPlugin"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import com.android.build.api.dsl.ApplicationExtension
import com.wei.picquest.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType

class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.application")
// Screenshot Tests
pluginManager.apply("io.github.takahirom.roborazzi")

val extension = extensions.getByType<ApplicationExtension>()
configureAndroidCompose(extension)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import com.android.build.api.dsl.ApplicationExtension
import com.wei.picquest.configureGradleManagedDevices
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.wei.picquest.configureKotlinAndroid
import com.wei.picquest.configurePrintApksTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidApplicationConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.application")
apply("org.jetbrains.kotlin.android")
}

extensions.configure<ApplicationExtension> {
configureKotlinAndroid(this)
defaultConfig.targetSdk = 34
configureGradleManagedDevices(this)
}
extensions.configure<ApplicationAndroidComponentsExtension> {
configurePrintApksTask(this)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import com.android.build.api.dsl.ApplicationExtension
import com.wei.picquest.configureFlavors
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidApplicationFlavorsConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
extensions.configure<ApplicationExtension> {
configureFlavors(this)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import com.android.build.gradle.LibraryExtension
import com.wei.picquest.configureGradleManagedDevices
import com.wei.picquest.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin

class AndroidFeatureConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply {
apply("pq.android.library")
apply("pq.android.hilt")
apply("androidx.navigation.safeargs.kotlin")
}
extensions.configure<LibraryExtension> {
defaultConfig {
testInstrumentationRunner =
"com.wei.picquest.core.testing.AtTestRunner"
}
configureGradleManagedDevices(this)
}

dependencies {
add("implementation", project(":core:network"))
add("implementation", project(":core:common"))
add("implementation", project(":core:designsystem"))
add("implementation", project(":core:data"))
add("implementation", project(":core:model"))
add("implementation", project(":core:domain"))

add("testImplementation", kotlin("test"))
add("testImplementation", project(":core:testing"))
add("androidTestImplementation", kotlin("test"))
add("androidTestImplementation", project(":core:testing"))
add("androidTestImplementation", project(":core:designsystem"))

add("implementation", libs.findLibrary("coil.kt").get())
add("implementation", libs.findLibrary("coil.kt.compose").get())
add("implementation", libs.findLibrary("coil.kt.svg").get())

add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get())
add("implementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get())

add("implementation", libs.findLibrary("kotlinx.coroutines.android").get())
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.wei.picquest.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies

class AndroidHiltConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("dagger.hilt.android.plugin")
// KAPT must go last to avoid build warnings.
// See: https://stackoverflow.com/questions/70550883/warning-the-following-options-were-not-recognized-by-any-processor-dagger-f
apply("org.jetbrains.kotlin.kapt")
}

dependencies {
"implementation"(libs.findLibrary("hilt.android").get())
"kapt"(libs.findLibrary("hilt.compiler").get())
"kaptAndroidTest"(libs.findLibrary("hilt.compiler").get())
"kaptTest"(libs.findLibrary("hilt.compiler").get())
}

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import com.android.build.gradle.LibraryExtension
import com.wei.picquest.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.getByType

class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.library")
// Screenshot Tests
pluginManager.apply("io.github.takahirom.roborazzi")

val extension = extensions.getByType<LibraryExtension>()
configureAndroidCompose(extension)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.LibraryExtension
import com.wei.picquest.configureFlavors
import com.wei.picquest.configureGradleManagedDevices
import com.wei.picquest.configureKotlinAndroid
import com.wei.picquest.configurePrintApksTask
import com.wei.picquest.disableUnnecessaryAndroidTests
import com.wei.picquest.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin

class AndroidLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.library")
apply("org.jetbrains.kotlin.android")
}

extensions.configure<LibraryExtension> {
configureKotlinAndroid(this)
defaultConfig.targetSdk = 34
configureFlavors(this)
configureGradleManagedDevices(this)
}
extensions.configure<LibraryAndroidComponentsExtension> {
configurePrintApksTask(this)
disableUnnecessaryAndroidTests(target)
}
dependencies {
add("testImplementation", kotlin("test"))
add("testImplementation", project(":core:testing"))
add("androidTestImplementation", kotlin("test"))
add("androidTestImplementation", project(":core:testing"))

// Timber
add("implementation", libs.findLibrary("timber").get())
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import com.android.build.gradle.TestExtension
import com.wei.picquest.configureGradleManagedDevices
import com.wei.picquest.configureKotlinAndroid
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure

class AndroidTestConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.test")
apply("org.jetbrains.kotlin.android")
}

extensions.configure<TestExtension> {
configureKotlinAndroid(this)
defaultConfig.targetSdk = 34
configureGradleManagedDevices(this)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import com.wei.picquest.configureKotlinJvm
import org.gradle.api.Plugin
import org.gradle.api.Project

class JvmLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.jvm")
}
configureKotlinJvm()
}
}
}
Loading

0 comments on commit c4597ce

Please sign in to comment.