A teammate adds `release.mustRunAfter(build)` expecting that running `gradle release` will now also build. Why doesn't it, and what should they do instead?
answer
- ordering = order, not inclusion
- membership vs order are separate
- mustRunAfter won't pull build in
- fix: dependsOn OR request both
- must run before always => dependency
basics
~10 smustRunAfter only orders tasks that are already scheduled; it never adds build to the graph. Running gradle release alone won't build. They need a real dependency (release.dependsOn(build)) or to request both tasks.
solid answer
~40 sOrdering rules are purely about *sequence*, not *inclusion*. `release.mustRunAfter(build)` says "if both `release` and `build` are in this build, run `build` first" — but it does nothing to put `build` into the graph. So `gradle release` runs `release` alone, and the rule is inert. To actually build before releasing, the teammate has two correct options: 1. **Declare a dependency:** `tasks.named("release") { dependsOn("build") }`. This both pulls `build` into the graph and orders it first. 2. **Request both explicitly:** `gradle build release`. Now both are scheduled, and the existing `mustRunAfter` will order them correctly. The common confusion is treating ordering rules as a lightweight dependency. They are not — they are a *conditional sequencing* mechanism that assumes the other task's presence is handled elsewhere.
code
bash · 8 lines# Ordering rule inert — build is not scheduled:
gradle release # runs release only
# Works because both are requested:
gradle build release # build first (mustRunAfter honored), then release
# Or change the rule to a dependency so this always builds first:
# tasks.named("release") { dependsOn("build") }go deeper
Recognize that the predecessor must already be scheduled for an ordering rule to do anything.
Diagnose the bug, separate 'membership' from 'order', and propose both fixes with their tradeoffs.
Advise when to keep the decoupled ordering design vs convert to a dependency based on standalone-runnability requirements.
Establish team conventions so engineers don't reach for ordering rules expecting dependency semantics across modules.
## The root misconception Ordering rules answer the question *"in what order?"*, never *"does it run at all?"*. Two independent decisions drive the task graph: 1. **Membership** — which tasks are in the graph (decided by requested tasks + dependencies). 2. **Order** — the sequence among members (refined by `mustRunAfter` / `shouldRunAfter`). `mustRunAfter` touches only #2. If `build` never becomes a member, the rule has nothing to order. ## Reproducing the surprise ```kotlin tasks.named("release") { mustRunAfter("build") } ``` - `gradle release` → graph = `{release}`. `build` absent → rule inert → no build happens. **Surprise.** - `gradle build release` → graph = `{build, release}` → rule applies → `build` then `release`. Works. ## The two correct fixes ### Fix A — make it a dependency ```kotlin tasks.named("release") { dependsOn("build") // pulls build in AND orders it first } ``` Now `gradle release` always builds first. Note you usually no longer need the separate `mustRunAfter`, because `dependsOn` already implies ordering. ### Fix B — request both tasks Keep the ordering rule but always invoke `gradle build release` (e.g. in CI). The rule then guarantees order among the requested tasks. ## When the ordering rule is still the *right* choice If you *don't* want `release` to drag `build` along when invoked standalone (maybe `release` can run against a prebuilt artifact in some pipelines), then keeping `mustRunAfter` and explicitly requesting both in CI is exactly the decoupled design ordering rules exist for. The fix depends on whether `build` should be *mandatory* (→ dependency) or merely *ordered when present* (→ ordering rule). ## Mental checklist - Need the task to *always* run before? → dependency. - Need ordering *only when both already run*? → ordering rule. - Seeing 'my predecessor didn't run'? → you used an ordering rule where you needed a dependency.
- After switching to `dependsOn("build")`, is the original `mustRunAfter("build")` still needed?Usually no — a dependency already implies that `build` runs before `release`. The explicit ordering rule becomes redundant, though harmless.
- When is keeping the ordering rule (instead of a dependency) the better design?When `release` should be runnable standalone against a prebuilt artifact, but ordered after `build` whenever both are requested — i.e. you want order without forcing inclusion.
saying these in an interview costs you the question
- Believing mustRunAfter implicitly schedules the predecessor.
- Adding both dependsOn and mustRunAfter and thinking the ordering rule is what makes build run.