How do you declare multiple dependencies on a single task, and how would you build a custom lifecycle aggregate task using dependsOn?
answer
- dependsOn is additive, returns a Set
- varargs / collection / repeated calls
- aggregate = empty task + edges
- attach to check via tasks.named
- no order among siblings
basics
~20 sPass several arguments to one dependsOn call, call dependsOn multiple times, or pass a collection — dependencies accumulate. A custom aggregate is an empty task that dependsOn the real tasks, grouping them under one command.
solid answer
~40 s`dependsOn` is **additive**: every call adds to the task's dependency set rather than replacing it. So `dependsOn("a", "b")` plus a later `dependsOn("c")` yields all three. You can also pass a `Collection` or array. To build a **custom lifecycle/aggregate task**, register a task with no action and point its `dependsOn` at the real work — exactly how Gradle's own `build`/`check`/`assemble` are defined. For example a `qualityGate` task depending on `test`, `detekt`, and `ktlintCheck` lets a developer run `./gradlew qualityGate` to trigger all three; Gradle de-duplicates shared transitive dependencies so each task still runs at most once. Order among the aggregate's direct dependencies is not guaranteed unless you add explicit ordering edges.
code
kotlin · 6 linestasks.register("ci") {
group = "build"
dependsOn("build", "javadoc")
}
tasks.register("ci") // would clash; instead extend existing:
tasks.named("check") { dependsOn("integrationTest") }go deeper
Show that you can list several dependencies and that an aggregate task groups them.
Explain accumulation/set semantics, de-duplication, and building/attaching to lifecycle tasks like check.
Discuss plugin integration patterns (appending to check) and the ordering caveat among siblings.
Define team conventions for custom lifecycle tasks and how verification tools should integrate into the standard graph.
## Declaring multiple dependencies There are three equivalent styles, and they **accumulate** (never overwrite): ```kotlin tasks.register("publishAll") { dependsOn("publishApi", "publishDocs") // varargs dependsOn(listOf(jarTask, sourcesJarTask)) // collection dependsOn("signArtifacts") // another call, adds on } ``` The underlying `getDependsOn()` returns a mutable `Set`, so duplicates collapse and there is no positional meaning. ## Building a custom aggregate (lifecycle) task Gradle's lifecycle tasks are just **empty tasks** that aggregate others. You make your own the same way: ```kotlin tasks.register("qualityGate") { group = "verification" description = "Runs all static analysis and tests" dependsOn("test", "detekt", "ktlintCheck") } ``` Now `./gradlew qualityGate` schedules all three. Because they share no action of the gate task itself, the gate contributes nothing but the edges. If two of the dependencies share a transitive dependency (say all depend on `compileKotlin`), Gradle includes `compileKotlin` **once** — the DAG de-duplicates nodes. ## Hooking into existing lifecycle tasks Instead of inventing a new command, you often attach to an existing one so your work runs as part of a standard flow: ```kotlin tasks.named("check") { dependsOn("qualityGate") // make ./gradlew check include the gate } ``` This is the idiomatic way plugins integrate: the Java plugin's `check` already `dependsOn(test)`, and additional verification tools append themselves to `check`. ## Ordering caveat `dependsOn` guarantees each dependency runs before the aggregate, but says **nothing** about the order *among* the dependencies. If `detekt` must precede `test`, a plain aggregate won't enforce that; you'd need an explicit ordering relationship between those two. Treat the aggregate purely as "include and run all of these first."
- If an aggregate's two dependencies both transitively depend on compileJava, does compileJava run twice?No. The task graph is a set of nodes; compileJava appears once and runs at most once per build invocation.
- Does dependsOn guarantee the order in which an aggregate's direct dependencies run?No. dependsOn only guarantees they all run before the aggregate. Relative order among them is unspecified unless you add explicit ordering edges between those tasks.
saying these in an interview costs you the question
- Believing a second dependsOn call replaces the first — it accumulates into a set.
- Assuming dependsOn imposes order among the listed dependencies.