diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 7fc278c..ae7ebc5 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -5,9 +5,10 @@ plugins { group = "de.ahlfeld.bitriseartifacts.buildlogic" dependencies { - compileOnly(libs.android.gradlePlugin) - compileOnly(libs.kotlin.gradlePlugin) - compileOnly(libs.compose.gradlePlugin) + implementation(libs.android.gradlePlugin) + implementation(libs.kotlin.gradlePlugin) + implementation(libs.kotlin.serialization.gradlePlugin) + implementation(libs.compose.gradlePlugin) } gradlePlugin { @@ -24,5 +25,9 @@ gradlePlugin { id = "bitriseartifacts.koin" implementationClass = "KoinConventionPlugin" } + register("feature") { + id = "bitriseartifacts.feature" + implementationClass = "FeatureConventionPlugin" + } } } diff --git a/build-logic/convention/src/main/kotlin/FeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/FeatureConventionPlugin.kt new file mode 100644 index 0000000..1f76487 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/FeatureConventionPlugin.kt @@ -0,0 +1,20 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +class FeatureConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + configureKotlinMultiplatform() + + extensions.configure { + with(sourceSets) { + commonMain.dependencies { + implementation(libs.jetbrains.navigation.compose) + } + } + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryConvention.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConvention.kt new file mode 100644 index 0000000..8699e26 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KmpLibraryConvention.kt @@ -0,0 +1,59 @@ +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget +import org.gradle.api.Project +import org.gradle.api.tasks.testing.AbstractTestTask +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +internal fun Project.configureKotlinMultiplatform() { + apply(plugin = libs.plugins.kotlinMultiplatform.get().pluginId) + apply(plugin = libs.plugins.androidKmpLibraryPluging.get().pluginId) + apply(plugin = libs.plugins.kotlinSerialization.get().pluginId) + + + extensions.configure { + androidLibrary { + namespace = project.toNamespace() + compileSdk = libs.versions.android.compileSdk.get().toInt() + minSdk = libs.versions.android.minSdk.get().toInt() + compilerOptions.jvmTarget.set(JvmTarget.JVM_17) + + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + + withHostTestBuilder {}.configure { + enableCoverage = true + } + } + + jvm() + iosArm64() + iosSimulatorArm64() + + with(sourceSets) { + commonMain.dependencies { + implementation(libs.kotlinx.coroutines.core) + } + commonTest.dependencies { + implementation(libs.kotlin.test) + implementation(libs.kotlinx.coroutines.test) + } + } + + tasks.withType().configureEach { + failOnNoDiscoveredTests.set(false) + } + configureKotlin() + } +} + +internal fun KotlinMultiplatformExtension.androidLibrary( + block: KotlinMultiplatformAndroidLibraryTarget.() -> Unit +) { + configure(block) +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/KotlinConvention.kt b/build-logic/convention/src/main/kotlin/KotlinConvention.kt new file mode 100644 index 0000000..953c09f --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KotlinConvention.kt @@ -0,0 +1,37 @@ +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask + +/** + * Configure base Kotlin options for JVM (non-Android) + */ +internal fun Project.configureKotlinJvm() { + configureKotlin() +} + +/** + * Configure base Kotlin options + */ +internal fun Project.configureKotlin() { + extensions.configure { + jvmToolchain(17) + } + + tasks.withType>().configureEach { + compilerOptions { + freeCompilerArgs.addAll( + listOf( + "-Xinline-classes", + "-opt-in=kotlin.RequiresOptIn", + "-Xjvm-default=all" + ) + ) + + if (name.contains("test", ignoreCase = true)) { + freeCompilerArgs.add("-java-parameters") + } + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/KtorConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KtorConventionPlugin.kt index d3255b0..ab3ed52 100644 --- a/build-logic/convention/src/main/kotlin/KtorConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KtorConventionPlugin.kt @@ -8,17 +8,19 @@ class KtorConventionPlugin : Plugin { with(target) { extensions.configure { - sourceSets.getByName("androidMain").dependencies { - implementation(project.libs.ktor.client.okhttp) - } - sourceSets.getByName("commonMain").dependencies { - api(project.libs.ktor.client.core) - implementation(project.libs.ktor.client.logging) - implementation(project.libs.ktor.client.content.negotiation) - implementation(project.libs.ktor.serialization.json) - } - sourceSets.getByName("commonTest").dependencies { - implementation(project.libs.ktor.client.mock) + with(sourceSets) { + androidMain.dependencies { + implementation(project.libs.ktor.client.okhttp) + } + commonMain.dependencies { + implementation(project.libs.ktor.client.core) + implementation(project.libs.ktor.client.logging) + implementation(project.libs.ktor.client.content.negotiation) + implementation(project.libs.ktor.serialization.json) + } + commonTest.dependencies { + implementation(project.libs.ktor.client.mock) + } } } } diff --git a/build-logic/convention/src/main/kotlin/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/ProjectExtensions.kt new file mode 100644 index 0000000..196e4f0 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/ProjectExtensions.kt @@ -0,0 +1,12 @@ +import org.gradle.api.Project + +private val PATH_DELIMITERS = arrayOf(":", "-") +private const val NAMESPACE_DELIMITER = "." +private const val NAMESPACE = "de.ahlfeld.bitrise.%s" + +fun Project.toNamespace(): String { + val name = path.split(delimiters = PATH_DELIMITERS) + .joinToString(NAMESPACE_DELIMITER) + + return NAMESPACE.format(name) +} \ No newline at end of file diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index 4db1336..1e1ec77 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -1,18 +1,20 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + } +} + dependencyResolutionManagement { repositories { google() mavenCentral() gradlePluginPortal() } - versionCatalogs { - create("libs") { - from(files("../gradle/libs.versions.toml")) - } - } } plugins { - id("dev.panuszewski.typesafe-conventions") version "0.10.0" + id("dev.panuszewski.typesafe-conventions") version "0.10.1" } rootProject.name = "build-logic" diff --git a/feature-apps-api/build.gradle.kts b/feature-apps-api/build.gradle.kts index 890f5de..9c8e18e 100644 --- a/feature-apps-api/build.gradle.kts +++ b/feature-apps-api/build.gradle.kts @@ -9,6 +9,7 @@ plugins { kotlin { listOf( + iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> diff --git a/feature-apps/build.gradle.kts b/feature-apps/build.gradle.kts index e1b19d8..40eda0f 100644 --- a/feature-apps/build.gradle.kts +++ b/feature-apps/build.gradle.kts @@ -1,13 +1,8 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidKmpLibraryPluging) - alias(libs.plugins.kotlinSerialization) - alias(libs.plugins.bitrise.kmp.network) - alias(libs.plugins.bitrise.kmp.compose) - alias(libs.plugins.bitrise.kmp.koin) + id("bitriseartifacts.feature") + id("bitriseartifacts.koin") + id("bitriseartifacts.ktor") + id("bitriseartifacts.compose.multiplatform") } kotlin { @@ -21,36 +16,20 @@ kotlin { } } - jvm() - android { namespace = "de.ahlfeld.bitriseartifacts.apps" - compileSdk = libs.versions.android.compileSdk.get().toInt() - minSdk = libs.versions.android.minSdk.get().toInt() - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } - androidResources { enable = true } } sourceSets { - commonTest.dependencies { - implementation(libs.kotlin.test) - implementation(libs.kotlinx.coroutines.test) - } commonMain.dependencies { implementation(projects.featureAppsApi) implementation(projects.featureAuthApi) implementation(projects.featureBuildsApi) - implementation(libs.kotlinx.coroutines.core) implementation(libs.coil.compose) implementation(libs.coil.network.ktor) - implementation(libs.jetbrains.navigation.compose) } } } diff --git a/feature-artifact-detail/build.gradle.kts b/feature-artifact-detail/build.gradle.kts index 2cee3aa..4a3b6ba 100644 --- a/feature-artifact-detail/build.gradle.kts +++ b/feature-artifact-detail/build.gradle.kts @@ -1,13 +1,8 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidKmpLibraryPluging) - alias(libs.plugins.bitrise.kmp.network) - alias(libs.plugins.kotlinSerialization) - alias(libs.plugins.bitrise.kmp.compose) - alias(libs.plugins.bitrise.kmp.koin) + id("bitriseartifacts.feature") + id("bitriseartifacts.koin") + id("bitriseartifacts.ktor") + id("bitriseartifacts.compose.multiplatform") } kotlin { @@ -21,17 +16,8 @@ kotlin { } } - jvm() - android { namespace = "de.ahlfeld.bitriseartifacts.artifact_detail" - compileSdk = libs.versions.android.compileSdk.get().toInt() - minSdk = libs.versions.android.minSdk.get().toInt() - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } } sourceSets { @@ -41,15 +27,7 @@ kotlin { commonMain.dependencies { implementation(projects.featureArtifactDetailApi) implementation(projects.featureArtifactsApi) - implementation(libs.kotlinx.coroutines.core) implementation(libs.compose.material.icons.extended) - implementation(libs.koin.core) - implementation(libs.jetbrains.navigation.compose) - } - commonTest.dependencies { - implementation(libs.kotlin.test) - implementation(libs.kotlinx.coroutines.test) } } } - diff --git a/feature-artifacts/build.gradle.kts b/feature-artifacts/build.gradle.kts index 9ea9da3..d247314 100644 --- a/feature-artifacts/build.gradle.kts +++ b/feature-artifacts/build.gradle.kts @@ -1,12 +1,7 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidKmpLibraryPluging) - alias(libs.plugins.kotlinSerialization) - alias(libs.plugins.bitrise.kmp.network) - alias(libs.plugins.bitrise.kmp.koin) + id("bitriseartifacts.feature") + id("bitriseartifacts.ktor") + id("bitriseartifacts.koin") } kotlin { @@ -20,27 +15,15 @@ kotlin { } } - jvm() - android { namespace = "de.ahlfeld.bitriseartifacts.artifacts" - compileSdk = libs.versions.android.compileSdk.get().toInt() - minSdk = libs.versions.android.minSdk.get().toInt() - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } } sourceSets { commonMain.dependencies { implementation(projects.featureArtifactsApi) - implementation(libs.kotlinx.coroutines.core) } commonTest.dependencies { - implementation(libs.kotlin.test) - implementation(libs.kotlinx.coroutines.test) implementation(libs.ktor.client.mock) } } diff --git a/feature-auth-api/build.gradle.kts b/feature-auth-api/build.gradle.kts index aae8638..ec1e6a0 100644 --- a/feature-auth-api/build.gradle.kts +++ b/feature-auth-api/build.gradle.kts @@ -8,6 +8,7 @@ plugins { kotlin { listOf( + iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> diff --git a/feature-auth/build.gradle.kts b/feature-auth/build.gradle.kts index 809ff06..ed2154b 100644 --- a/feature-auth/build.gradle.kts +++ b/feature-auth/build.gradle.kts @@ -1,11 +1,7 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidKmpLibraryPluging) - alias(libs.plugins.bitrise.kmp.compose) - alias(libs.plugins.bitrise.kmp.koin) + id("bitriseartifacts.feature") + id("bitriseartifacts.compose.multiplatform") + id("bitriseartifacts.koin") } kotlin { @@ -19,29 +15,15 @@ kotlin { } } - jvm() - android { namespace = "de.ahlfeld.bitriseartifacts.feature.auth" - compileSdk = libs.versions.android.compileSdk.get().toInt() - minSdk = libs.versions.android.minSdk.get().toInt() - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } } sourceSets { commonMain.dependencies { implementation(projects.featureAuthApi) - implementation(libs.kotlinx.coroutines.core) implementation(libs.datastore.preferences.core) } - commonTest.dependencies { - implementation(libs.kotlin.test) - implementation(libs.kotlinx.coroutines.test) - } androidMain.dependencies { implementation(libs.datastore.preferences.android) } diff --git a/feature-builds/build.gradle.kts b/feature-builds/build.gradle.kts index 91894c1..045d9c2 100644 --- a/feature-builds/build.gradle.kts +++ b/feature-builds/build.gradle.kts @@ -1,13 +1,8 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidKmpLibraryPluging) - alias(libs.plugins.kotlinSerialization) - alias(libs.plugins.bitrise.kmp.network) - alias(libs.plugins.bitrise.kmp.compose) - alias(libs.plugins.bitrise.kmp.koin) + id("bitriseartifacts.feature") + id("bitriseartifacts.koin") + id("bitriseartifacts.ktor") + id("bitriseartifacts.compose.multiplatform") } kotlin { @@ -21,35 +16,19 @@ kotlin { } } - jvm() - android { namespace = "de.ahlfeld.bitriseartifacts.builds" - compileSdk = libs.versions.android.compileSdk.get().toInt() - minSdk = libs.versions.android.minSdk.get().toInt() - - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) - } - androidResources { enable = true } } sourceSets { - commonTest.dependencies { - implementation(libs.kotlin.test) - implementation(libs.kotlinx.coroutines.test) - } commonMain.dependencies { implementation(projects.featureBuildsApi) implementation(projects.featureArtifactsApi) implementation(projects.featureArtifactDetailApi) - implementation(libs.kotlinx.coroutines.core) implementation(libs.compose.material.icons.extended) - implementation(libs.jetbrains.navigation.compose) } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5610de..7ea6493 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,24 +1,24 @@ [versions] -agp = "9.1.0" +agp = "9.1.1" android-compileSdk = "36" android-minSdk = "30" android-targetSdk = "36" datastore = "1.2.1" androidx-activity = "1.13.0" androidx-browser = "1.10.0" -androidx-compose-ui-tooling = "1.10.6" +androidx-compose-ui-tooling = "1.11.0" androidx-lifecycle = "2.10.0" composeMultiplatform = "1.10.3" composeIcons = "1.7.3" kotlin = "2.3.20" kotlinx-coroutines = "1.10.2" -kotlinx-serialization = "1.10.0" +kotlinx-serialization = "1.11.0" material3 = "1.10.0-alpha05" # Frameworks coil = "3.4.0" -koin = "4.2.0" -ktor = "3.4.2" +koin = "4.2.1" +ktor = "3.4.3" navigation = "2.9.2" [libraries] @@ -80,6 +80,7 @@ coil-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.re # Gradle Plugins (for Convention Plugins) android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } +kotlin-serialization-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-serialization", version.ref = "kotlin" } compose-gradlePlugin = { group = "org.jetbrains.compose", name = "compose-gradle-plugin", version.ref = "composeMultiplatform" } [plugins] @@ -93,6 +94,7 @@ kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", versio # KMP Plugins +bitrise-kmp-feature = { id = "bitriseartifacts.feature" } bitrise-kmp-network = { id = "bitriseartifacts.ktor" } bitrise-kmp-compose = { id = "bitriseartifacts.compose.multiplatform" } bitrise-kmp-koin = { id = "bitriseartifacts.koin" }