Gradle, dependsOn ordering

Related searches

Confused by ordering in Gradle. I'm a novice, previously used Ant for builds, having a play with Gradle which may explain some of this

Brief background (in case anyone would be asking "why would you do that"). We ship a Java WebStart app in a war file. Java 7 (-40 onwards) is prompting users about incorrectly formatted jar files with missing elements. I would like to automate a process that gets the war; extracts the jars for JavaWS from 'bin' folder; adds elements to the Manifest Later I'll get to re-signing the jars and re-assembling the war, but for now I just want to get to adding the Manifest entries.

My problem is that I have defined tasks that have dependsOn elements but the tasks seem to run in the wrong order (see gradle file below). What I expect is the tasks to run in sequence: delete dir; get war; unwar the war; add elements to the jar. What I see (from log file) is: elements are added to jar, effectively this creates a new jar, the dir is deleted and the war is unwar'ed so I end up with the original war file contents.

I checked: Gradle Task To Call Other Tasks In Order however, I don't seem able to use mustRunAfter at all, could be related to version of gradle I have, but anyway I don't really want to control order of disparate tasks, I would prefer (in my Ant based thinking) that I can define the order I want by having tasks depend on each other.

Can anyone see the flaw in my build file? NOTE: if I remove the "dependsOn" from the resignclientjars task and run it manually after running the other tasks, it all works fine and I get my jars with the new elements in the Manifest, so I have a workable workaround, but would prefer to know what I'm doing wrong here.

task (deletework, type: Delete) {
    delete 'workYYY'
}

task (getlaganwar, type: Copy, dependsOn: deletework) {
    from "d:/dev/v8-0-5/wars"
    into "workYYY"
    include 'lagan.war'
}

task (unwar, type: Copy, dependsOn: getlaganwar) {
    from zipTree(file('workYYY/lagan.war'))
    into file("workYYY/lagan")
}

task (resignclientjars, type: Copy, dependsOn: unwar) {
//task (resignclientjars, type: Copy) {

//  mustRunAfter unwar

    def workDir = file("workYYY/lagan")
    def binDir = file(new File(workDir, "bin"))

    def collection = files { binDir.listFiles() }
    collection.each { 
        File jarFile = new File(binDir, it.name)
        ant.echo(message: "updating:${jarFile.absolutePath}")
        ant.jar(jarfile: jarFile, update: 'true') {
            manifest {
                attribute(name: 'Implementation-Title', value: 'Lagan Enterprise')
                attribute(name: 'Implementation-Vendor', value: 'Lagan Enterprise')
                attribute(name: 'Implementation-Version', value: 'Lagan Enterprise')
                attribute(name: 'Application-Name', value: 'Lagan Enterprise')
                attribute(name: 'Permissions', value: 'all-permissions')
            }
        }
    }
}

//unwar.mustRunAfter getlaganwar
//getlaganwar.mustRunAfter deletework
//resignclientjars.mustRunAfter getlaganwar

Debug Output contains the following:

[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks: 
[sts]      :resignclientjars
[sts] -----------------------------------------------------

12:06:19.658 [WARN] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:echo] updating:D:\dev\util\java7-clientjars\workYYY\lagan\bin\DebugWinIEBrowser.jar
12:06:19.666 [WARN] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:echo] updating:D:\dev\util\java7-clientjars\workYYY\lagan\bin\DebugWinMSWord.jar
12:06:19.670 [WARN] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:echo] updating:D:\dev\util\java7-clientjars\workYYY\lagan\bin\WinIEBrowser.jar
12:06:19.674 [WARN] [org.gradle.api.internal.project.ant.AntLoggingAdapter] [ant:echo] updating:D:\dev\util\java7-clientjars\workYYY\lagan\bin\WinMSWord.jar

12:06:19.690 [INFO] [org.gradle.execution.TaskNameResolvingBuildConfigurationAction] Selected primary task ':resignclientjars'
12:06:19.692 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Waiting to acquire exclusive lock on task artifact state cache (D:\dev\util\java7-clientjars\.gradle\1.5\taskArtifacts).
12:06:19.692 [DEBUG] [org.gradle.cache.internal.DefaultFileLockManager] Lock acquired.
12:06:19.692 [INFO] [org.gradle.BuildLogger] Tasks to be executed: [task ':deletework', task ':getlaganwar', task ':unwar', task ':resignclientjars']

