Extract common build logic to convention plugins

This commit is contained in:
FooIbar committed 2025-08-03 10:39:03 +08:00
1 parent 1a66d84bd0
commit 295770002a
18 files changed
+302 -62

No files matched your search

+3
View File
@@ -42,6 +42,9 @@ jobs:
with: with:
cache-read-only: true cache-read-only: true
- name: Check build-logic
run: ./gradlew :build-logic:convention:check
- name: Spotless Check - name: Spotless Check
run: ./gradlew spotlessCheck run: ./gradlew spotlessCheck
+3 -2
View File
@@ -1,8 +1,9 @@
.gradle .gradle
/local.properties /local.properties
.DS_Store .DS_Store
/build build
/.kotlin .cxx
.kotlin
*.iml *.iml
.idea .idea
.vscode .vscode
-2
View File
@@ -1,2 +0,0 @@
/build
/.cxx
+4 -52
View File
@@ -1,20 +1,15 @@
import com.mikepenz.aboutlibraries.plugin.DuplicateMode import com.mikepenz.aboutlibraries.plugin.DuplicateMode
import com.mikepenz.aboutlibraries.plugin.DuplicateRule import com.mikepenz.aboutlibraries.plugin.DuplicateRule
import java.util.regex.Pattern import java.util.regex.Pattern
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
val isRelease: Boolean val isRelease: Boolean
get() = gradle.startParameter.taskNames.any { it.contains("Release") } get() = gradle.startParameter.taskNames.any { it.contains("Release") }
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.ehviewer.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization) alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp) alias(libs.plugins.ksp)
alias(libs.plugins.spotless)
alias(libs.plugins.aboutlibrariesPlugin) alias(libs.plugins.aboutlibrariesPlugin)
alias(libs.plugins.composeCompilerReportGenerator)
alias(libs.plugins.baselineprofile) alias(libs.plugins.baselineprofile)
} }
@@ -79,9 +74,10 @@ android {
flavorDimensions += "api" flavorDimensions += "api"
productFlavors { productFlavors {
create("default") create("default") {
minSdk = 26
}
create("marshmallow") { create("marshmallow") {
minSdk = 23
applicationIdSuffix = ".m" applicationIdSuffix = ".m"
versionNameSuffix = "-M" versionNameSuffix = "-M"
} }
@@ -97,12 +93,6 @@ android {
isCoreLibraryDesugaringEnabled = true isCoreLibraryDesugaringEnabled = true
} }
lint {
checkReleaseBuilds = false
disable += setOf("MissingTranslation", "MissingQuantity")
error += setOf("InlinedApi")
}
packaging { packaging {
dex { dex {
useLegacyPackaging = false useLegacyPackaging = false
@@ -254,39 +244,14 @@ dependencies {
} }
kotlin { kotlin {
jvmToolchain(21)
// https://kotlinlang.org/docs/gradle-compiler-options.html#all-compiler-options
compilerOptions { compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
progressiveMode = true
optIn.addAll( optIn.addAll(
"coil3.annotation.ExperimentalCoilApi", "coil3.annotation.ExperimentalCoilApi",
"androidx.compose.foundation.layout.ExperimentalLayoutApi",
"androidx.compose.material3.ExperimentalMaterial3Api",
"androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"androidx.compose.ui.ExperimentalComposeUiApi",
"androidx.compose.foundation.ExperimentalFoundationApi",
"androidx.compose.animation.ExperimentalAnimationApi",
"androidx.compose.animation.ExperimentalSharedTransitionApi",
"androidx.compose.runtime.ExperimentalComposeRuntimeApi",
"androidx.paging.ExperimentalPagingApi", "androidx.paging.ExperimentalPagingApi",
"kotlin.ExperimentalStdlibApi",
"kotlin.concurrent.atomics.ExperimentalAtomicApi",
"kotlin.contracts.ExperimentalContracts",
"kotlin.time.ExperimentalTime",
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.FlowPreview",
"kotlinx.serialization.ExperimentalSerializationApi", "kotlinx.serialization.ExperimentalSerializationApi",
"splitties.experimental.ExperimentalSplittiesApi", "splitties.experimental.ExperimentalSplittiesApi",
"splitties.preferences.DataStorePreferencesPreview", "splitties.preferences.DataStorePreferencesPreview",
) )
freeCompilerArgs.addAll(
"-Xcontext-parameters",
"-Xwhen-expressions=indy",
"-Xannotation-default-target=param-property",
)
} }
} }
@@ -305,16 +270,3 @@ aboutLibraries {
duplicationRule = DuplicateRule.GROUP duplicationRule = DuplicateRule.GROUP
} }
} }
val ktlintVersion = libs.ktlint.get().version
spotless {
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
-1
View File
@@ -1 +0,0 @@
/build
+43
View File
@@ -0,0 +1,43 @@
plugins {
`kotlin-dsl`
alias(libs.plugins.spotless)
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.spotless.gradlePlugin)
}
gradlePlugin {
plugins {
register("androidApplication") {
id = libs.plugins.ehviewer.android.application.get().pluginId
implementationClass = "AndroidApplicationConventionPlugin"
}
register("multiplatformLibrary") {
id = libs.plugins.ehviewer.multiplatform.library.asProvider().get().pluginId
implementationClass = "MultiplatformLibraryConventionPlugin"
}
register("multiplatformLibraryCompose") {
id = libs.plugins.ehviewer.multiplatform.library.compose.get().pluginId
implementationClass = "MultiplatformLibraryComposeConventionPlugin"
}
}
}
kotlin {
jvmToolchain(21)
}
spotless {
val ktlintVersion = libs.ktlint.get().version
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
@@ -0,0 +1,37 @@
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.Lint
import com.ehviewer.configureKotlin
import com.ehviewer.configureKotlinCompose
import com.ehviewer.configureLint
import com.ehviewer.configureSpotless
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidExtension
@Suppress("unused")
class AndroidApplicationConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply(plugin = libs.findPlugin("kotlin-android").get().get().pluginId)
apply(plugin = libs.findPlugin("android-application").get().get().pluginId)
apply(plugin = libs.findPlugin("compose-compiler").get().get().pluginId)
apply(plugin = libs.findPlugin("composeCompilerReportGenerator").get().get().pluginId)
configure<KotlinAndroidExtension> {
jvmToolchain(21)
compilerOptions {
configureKotlin()
configureKotlinCompose()
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
configure<ApplicationExtension> {
lint(Lint::configureLint)
}
configureSpotless()
}
}
@@ -0,0 +1,23 @@
import com.ehviewer.configureKotlinCompose
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@Suppress("unused")
class MultiplatformLibraryComposeConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply<MultiplatformLibraryConventionPlugin>()
apply(plugin = libs.findPlugin("compose-compiler").get().get().pluginId)
apply(plugin = libs.findPlugin("compose-multiplatform").get().get().pluginId)
apply(plugin = libs.findPlugin("composeCompilerReportGenerator").get().get().pluginId)
configure<KotlinMultiplatformExtension> {
compilerOptions {
configureKotlinCompose()
}
}
}
}
@@ -0,0 +1,66 @@
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import com.android.build.api.dsl.Lint
import com.android.build.api.dsl.androidLibrary
import com.ehviewer.configureKotlin
import com.ehviewer.configureLint
import com.ehviewer.configureSpotless
import com.ehviewer.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@OptIn(ExperimentalKotlinGradlePluginApi::class)
class MultiplatformLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
apply(plugin = libs.findPlugin("kotlin-multiplatform").get().get().pluginId)
apply(plugin = libs.findPlugin("android-kotlin-multiplatform-library").get().get().pluginId)
apply(plugin = libs.findPlugin("android-lint").get().get().pluginId)
configure<KotlinMultiplatformExtension> {
jvmToolchain(21)
compilerOptions {
configureKotlin()
}
applyHierarchyTemplate {
common {
group("jvm") {
withCompilations { it.target is KotlinMultiplatformAndroidLibraryTarget }
withJvm()
}
}
}
// jvm("desktop") {
// compilerOptions {
// jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
// }
// }
androidLibrary {
namespace = "com.ehviewer${path.replace(':', '.')}"
withHostTestBuilder {
}
enableCoreLibraryDesugaring = true
compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
}
configure<Lint>(Lint::configureLint)
configureSpotless()
dependencies {
"coreLibraryDesugaring"(libs.findLibrary("desugar").get())
}
}
}
@@ -0,0 +1,36 @@
package com.ehviewer
import org.gradle.kotlin.dsl.assign
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
// https://kotlinlang.org/docs/gradle-compiler-options.html#all-compiler-options
internal fun KotlinCommonCompilerOptions.configureKotlin() {
progressiveMode = true
optIn.addAll(
"kotlin.ExperimentalStdlibApi",
"kotlin.concurrent.atomics.ExperimentalAtomicApi",
"kotlin.contracts.ExperimentalContracts",
"kotlin.time.ExperimentalTime",
"kotlinx.coroutines.ExperimentalCoroutinesApi",
"kotlinx.coroutines.FlowPreview",
)
freeCompilerArgs.addAll(
"-Xcontext-parameters",
"-Xwhen-expressions=indy",
"-Xannotation-default-target=param-property",
)
}
internal fun KotlinCommonCompilerOptions.configureKotlinCompose() {
optIn.addAll(
"androidx.compose.animation.ExperimentalAnimationApi",
"androidx.compose.animation.ExperimentalSharedTransitionApi",
"androidx.compose.foundation.ExperimentalFoundationApi",
"androidx.compose.foundation.layout.ExperimentalLayoutApi",
"androidx.compose.material3.ExperimentalMaterial3Api",
"androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"androidx.compose.runtime.ExperimentalComposeRuntimeApi",
"androidx.compose.ui.ExperimentalComposeUiApi",
)
}
@@ -0,0 +1,9 @@
package com.ehviewer
import com.android.build.api.dsl.Lint
internal fun Lint.configureLint() {
checkReleaseBuilds = false
disable += setOf("MissingTranslation", "MissingQuantity")
error += setOf("InlinedApi")
}
@@ -0,0 +1,8 @@
package com.ehviewer
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.getByType
internal val Project.libs
get() = extensions.getByType<VersionCatalogsExtension>().named("libs")
@@ -0,0 +1,22 @@
package com.ehviewer
import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
internal fun Project.configureSpotless() {
apply(plugin = libs.findPlugin("spotless").get().get().pluginId)
configure<SpotlessExtension> {
val ktlintVersion = libs.findLibrary("ktlint").get().get().version
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
}
+4
View File
@@ -0,0 +1,4 @@
# Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
+20
View File
@@ -0,0 +1,20 @@
dependencyResolutionManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":convention")
+5 -1
View File
@@ -1,7 +1,11 @@
plugins { plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.kotlin.multiplatform.library) apply false
alias(libs.plugins.android.lint) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.compose.multiplatform) apply false
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.ksp) apply false alias(libs.plugins.ksp) apply false
alias(libs.plugins.spotless) apply false alias(libs.plugins.spotless) apply false
+16 -2
View File
@@ -16,6 +16,7 @@ androidx-work = "2.10.3"
arrow = "2.1.2" arrow = "2.1.2"
coil = "3.3.0" coil = "3.3.0"
compose-bom = "2025.07.01" compose-bom = "2025.07.01"
compose-multiplatform = "1.8.2"
compose-destinations = "2.2.0" compose-destinations = "2.2.0"
compose-preference = "2.1.0" compose-preference = "2.1.0"
kotlin = "2.2.20-Beta2" kotlin = "2.2.20-Beta2"
@@ -27,6 +28,7 @@ ktor = "3.2.3"
okhttp = "5.1.0" okhttp = "5.1.0"
okio = "3.16.0" okio = "3.16.0"
splitties = "3.0.0" splitties = "3.0.0"
spotless = "7.2.1"
telephoto = "0.15.1" telephoto = "0.15.1"
xmlutil = "0.91.2" xmlutil = "0.91.2"
junit = "1.3.0" junit = "1.3.0"
@@ -121,6 +123,10 @@ androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", versi
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" } androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" }
androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "profileinstaller" } androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "profileinstaller" }
android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "agp" }
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
spotless-gradlePlugin = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
[bundles] [bundles]
arrow = ["arrow-fx-coroutines", "arrow-functions", "arrow-resilience"] arrow = ["arrow-fx-coroutines", "arrow-functions", "arrow-resilience"]
coil = ["coil-compose", "coil-gif", "coil-network"] coil = ["coil-compose", "coil-gif", "coil-network"]
@@ -131,11 +137,19 @@ splitties = ["splitties-appctx", "splitties-arch-room", "splitties-preferences",
[plugins] [plugins]
aboutlibrariesPlugin = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" } aboutlibrariesPlugin = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
android-lint = { id = "com.android.lint", version.ref = "agp" }
composeCompilerReportGenerator = { id = "dev.shreyaspatil.compose-compiler-report-generator", version = "1.4.2" } composeCompilerReportGenerator = { id = "dev.shreyaspatil.compose-compiler-report-generator", version = "1.4.2" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
spotless = { id = "com.diffplug.spotless", version = "7.2.1" } spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
android-test = { id = "com.android.test", version.ref = "agp" } android-test = { id = "com.android.test", version.ref = "agp" }
baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" } baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" }
ehviewer-android-application = { id = "ehviewer.android.application" }
ehviewer-multiplatform-library = { id = "ehviewer.multiplatform.library" }
ehviewer-multiplatform-library-compose = { id = "ehviewer.multiplatform.library.compose" }
+3 -2
View File
@@ -1,6 +1,6 @@
pluginManagement { pluginManagement {
includeBuild("build-logic")
repositories { repositories {
gradlePluginPortal()
google { google {
content { content {
includeGroupByRegex("com\\.android.*") includeGroupByRegex("com\\.android.*")
@@ -9,6 +9,7 @@ pluginManagement {
} }
} }
mavenCentral() mavenCentral()
gradlePluginPortal()
} }
} }
@@ -32,7 +33,7 @@ plugins {
android { android {
compileSdk = 36 compileSdk = 36
minSdk = 26 minSdk = 23
targetSdk = 36 targetSdk = 36
ndkVersion = "28.2.13676358" ndkVersion = "28.2.13676358"
buildToolsVersion = "36.0.0" buildToolsVersion = "36.0.0"