Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
implementation(libs.jackson.dataformat.yaml)
testImplementation(platform(libs.junit.bom))
testImplementation(libs.junit.jupiter)
testRuntimeOnly(libs.junit.platform.launcher)
}

tasks.test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class GenerateVersionsYaml {
| work: ${versions.android.work}
| room: ${versions.android.room}
| roomDatabase: ${versions.android.roomDatabase}
| kotlinMultiplatformLibrary: ${versions.android.kotlinMultiplatformLibrary}
| hilt: ${versions.android.hilt}
| hiltAandroidx: ${versions.android.hiltAandroidx}
| metro: ${versions.android.metro}
Expand Down
36 changes: 28 additions & 8 deletions cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.readValue
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.UsageError
import com.github.ajalt.clikt.core.main
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.options.*
Expand Down Expand Up @@ -59,13 +60,23 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
private val develocityUrl by option()
private val agp9 by option().flag(default = false)
private val roomDatabase by option("--room-database").flag(default = false)
private val kotlinMultiplatformLibrary by option("--android-kotlin-multiplatform-library").flag(default = false)


override fun run() {
val typeOfProjectRequested = TypeProjectRequested.valueOf(type.uppercase())
val shape = Shape.valueOf(shape.uppercase())
val dependencyInjection = DependencyInjection.valueOf(di.uppercase())
val versions = getVersions(versionsFile, develocityUrl, agp9, roomDatabase).copy(di = dependencyInjection)
if (typeOfProjectRequested != TypeProjectRequested.ANDROID && kotlinMultiplatformLibrary) {
throw UsageError("--android-kotlin-multiplatform-library is only available when --type android.")
}
val versions = getVersions(
fileVersions = versionsFile,
develocityUrl = develocityUrl,
agp9 = agp9,
roomDatabase = roomDatabase,
kotlinMultiplatformLibrary = kotlinMultiplatformLibrary
).copy(di = dependencyInjection)
val develocityEnabled = getDevelocityEnabled(develocity, develocityUrl)
ProjectGenerator(
modules,
Expand Down Expand Up @@ -104,7 +115,13 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
}
}

private fun getVersions(fileVersions: File?, develocityUrl: String?, agp9: Boolean, roomDatabase: Boolean): Versions {
private fun getVersions(
fileVersions: File?,
develocityUrl: String?,
agp9: Boolean,
roomDatabase: Boolean,
kotlinMultiplatformLibrary: Boolean
): Versions {
val versions = if (fileVersions != null) {
parseYaml(fileVersions)
} else {
Expand All @@ -117,15 +134,18 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
Versions()
}
}
val withRoomDatabase = if (roomDatabase) {
versions.copy(android = versions.android.copy(roomDatabase = true))
} else {
versions
var androidConfig = versions.android
if (roomDatabase) {
androidConfig = androidConfig.copy(roomDatabase = true)
}
if (kotlinMultiplatformLibrary) {
androidConfig = androidConfig.copy(kotlinMultiplatformLibrary = true)
}
val withAndroidFlags = versions.copy(android = androidConfig)
return if (develocityUrl != null) {
withRoomDatabase.copy(project = withRoomDatabase.project.copy(develocityUrl = develocityUrl))
withAndroidFlags.copy(project = withAndroidFlags.project.copy(develocityUrl = develocityUrl))
} else {
withRoomDatabase
withAndroidFlags
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.cdsap.projectgenerator.cli

import com.github.ajalt.clikt.core.UsageError
import com.github.ajalt.clikt.core.parse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class GenerateProjectsCliTest {

@Test
fun `android kotlin multiplatform library flag is rejected for jvm type`() {
val error = assertThrows<UsageError> {
GenerateProjects().parse(
listOf(
"--modules", "6",
"--type", "jvm",
"--android-kotlin-multiplatform-library"
)
)
}
assertTrue(
error.message?.contains("--android-kotlin-multiplatform-library is only available when --type android.") == true
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class CompositeBuildPluginAndroidLib {
| override fun apply(target: Project) {
| with(target) {
| with(pluginManager) {
| apply("com.android.library")
| apply("${androidLibraryPluginId(versions)}")
| ${provideKgpBasedOnAgp(versions)}
| ${provideKotlinProcessor(versions,di)}
| ${applyDiPlugin(di)}
Expand Down Expand Up @@ -85,4 +85,12 @@ class CompositeBuildPluginAndroidLib {
DependencyInjection.NONE -> """"""
}
}

private fun androidLibraryPluginId(versions: Versions): String {
return if (versions.android.kotlinMultiplatformLibrary) {
"com.android.kotlin.multiplatform.library"
} else {
"com.android.library"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class BuildGradle {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
${androidLibraryRootPlugin(versions)}
${provideKotlinProcessor(versions)}
${diPlugins(di)}
${additionalBuildGradlePlugins(versions)}
Expand Down Expand Up @@ -48,4 +48,12 @@ class BuildGradle {
return additionalPlugins
}

private fun androidLibraryRootPlugin(versions: Versions): String {
return if (versions.android.kotlinMultiplatformLibrary) {
"alias(libs.plugins.android.kotlin.multiplatform.library) apply false"
} else {
"alias(libs.plugins.android.library) apply false"
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class AndroidToml {
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
${hiltPlugin(version.di)}
${metroPlugin(version.di)}
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ data class Android(
val work: String = "2.11.1",
val room: String = "2.8.4",
val roomDatabase: Boolean = false,
val kotlinMultiplatformLibrary: Boolean = false,
val hilt: String = "2.59.1",
val hiltAandroidx: String = "1.3.0",
val metro: String = "0.10.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.github.cdsap.projectgenerator.generator.includedbuild.CompositeBuildSe
import io.github.cdsap.projectgenerator.generator.plugins.android.CompositeBuildPluginAndroidApp
import io.github.cdsap.projectgenerator.generator.plugins.android.CompositeBuildPluginAndroidLib
import io.github.cdsap.projectgenerator.generator.plugins.jvm.CompositeBuildJvmLib
import io.github.cdsap.projectgenerator.model.Android
import io.github.cdsap.projectgenerator.model.LanguageAttributes
import io.github.cdsap.projectgenerator.model.TypeProjectRequested
import io.github.cdsap.projectgenerator.model.Versions
Expand Down Expand Up @@ -104,6 +105,27 @@ class ConventionPluginWriterTest {
assertEquals(0, tempDir.listFiles()?.size ?: 0, "Temp directory should be empty")
}

@Test
fun `write should use android kotlin multiplatform library plugin when enabled`() {
val projectName = "androidKmpLib"
val language = LanguageAttributes(projectName = "${tempDir.path}/$projectName", extension = "gradle.kts")
val versions = Versions(android = Android(kotlinMultiplatformLibrary = true))
val writer = ConventionPluginWriter(
languages = listOf(language),
versions = versions,
requested = TypeProjectRequested.ANDROID
)

writer.write()

val libPluginFile = File("${language.projectName}/build-logic/convention/src/main/kotlin/com/logic/CompositeBuildPluginAndroidLib.kt")
assertTrue(libPluginFile.exists(), "Lib plugin missing for ${language.projectName}")
assertTrue(
libPluginFile.readText().contains("apply(\"com.android.kotlin.multiplatform.library\")"),
"Expected KMP Android library plugin application in lib convention plugin"
)
}

private fun assertAndroidConventionFilesExist(projectBasePath: String, versions: Versions) {
val conventionSrcDir = File("$projectBasePath/build-logic/convention/src/main/kotlin/com/logic")
assertTrue(conventionSrcDir.exists() && conventionSrcDir.isDirectory, "Convention src dir missing for $projectBasePath")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,29 @@ class ProjectWriterTest {
assertTrue(content.contains("Room.databaseBuilder"))
assertTrue(content.contains("by viewModels { viewModelFactory }"))
}

@Test
fun `uses android kotlin multiplatform library root plugin alias when enabled`() {
val node = ProjectGraph("module_1_1", 1, emptyList(), TypeProject.ANDROID_LIB, 10)
val language = LanguageAttributes("gradle.kts", "${tempDir}/project_kts_kmp")
val versions = Versions(android = Android(kotlinMultiplatformLibrary = true))
val projectWriter = ProjectWriter(
listOf(node),
listOf(language),
versions,
TypeProjectRequested.ANDROID,
TypeOfStringResources.NORMAL,
false,
GradleWrapper(Gradle.GRADLE_9_3_0),
false,
"kmp_android_lib_alias"
)

projectWriter.write()

val rootBuild = File("${language.projectName}/build.gradle.kts")
assertTrue(rootBuild.exists(), "Expected root build.gradle.kts to exist")
val content = rootBuild.readText()
assertTrue(content.contains("alias(libs.plugins.android.kotlin.multiplatform.library) apply false"))
}
}