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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class GenerateVersionsYaml {
| activity: ${versions.android.activity}
| constraintlayout: ${versions.android.constraintlayout}
| work: ${versions.android.work}
| room: ${versions.android.room}
| roomDatabase: ${versions.android.roomDatabase}
| hilt: ${versions.android.hilt}
| hiltAandroidx: ${versions.android.hiltAandroidx}
| metro: ${versions.android.metro}
Expand Down
16 changes: 11 additions & 5 deletions cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
private val projectName by option()
private val develocityUrl by option()
private val agp9 by option().flag(default = false)
private val roomDatabase by option("--room-database").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).copy(di = dependencyInjection)
val versions = getVersions(versionsFile, develocityUrl, agp9, roomDatabase).copy(di = dependencyInjection)
val develocityEnabled = getDevelocityEnabled(develocity, develocityUrl)
Comment on lines +61 to 69
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--room-database can currently be combined with --di none, but the Room-based generator path produces constructor-injected classes (Repository/UseCase/ViewModel) without providing a way to build them when DI is disabled. This will generate projects that compile but fail at runtime. Consider adding CLI validation to reject --room-database when di == none (or implicitly switch DI to a supported option), unless you also generate the required manual wiring / factories for the NONE case.

Copilot uses AI. Check for mistakes.
ProjectGenerator(
modules,
Expand Down Expand Up @@ -103,24 +104,29 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
}
}

private fun getVersions(fileVersions: File?, develocityUrl: String?, agp9: Boolean): Versions {
private fun getVersions(fileVersions: File?, develocityUrl: String?, agp9: Boolean, roomDatabase: Boolean): Versions {
val versions = if (fileVersions != null) {
parseYaml(fileVersions)
} else {
// We only support the injection of AGP 9 version via CLI with the `agp9` option
// if the version is provided by file this logic is not executed
if (agp9) {
val versions = Versions()
versions.copy(android = Android(agp = versions.android.agp9))
versions.copy(android = versions.android.copy(agp = versions.android.agp9))
} else {
Versions()
}
}
return if (develocityUrl != null) {
versions.copy(project = versions.project.copy(develocityUrl = develocityUrl))
val withRoomDatabase = if (roomDatabase) {
versions.copy(android = versions.android.copy(roomDatabase = true))
} else {
versions
}
return if (develocityUrl != null) {
withRoomDatabase.copy(project = withRoomDatabase.project.copy(develocityUrl = develocityUrl))
} else {
withRoomDatabase
}

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class AndroidApplication {
node: ProjectGraph,
lang: LanguageAttributes,
di: DependencyInjection,
dictionary: MutableMap<String, CopyOnWriteArrayList<GenerateDictionaryAndroid>>
dictionary: MutableMap<String, CopyOnWriteArrayList<GenerateDictionaryAndroid>>,
roomDatabase: Boolean = false
) {
val layerDir = NameMappings.layerName(node.layer)
val moduleDir = NameMappings.moduleName(node.id)
Expand Down Expand Up @@ -86,22 +87,69 @@ class AndroidApplication {
?.firstOrNull { it.type == ClassTypeAndroid.VIEWMODEL }
?.className
?: "Viewmodel${moduleNumber}_1"
"""
|package com.awesomeapp.$packageDir
|
|import android.app.Application
|import dev.zacsweers.metro.DependencyGraph
|import dev.zacsweers.metro.createGraph
|
|@DependencyGraph
|interface AppGraph {
| val viewModel: $viewModel
|}
|
|class MainApplication : Application() {
| val graph: AppGraph by lazy { createGraph() }
|}
""".trimMargin()
if (roomDatabase) {
val databaseClass = dictionary[moduleId]
?.firstOrNull { it.type == ClassTypeAndroid.DATABASE }
?.className
?: "Database${moduleNumber}_1"
val daoClass = dictionary[moduleId]
?.firstOrNull { it.type == ClassTypeAndroid.DAO }
?.className
?: "Dao${moduleNumber}_1"
"""
|package com.awesomeapp.$packageDir
|
|import android.app.Application
|import android.content.Context
|import androidx.room.Room
|import dev.zacsweers.metro.DependencyGraph
|import dev.zacsweers.metro.Provides
|import dev.zacsweers.metro.createGraphFactory
|
|@DependencyGraph
|interface AppGraph {
| val viewModel: $viewModel
|
| @DependencyGraph.Factory
| fun interface Factory {
| fun create(@Provides context: Context): AppGraph
| }
|
| @Provides
| fun provideDatabase(context: Context): $databaseClass {
| return Room.databaseBuilder(context, $databaseClass::class.java, "$moduleId.db")
| .fallbackToDestructiveMigration()
| .build()
| }
|
| @Provides
| fun provideDao(db: $databaseClass): $daoClass {
| return db.dao()
| }
|}
|
|class MainApplication : Application() {
| val graph: AppGraph by lazy { createGraphFactory<AppGraph.Factory>().create(this) }
|}
""".trimMargin()
} else {
"""
|package com.awesomeapp.$packageDir
|
|import android.app.Application
|import dev.zacsweers.metro.DependencyGraph
|import dev.zacsweers.metro.createGraph
|
|@DependencyGraph
|interface AppGraph {
| val viewModel: $viewModel
|}
|
|class MainApplication : Application() {
| val graph: AppGraph by lazy { createGraph() }
|}
""".trimMargin()
}
}

DependencyInjection.NONE -> """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class BuildFilesGeneratorAndroid(
}
}

val deps = AndroidToml().tomlImplementations(versions, di)
val deps = AndroidToml().tomlImplementations(versions, di, versions.android.roomDatabase)
return """
|plugins {
| id("awesome.androidapp.plugin")
Expand All @@ -59,7 +59,7 @@ ${testImplementations.joinToString("\n").prependIndent(" ")}
private fun createAndroidLibBuildFile(node: ProjectGraph, generateUnitTests: Boolean): String {
val implementations = mutableSetOf<String>()
val testImplementations = mutableSetOf<String>()
val deps = AndroidToml().tomlImplementations(versions, di)
val deps = AndroidToml().tomlImplementations(versions, di, versions.android.roomDatabase)
// Add direct dependencies first (only from different layers)
node.nodes.forEach { dependency ->
if (dependency.layer != node.layer) {
Expand Down
Loading