Inside whenReady, how do you inspect what the build is about to do using allTasks and hasTask, and what do they return?
answer
- allTasks = ordered List<Task>, full closure
- hasTask(path) / hasTask(task) -> Boolean
- execution order, dependencies first
- transitive, not just requested
- fail-fast on bad combinations
basics
~10 sgraph.allTasks returns the ordered list of every Task that will execute; graph.hasTask checks whether a specific task (by path or instance) is in the graph. Both reflect the fully built graph.
solid answer
~40 sInside `whenReady { graph -> }` the `graph` is a `TaskExecutionGraph`. `graph.allTasks` returns a `List<Task>` of all tasks scheduled for execution, in execution order (dependencies before dependents). `graph.hasTask(path)` and `graph.hasTask(task)` return a `Boolean` indicating membership. Because the graph is already complete, these reflect not just the tasks you requested on the command line but their full transitive dependency closure — so requesting `:app:publish` may make `hasTask(":app:compileJava")` true. Typical uses: branch on whether a release/publish task is present, count work for logging, or scan `allTasks` to detect an incompatible combination and `throw GradleException(...)` to fail before execution. Calling these during configuration would be wrong because the graph isn't populated yet.
code
kotlin · 8 linesgradle.taskGraph.whenReady { graph ->
if (graph.hasTask(":app:publish")) {
require(System.getenv("OSSRH_TOKEN") != null) {
"Publishing requested but OSSRH_TOKEN is missing"
}
}
println("Plan: " + graph.allTasks.joinToString { it.path })
}go deeper
Recall that allTasks lists what will run and hasTask checks for a specific task.
Stress that both reflect the transitive closure and execution order, and use hasTask with full paths.
Use these for fail-fast validation and explain why mutation this late is discouraged.
Weigh lifecycle-callback inspection against lazy Provider wiring and configuration-cache compatibility for build-logic governance.
## The TaskExecutionGraph read surface When `whenReady` (or `addTaskExecutionGraphListener`) fires, you hold a fully populated `TaskExecutionGraph`. Its two most-used read methods: ### allTasks ```kotlin val tasks: List<Task> = graph.allTasks ``` Returns **every** task that Gradle will execute for this invocation, in **execution order** (a topological order where each task appears after its dependencies). This is the transitive closure — requested tasks **plus** everything they depend on — not just the command-line list. ### hasTask ```kotlin graph.hasTask(":app:publish") // by path (String) graph.hasTask(publishTaskRef) // by Task instance ``` Returns a `Boolean`. Membership again reflects the full closure: a task you never named can be present because something you named depends on it. ## Why this is powerful at this point Graph membership answers questions you cannot answer earlier: - *Is this a release build?* → `graph.hasTask(":app:release")` - *Will we publish?* → check for any `*publish*` task in `allTasks`. - *Are two mutually-exclusive tasks both requested?* → scan and fail fast. ## Fail-fast pattern ```kotlin gradle.taskGraph.whenReady { graph -> val names = graph.allTasks.map { it.name } if ("clean" in names && "build" in names && names.indexOf("build") < names.indexOf("clean")) { throw GradleException("'build' is scheduled before 'clean' — check ordering") } } ``` ## Gotchas - `hasTask(String)` expects a **task path** (e.g. `:app:test`), not a bare name in a multi-project build. - The list is a snapshot of the plan; reacting here is fine, but mutating task dependencies this late is discouraged because the graph is already finalized. - Under the configuration cache, prefer modeling such decisions via lazy `Provider`/`Property` wiring where possible, since lifecycle callbacks interact with caching constraints.
- If I request only :app:assemble, will hasTask(":app:compileJava") be true?Yes, if assemble transitively depends on compileJava. allTasks/hasTask reflect the full dependency closure, not just the command-line tasks.
- What does hasTask expect as its String argument in a multi-project build?A fully qualified task path like :app:test, not a bare task name, otherwise it may not match the intended task.
- Is allTasks ordered?Yes — it's in execution order, a topological order where each task follows its dependencies.
saying these in an interview costs you the question
- Thinking allTasks contains only the tasks named on the command line.
- Passing a bare task name to hasTask in a multi-project build and expecting a match.
- Trying to add new task dependencies inside whenReady — the graph is already finalized.