53

Whether taskB mustRunAfter taskA, or taskB dependsOn taskA, it seems that taskA runs first, then taskB runs. What's the difference?

Dan B.
  • 1,451
  • 2
  • 14
  • 23

4 Answers4

69

For example:

tasks.create('a')

tasks.create('b').dependsOn('a')

tasks.create('c')

tasks.create('d').mustRunAfter('c')
  • dependsOn - sets task dependencies. Executing b here would require that a be executed first.
  • mustRunAfter - sets task ordering. Executing d does not require c. But, when both c and d are included, c will execute before d.
mkobit
  • 43,979
  • 12
  • 156
  • 150
  • Does this mean `b.dependsOn(a)` doesn't add the outputs of `a` to the inputs of `b`? So `a` could be run without `b` running? – adentinger Feb 11 '21 at 16:52
  • @AnthonyD973 No, the inputs in this example are not implicitly passed through. Gradle does have support for dependency inference based on inputs/outputs in other areas, though. – mkobit Feb 12 '21 at 17:40
14

Where possible, declare task inputs instead of task dependencies. That said, expanding on mkobit's answer:

Ordering and dependencies involving two tasks

mustRunAfter

mustRunAfter controls the execution order of tasks explicitly specified on the command line, but doesn't create implicit dependencies on other tasks. Given taskA and taskB:

build.gradle.kts

val taskA by tasks.registering {
    doLast {
        println("taskA")
    }
}

val taskB by tasks.registering {
    doLast {
        println("taskB")
    }
}

taskB {
    mustRunAfter(taskA)
}

then

  • gradle taskB taskA executes taskA followed by taskB;
  • gradle taskA executes taskA only;
  • gradle taskB executes taskB only.

dependsOn

dependsOn creates implicit dependencies on other tasks. Given the same two tasks:

taskB {
    dependsOn(taskA)
}

then

  • gradle taskB executes taskA followed by taskB;
  • gradle taskB taskA executes taskA followed by taskB;
  • gradle taskA executes taskA only.

Ordering and dependencies involving three tasks

mustRunAfter and dependsOn accept an unordered collection of tasks. Given:

val taskC by tasks.registering {
    doLast {
        println("taskC")
    }
}

taskC {
    dependsOn(taskA, taskB)
}

then gradle taskC executes taskA and taskB in no guaranteed order, followed by taskC (assuming no other dependsOn or mustRunAfter declarations).

mustRunAfter also controls the execution order between interdependent tasks that would otherwise have no guaranteed order. Given:

taskB {
    mustRunAfter(taskA)
}

then gradle taskC executes taskA followed by taskB followed by taskC, but gradle taskB only runs taskA because taskB does not dependOn(taskA).

Other types of task dependency

Further reading

Consult the Gradle documentation for more information on:

hertzsprung
  • 9,445
  • 4
  • 42
  • 77
6

Sometimes they have the same effect. For example, if taskC dependsOn taskA and taskB, then it doesn't matter whether taskB dependsOn taskA or mustRunAfter it - when you run taskC, the order will be taskA, taskB, taskC.

But if taskC dependsOn taskB only, then there's a difference. If taskB dependsOn taskA, then it's the same as above - taskA, taskB, taskC. If taskB merely mustRunAfter taskA, then taskA doesn't run, and running taskC will run taskB, then taskC.

mustRunAfter really means if taskA runs at all, then taskB must run after it.

Dan B.
  • 1,451
  • 2
  • 14
  • 23
0

Generally, if order is important, it appears that you need both dependsOn and mustRunAfter. Here is an example of running two tasks, one (custom registered "importUnicodeFiles" task) that is in "this" project and one (predefined "run" task) that is in a sibling project named ":unicode":

tasks.register("rebuildUnicodeFiles") {
    description = "Force the rebuild of the `./src/main/resources/text` data"
    val make = project(":unicode").tasks["run"]
    val copy = tasks["importUnicodeFiles"]
    dependsOn(make)
    dependsOn(copy)
    copy.mustRunAfter(make)
}
cpurdy
  • 1,177
  • 5
  • 12