Gradle tip #3-Task sequence,
Original article link
I noticed that most of the problems I encountered when using Gradle are related to the execution sequence of tasks. Obviously, my build will work better if all my tasks are executed correctly. The following describes how to change the execution sequence of tasks.
DependsOn
In my opinion, the most direct way to describe your method of depending on other tasks during task execution is to use the dependsOn method.
For example, in the following scenario, task A already exists. To add task B, the execution of task B must be completed after task:
A "title =" ">
This is A simple scenario. Assume that A and B are defined as follows:
task A << {println 'Hello from A'}task B << {println 'Hello from B'}
You only need to call B. dependsOn.
This means that as long as I execute task B, task A will first execute.
paveldudka$ gradle B:AHello from A:BHello from B
In addition, you can declare its dependencies in the task configuration area:
task A << {println 'Hello from A'}task B { dependsOn A doLast { println 'Hello from B' }}
What should we do if we want to insert our tasks in an existing task dependency?
The process is similar to that just now. Assume that the following task dependency already exists:
task A << {println 'Hello from A'}task B << {println 'Hello from B'}task C << {println 'Hello from C'}B.dependsOn AC.dependsOn B
Join our new task
task B1 << {println 'Hello from B1'}B1.dependsOn BC.dependsOn B1
Output:
paveldudka$ gradle C:AHello from A:BHello from B:B1Hello from B1:CHello from C
Note that dependsOn adds a task to the dependent set. Therefore, it is no problem to depend on multiple tasks.
task B1 << {println 'Hello from B1'}B1.dependsOn BB1.dependsOn Q
Output:
paveldudka$ gradle B1:AHello from A:BHello from B:QHello from Q:B1Hello from B1
MustRunAfter
Now assume that I have another task, which depends on the other two tasks. Here I use a real scenario. I have two tasks, one for unit testing and the other for UI testing. Another task runs all tests and depends on the previous two tasks.
task unit << {println 'Hello from unit tests'}task ui << {println 'Hello from UI tests'}task tests << {println 'Hello from all tests!'}tests.dependsOn unittests.dependsOn ui
Output:
paveldudka$ gradle tests:uiHello from UI tests:unitHello from unit tests:testsHello from all tests!
Although unitest and UI test are executed before the test task, the execution sequence of the two tasks, unit and ui, cannot be guaranteed. Although the execution is performed in alphabetical order, it depends on the implementation of Gradle. Your code cannot depend on this order.
Since the UI test takes a longer time than the unit test, I want the unit test to be executed first. One solution is to make the ui task dependent on the unit task.
Unit "title =" ">
task unit << {println 'Hello from unit tests'}task ui << {println 'Hello from UI tests'}task tests << {println 'Hello from all tests!'}tests.dependsOn unittests.dependsOn uiui.dependsOn unit // <-- I added this dependency
Output:
paveldudka$ gradle tests:unitHello from unit tests:uiHello from UI tests:testsHello from all tests!
Now unit test is executed before ui test.
However, there is a disgusting problem here. In fact, my ui test does not depend on unit test. I want to execute the ui test separately, but every time I execute the ui test, the unit test will be executed first.
Here mustRunAfter is used. MustRunAfter does not add dependencies. It only tells Gradle the execution priority if two tasks exist at the same time. For example, we can specify the ui here. mustRunAfter unit. In this way, if both the ui task and the unit task exist, Gradle executes the unit test first. If only gradle ui is executed, it does not execute the unit task.
task unit << {println 'Hello from unit tests'}task ui << {println 'Hello from UI tests'}task tests << {println 'Hello from all tests!'}tests.dependsOn unittests.dependsOn uiui.mustRunAfter unit
Output:
paveldudka$ gradle tests:unitHello from unit tests:uiHello from UI tests:testsHello from all tests!
Dependencies such:
MustRunAfter is an experimental feature in Gradle2.4.
FinalizedBy
Now we have two tasks, unit and ui. Assume that both tasks will output The test report. Now I want to combine these two test reports into one:
task unit << {println 'Hello from unit tests'}task ui << {println 'Hello from UI tests'}task tests << {println 'Hello from all tests!'}task mergeReports << {println 'Merging test reports'}tests.dependsOn unittests.dependsOn uiui.mustRunAfter unitmergeReports.dependsOn tests
Now, if I want to obtain the test reports of the ui and unit, execute the task mergeReports.
paveldudka$ gradle mergeReports:unitHello from unit tests:uiHello from UI tests:testsHello from all tests!:mergeReportsMerging test reports
This task can work, but it looks stupid. MergeReports does not feel particularly good from the user's perspective. I want to execute the tests task to obtain the test report without having to know the existence of mergeReports. Of course, I can move the merge logic to the tests task, but I don't want to make the tests task too bloated. I will continue to put the merge logic in the mergeReports task.
FinalizeBy. As the name suggests, finalizeBy is the task to be executed after the task is executed. Modify the script as follows:
task unit << {println 'Hello from unit tests'}task ui << {println 'Hello from UI tests'}task tests << {println 'Hello from all tests!'}task mergeReports << {println 'Merging test reports'}tests.dependsOn unittests.dependsOn uiui.mustRunAfter unitmergeReports.dependsOn teststests.finalizedBy mergeReports
Now you can run the tests task to get the test report:
paveldudka$ gradle tests:unitHello from unit tests:uiHello from UI tests:testsHello from all tests!:mergeReportsMerging test reports
Note: finalizedBy is also an experimental function of Gradle2.4.