Putting this here to be shot at... I have tasks t...
# community-support
r
Putting this here to be shot at... I have tasks that generate sources in a multi-project build. Interested in thoughts on this structure: (code in 🧵)
Root `build.gradle.kts`:
Copy code
plugins {
  base
  alias(libs.plugins.idea.ext)
}

val generateSources by tasks.registering {}

idea {
  idea.project.settings {
    taskTriggers {
      afterSync(generateSources)
    }
  }
}
`buildlogic.kotlin-common-conventions.gradle.kts`:
Copy code
val generateSources by tasks.registering {}

rootProject.tasks.findByName("generateSources")?.dependsOn(generateSources)

tasks.classes {
  dependsOn(generateSources)
}
Sub project `build.gradle.kts`:
Copy code
plugins {
  id("buildlogic.kotlin-common-conventions")
}
val templateKotlin by tasks.registering(Sync::class) {
  // generation stuff
}
tasks.generateSources { dependsOn(templateKotlin) }
Does this seem sound / sensible? General idea is that whenever you have a task that does generation you add
tasks.generateSources { dependsOn(newTask) }
.
(The creation of a task on the root project and linking each sub projects task to it seems unncessary except that the idea ext
afterSync(taskName)
call seems to need it - I can do
./gradlew generateSources
, but
afterSync("generateSources")
throws an NPE if the task does not exist explicitly on the root project.)
Actually I'm thinking the
Copy code
tasks.classes {
  dependsOn(generateSources)
}
may be unnecessary, it isn't needed by the idea
afterSync
.
v
Basically it is imho fine and also what I do, just some detail points: • cross-project configuring the root project's task with a dependency is bad • also by using
findByName
you break task configuration avoidance and it also only works if that task is registered already • what I do is to have a
generate
task (like your
generateSources
, but could also depend on resource generation and so on) in each and every project, no matter whether is has actual generation or not and then use
val generate by tasks.registering { dependsOn(project.subprojects.map { "${it.path}:generate" }) }
in the root project. • As you already said, making
classes
depend on the source generation does not make much sense to me, and also is the wrong semantic. That lifecycle task should depend on tasks that produce class files, not source files. The source generation tasks should be registered as source dirs for the respective source sets. By that the source generation is automatically run when the sources are needed. This includes the compilation tasks, which then already makes
classes
implicitly depend on the source generation.
r
Cool, thanks. Is this OK in the root project?
Copy code
val generate by tasks.registering {
  dependsOn(project.subprojects.map { it.tasks.named("generateSources") })
}
v
No, you don't cross-configure, but you still access the model of the other project, which is also bad and would also require that the task is already registered when executing that. Thus the string-y dependency in my code line. The project name is fine, it is defined in the settings script already and cannot change any further, and the string-y dependency is resolved to a task instance late by Gradle.
👍 1