12:06:19.693 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':deletework'
12:06:19.693 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] Determining if task ':deletework' is up-to-date
12:06:19.694 [INFO] [org.gradle.api.internal.changedetection.ShortCircuitTaskArtifactStateRepository] Task ':deletework' has not declared any outputs, assuming that it is out-of-date.
12:06:19.694 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] task ':deletework' is not up-to-date

12:06:19.695 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter] Executing actions for task ':deletework'.
12:06:19.695 [DEBUG] [org.gradle.api.internal.file.copy.DeleteActionImpl] Deleting D:\dev\util\java7-clientjars\workYYY

12:06:19.934 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':deletework'
12:06:19.934 [LIFECYCLE] [org.gradle.TaskExecutionLogger] :getlaganwar
12:06:19.934 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':getlaganwar'
12:06:19.936 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] Determining if task ':getlaganwar' is up-to-date

12:06:19.942 [INFO] [org.gradle.api.internal.changedetection.DefaultTaskArtifactStateRepository] Executing task ':getlaganwar' due to:
Output file D:\dev\util\java7-clientjars\workYYY for task ':getlaganwar' has changed.
Output file D:\dev\util\java7-clientjars\workYYY\lagan.war has been removed for task ':getlaganwar'.
12:06:19.942 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] task ':getlaganwar' is not up-to-date

12:06:19.944 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter] Executing actions for task ':getlaganwar'.

12:06:20.564 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':getlaganwar'
12:06:20.565 [LIFECYCLE] [org.gradle.TaskExecutionLogger] :unwar
12:06:20.565 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':unwar'
12:06:20.586 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] Determining if task ':unwar' is up-to-date
12:06:20.588 [DEBUG] [org.gradle.api.internal.changedetection.DefaultFileCacheListener] Can cache files for ZIP 'D:\dev\util\java7-clientjars\workYYY\lagan.war'
12:06:20.588 [DEBUG] [org.gradle.api.internal.changedetection.DefaultFileCacheListener] Can cache files for file 'D:\dev\util\java7-clientjars\workYYY\lagan'
12:06:24.096 [INFO] [org.gradle.api.internal.changedetection.DefaultTaskArtifactStateRepository] Executing task ':unwar' due to:
Output file D:\dev\util\java7-clientjars\workYYY\lagan for task ':unwar' has changed.

12:06:24.097 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] task ':unwar' is not up-to-date

12:06:24.100 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter] Executing actions for task ':unwar'.

12:06:27.863 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':unwar'
12:06:27.863 [LIFECYCLE] [org.gradle.TaskExecutionLogger] :resignclientjars
12:06:27.864 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':resignclientjars'
12:06:27.864 [INFO] [org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter] Skipping task ':resignclientjars' as it has no source files.
12:06:27.864 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':resignclientjars'
12:06:27.864 [LIFECYCLE] [org.gradle.TaskExecutionLogger] :resignclientjars UP-TO-DATE
12:06:27.865 [DEBUG] [org.gradle.execution.taskgraph.DefaultTaskGraphExecuter] Timing: Executing the DAG took 8.173 secs
12:06:27.865 [LIFECYCLE] [org.gradle.BuildResultLogger] 
12:06:27.865 [LIFECYCLE] [org.gradle.BuildResultLogger] BUILD SUCCESSFUL
12:06:27.865 [LIFECYCLE] [org.gradle.BuildResultLogger] 
12:06:27.866 [LIFECYCLE] [org.gradle.BuildResultLogger] Total time: 8.886 secs

The problem with your build script isn't the task dependencies, but that the task definition for resignclientjars is incorrect. It's doing its work in the configuration phase (i.e. for every build invocation whatsoever) instead of the execution phase. A correct task definition would look as follows:

task resignclientjars(dependsOn: unwar) {
    doLast {
       ...
    }
} 

You can read up on configuration phase vs. execution phase in the Gradle User Guide or the Gradle forums.

