Gradle is a build automation tool, making use of Groovy to provide a powerful Domain Specific Language (DSL) to describe and instruct the behavior of your build.

Part of Gradle’s core is reflecting the actions of a build in tasks that become part of a Directed Acyclic Graph (DAG) expressing the relationships between those tasks.

Up until recently, the only option was to use task dependencies to affect the DAG. This post will discuss task dependencies and how they compare to two new task ordering features: must run after and finalizer tasks.

Dependencies

Gradle users will be pretty familiar with traditional task dependencies, but I’ll illustrate the key points to serve as a comparison to the other options.

Gradle can implicitly determine the dependencies of many tasks, but you can also declare them explicitly:

1

2

task myTask1

task myTask2(dependsOn:myTask1)

Now, if I call myTask2, Gradle knows it should run myTask1 first.

1

2

3

4

5

6

7

C:\&gt;gradle myTask2

:myTask1 UP-TO-DATE

:myTask2 UP-TO-DATE

BUILD SUCCESSFUL

Total time:8.536secs

Even if I try to run them in the wrong order, Gradle will correct me.

1

2

3

4

5

6

7

C:\&gt;gradle myTask2 myTask1

:myTask1 UP-TO-DATE

:myTask2 UP-TO-DATE

BUILD SUCCESSFUL

Total time:0.85secs

The key behavior is that asking for myTask2requiresmyTask1 to run sometime before it.

Must Run After

Must run after was introduced in Gradle 1.6 as an alternative to the stricter dependsOn. This is a way to enforce that tasks run in the order you desire, without forcing both tasks to be run.

1

2

taskmyTask1

taskmyTask2{mustRunAfter myTask1}

If I call both tasks, myTask2 will run after myTask1.

1

2

3

4

5

6

7

C:\&gt;gradle myTask2 myTask1

:myTask1 UP-TO-DATE

:myTask2 UP-TO-DATE

BUILD SUCCESSFUL

Total time:1mins1.37secs

However, if I only call myTask2, myTask1 won’t even run.

1

2

3

4

5

6

C:\&gt;gradle myTask2

:myTask2 UP-TO-DATE

BUILD SUCCESSFUL

Total time:0.866secs

Must run after means that if, and only if, myTask1 and myTask2 are both requested to be run (either directly or via other dependencies), myTask2 will always run after myTask1.

My favorite use cases for this are:

Ensuring that my integration tests run after my unit tests

Making sure that clean runs before any of the real tasks

NOTE: There is talk of an eventual should run after feature that would be more of a suggestion.

Finalized By

In the 1.7 version there is new support for “finalizer” tasks. These are tasks that need to run as a follow up to another task, whether it was requested or not.

1

2

taskmyTask1{finalizedBy'myTask2'}

task myTask2

If I ask for myTask1, it will run myTask2 afterwards:

1

2

3

4

5

6

7

C:\&gt;gradle myTask1

:myTask1 UP-TO-DATE

:myTask2 UP-TO-DATE

BUILD SUCCESSFUL

Total time:1.393secs

Even if myTask1 fails:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

C:\&gt;gradle myTask1

:myTask1 FAILED

:myTask2 UP-TO-DATE

FAILURE:Build failed with an exception.

*Where:

Build file'C:\Users\Andy\projects\sandox\testing\build.gradle'line:1

*What went wrong:

Execution failed fortask':myTask1'.

&gt;java.lang.Exception:Boom!

*Try:

Run with--stacktrace option toget the stack trace.Run with--info

or--debug option toget more log output.

BUILD FAILED

Total time:1.531secs

Finalizer tasks are essentially reverse dependencies. Asking for myTask1 requires that myTask2 be run sometime after, even if it fails.

One of the canonical use cases for this is stopping an application server after a task that has used it.

Conclusion

Gradle’s task relationship features have evolved a lot over the last couple of releases, providing far more flexibility into how tasks are ordered at runtime. This post has shown three ways to express those relationships to inform Gradle of how the build should behave.

See below for some Gradle resources from Safari Books Online.

Safari Books Online has the content you need

Gradle Beyond the Basics is an advanced guide that provides the recipes, techniques, and syntax to help you master this build automation tool. With clear, concise explanations and lots of ready-to-use code examples, you’ll explore four discrete areas of Gradle functionality: file operations, custom Gradle plugins, build lifecycle hooks, and dependency management.

Building and Testing with Gradle shows you to us Gradle for building and testing software written in Java and other JVM languages. It covers transitioning to Gradle from Maven, integration with IDEs such as Eclipse, and more.

Gradle Effective Implementation Guide is a great introduction and reference for using Gradle. The Gradle build language is explained with hands on code and practical applications. You learn how to apply Gradle in your Java, Scala or Groovy projects, integrate with your favorite IDE and how to integrate with well-known continuous integration servers.