Authoring Tasks, If you specify a “dependsOn” relationship then the tasks will always run in the correct order. Gradle will always run tasks within a single module in series (never in parallel). In a non-composite build, the only way to benefit from parallel execution is to use multiple modules. When Gradle executes a task, it can label the task with different outcomes in the console UI and via the Tooling API. These labels are based on if a task has actions to execute, if it should execute those actions, if it did execute those actions and if those actions made any changes. (no label) or

You're using Gradle 1.5, and mustRunAfter dates from 1.6. The current version is 1.8.

dependsOn doesn't fix any order for the tasks. This has been discussed ad nauseam in various bug reports. The workaround is to use depencencies between indifidual tasks, or mustRunAfter.

How to order a Composite Build with dependsOn?, I've searched for a solution but could not really find an answer that would fit my needs. I have a project that is split into 4 subprojects like so� Task Dependencies and Task Ordering. A task may have dependencies on other tasks or might be scheduled to always run after another task. Gradle ensures that all task dependencies and ordering rules are honored when executing tasks, so that the task is executed after all of its dependencies and any "must run after" tasks have been executed.

The unpredictable dependency ordering in Gradle is really annoying.

Here is workaround for executing the dependent tasks in order:

task dist(type: Zip) {
    def tasks = [clean, jar, test, docs]
    for (int i = 0; i < tasks.size() - 1; i++) {
        tasks[i + 1].mustRunAfter(tasks[i])
    }
    dependsOn(tasks)

    //...other stuff
}

Probably this workaround could be extracted in reusable manner as strictDependsOn()...

Specify the order when a task depends on 2 other , I am trying to develop a "release" task within a multi-project build. This task needs to coordinate the execution of many tasks across all the� Gradle executes the dependent tasks in alphabetical order. Along with dependsOn, Gradle provides some additional categories of ordering. For example, after the execution of the last task, you might want to clean the temporary resources, which were created during the build process. To enable this type of ordering, Gradle provides the following

For whatever reason gradle does guarantee order for dependsOn, after time they added mustRunAfter, which however you have to chain yourself like a idiot, so here is a utility:

task buildAppRelease() {
    group = "build"
    dependsOn ordered(":allClean", ":allTestReleaseUnitTest", ":app:assembleRelease")
}

def ordered(String... dependencyPaths) {
    def dependencies = dependencyPaths.collect { tasks.getByPath(it) }
    for (int i = 0; i < dependencies.size() - 1; i++) {
        dependencies[i + 1].mustRunAfter(dependencies[i])
    }
    return dependencies
}

How to order amongst the group of dependsOn , To completely rewrite existing Eclipse files, execute a clean task together with its corresponding generation task, like “gradle cleanEclipse eclipse” (in that order). If you want to make this the default behavior, add “tasks.eclipse.dependsOn(cleanEclipse)” to your build script. This makes it unnecessary to execute the clean task

I have been able to use dependsOn and mustRunAfter as below to define order for the tasks. Note, here I want to run ktlintFormat first then run ktlint.

ktlint.mustRunAfter ktlintFormat
compileKotlin.dependsOn ktlintFormat,ktlint

However, if you overwrite the "compileJava" task (real world use case for this is needing to use an aspectj compiler instead), then the ordering is broken as compilation of project "Child" occurs before the jar is built for project "Parent".

gradle documentation: Adding multiple dependencies Ordering tasks; B.dependsOn A C.dependsOn B D.dependsOn C The output is: > gradle -q D Hello from A Hello

Gradle is written in Java and uses Groovy for its domain-specific language (DSL). While your primary use case for Gradle as a DevOps tool might be using it to call other scripts, you can also extend Gradle project by using the existing Java libraries, writing Java or Groovy code.

Gradle Tutorials and Guides. Here you can find project-based tutorials and topical guides to help you learn Gradle through using it. Whether you are new to Gradle or an experienced build master, the guides hosted here are designed to help you accomplish your goals.

Comments
  • I fear this will cause every :allTestReleaseUnitTest will start :allClean first, even when started directly, not as part of buildAppRelease task...
  • I can't believe that Gradle does not respect the order of dependencies. That's completely annoying.