Task is always up to date - gradle

I've got a gradle build with a task like the following
task createFolders {
file(rootFolder).mkDirs()
}
Note that in the real system there are about 15 folders getting created during this task.
This task always reports as UP-TO-DATE when I run the task, even if I run it directly after deleted the folders being created. I have several tasks that depend on this task and they run.
How do I tell gradle that this task is only up to date if all the created folders exist?

It happens because folders are created during configuration phase. Add an action:
task createFolders << {
file(rootFolder).mkDirs()
}
For more details see here and here.

Related

Gradle Report Plugin Task is not executed properly

I am trying to execute Plugin task depending on the build task of the root project.
Therefore I've already did this in my gradle.build:
task dependencyCheck(dependsOn: dependencyUpdates){*Task instructions*}
build.dependsOn(dependencyCheck)
The dependencyUpdates task creates a report of all dependencies that are stored in an external folder.
The console says that the task is executed successfully:
Code Snippet
But actually it is not refreshing the report.xml in the external folder and the modification date stays the same.
What am I doing wrong?
Thanks
Found the solution:
I had to set the outputDir.
I thought the default path would be applied to the task like when executing it manually, but that is not the case.

Why copy task delete stale output on first build?

I have this kotlin gradle build script representing my use case.
I am working with Gradle 6.7.
This is my kotlin gradle build file:
plugins {
java
}
tasks.register("createFile"){
doLast{
projectDir.resolve("tmp.txt").createNewFile()
projectDir.resolve("tmp.txt").writeText("tmp")
}
dependsOn("assemble")
}
tasks.register("createExecFile", Exec::class){
workingDir(buildDir)
commandLine("cmd", "/c", "mkdir destdir\\subdir")
dependsOn("createFile")
}
tasks.register("copyBug", Copy::class){
from(projectDir.resolve("tmp.txt"))
into(buildDir.resolve("destDir"))
dependsOn("createExecFile")
}
Now run gradle copyBug -i.
The first time this will give you this output:
> Task :copyBug Deleting stale output file: E:\repo\BugCOpy\build\destDir Caching disabled for task ':copyBug' because: Build cache is disabled Task ':copyBug' is not up-to-date because: No history is available.
The copy task deletes the file created by the previous exec task.
Now if you rerun this command the copy task won't delete stale file.
So what are those stale file? How can I prevent those file to be deleted? My first build and is different than the other build.
Should I file a bug?
In your createExecFile task you produce output files without telling Gradle about them. So Gradle doesn’t know that this task and the copyBug task use the same output directory. Instead, Gradle believes that copyBug is the only task producing outputs under build/destdir and hence it’s safer to assume that any existing files in that directory should not be there (and are “stale”).
The solution is to tell Gradle that your createExecFile task outputs to build/destdir:
tasks.register("createExecFile", Exec::class) {
workingDir(buildDir)
commandLine("cmd", "/c", "mkdir destdir\\subdir")
// tell Gradle about the output directory
outputs.dir(buildDir.resolve("destdir"))
dependsOn("createFile")
}
See this release notes section for why this behavior was introduced and this explanation to a very similar issue if you want some more background information.
My build process looks like
run gradle (part 1)
do something else
run gradle (part 2)
For me annoyingly running gradle in step 3 would not just add a few files to the output directory but delete that folder as stale first. Even adding
outputs.dir(...)
did not prevent Gradle from removing it as stale. Working out the inputs and outputs of my task looked too tedious, but luckily I found a way to tell Gradle not to perform any up to date tracking:
Example 37. Ignoring up-to-date checks mentions to add
doNotTrackState("Comment why this is needed")
which ultimately helped me to keep the files from build step 1.

How to run a task automatically when a gradle script is called

I have a file that needs to be pushed into a specific directory when the project is built with gradle.
My solution so far is inside the build.gradle itself:
....
task copyTask(type: Copy) {
from 'filename'
into 'dirctoryname'
}
The other question on this website wonder, why their tasks are being executed automatically and are told that they need to add a closure inside the task (like doLast).
I however actually want the task to be executed automatically, so I am not using any closures.
When I run the task manually it works just fine and the file gets copied into the directory.
When I however rightclick -> run the build script in IntelliJ nothing happens.
How can I let the task get executed automatically any time the build script is executed?
I was thinking of something like "dependsOn this" but that just throws nasty errors.
And "build.dependsOn copyTask" doesn't throw errors, but also doesn't copy the file.
You have to link the creation of filename also into the deps. E.g.
copyTask.dependsOn myBuildStep
assemle.dependsOn copyTask

Gradle shouldRunAfter not available for a task

I created this repo to reproduce exactly what I'm seeing. I have a project that I'm building with Gradle. I would like to configure my Gradle build so that running:
./gradlew build
Has the exact same effect as running:
./gradlew clean build scalafmt shadowJar fizzbuzz
Meaning Gradle calls tasks in the following order:
clean
build (compile & run unit tests)
scalafmt (run a tool that formats my code to a styleguide)
shadowJar (creates a self-contained executable "fat" jar)
fizzbuzz (prints out "Fizzbuzz!" to the console)
According to the Gradle docs on ordering tasks, it seems that I can use shouldRunAfter to specify ordering on all tasks...
If you clone my repo above and then run ./gradlew build you'll get the following output:
./gradlew build
Fizzbuzz!
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/myUser/thelab/idea-scala-hate-each-other/build.gradle' line: 65
* What went wrong:
A problem occurred evaluating root project 'idea-scala-hate-each-other'.
> Could not find method shouldRunAfter() for arguments [task ':build'] on cz.alenkacz.gradle.scalafmt.PluginExtension_Decorated#6b24ddd7.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 10.983 secs
So even though I specify fizzbuzz to run last...its running first! And there are (obviously) errors with the rest of my config. And I'm not sure how to "hook" clean so that even when I run ./gradlew build it first runs clean.
I'd be OK with a solution that requires me to write my own "wrapper task" to achieve the order I want, and then invoke it, say, via ./gradlew buildMyApp, etc. Just not sure how to accomplish what I want.
Update
I made some changes to build.gradle and am now seeing this:
./gradlew fullBuild
:compileJava UP-TO-DATE
:compileScala
:processResources UP-TO-DATE
:classes
:jar
:startScripts
:distTar
:distZip
:assemble
:compileTestJava UP-TO-DATE
:compileTestScala UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
:clean
:fizzbuzz
Fizzbuzz!
:scalafmt
:shadowJar
:fullBuild
So when I run ./gradlew fullBuild task execution seems to be:
build (which calls compileJava through check)
clean
fizzbuzz
scalafmt
shadowJar
So the ordering is still wrong even given my most recent changes...
As Oliver already stated, you need to put the console output to a doFirst or doLast closure, otherwise it will be executed when the task is defined (during configuration phase).
The exception is caused by the fact that both extension properties and tasks are added to the scope of the Project object, but if both an extension property and a task with the same name (scalafmt in this case) exist, the extension property will be accessed. As the error message tells you, you are trying to access the shouldRunAfter method on an object of the type PluginExtension, where it does not exist. You need to make sure to access the task:
tasks['scalafmt'].shouldRunAfter build
Update
Actually, I thought that you only need the two specific problems to be solved, but already have a solution for your basic Gradle structure.
First of all, both shouldRunAfter and mustRunAfter do not actually cause a task to be executed, they only define the order if both tasks are executed (caused by command line or a task dependency). This is the reason why the tasks clean, scalafmt, shadowJar and even fizzbuzz are not executed if you call gradle build. So, to solve your first problem, you could let the build task, which you call explicitly, depend on them:
build.dependsOn 'clean', 'scalafmt', 'shadowJar', 'fizzbuzz'
But a task dependency will always run before the parent task, so all tasks will be executed before the build task. This should not be a problem, since the build task does nothing more than collecting task dependencies for all required build steps. You would also need to define the order not only between of your task dependencies, e.g. clean and the parent task build, but mainly between the existing task dependencies, e.g. compileJava. Otherwise clean could run after compileJava, which would delete the compiled files.
Another option would be to define a new task, which then depends on all the tasks you want to execute:
task fullBuild {
dependsOn 'clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz'
}
This would still require to define the order between your tasks and the existing task dependencies, e.g.
compileJava.mustRunAfter 'clean'
[...]
Please note, that now you would have to call gradle fullBuild from command line. If you really need to only call gradle build via command line and still execute some tasks after the actual build task, you could use a little trick in your settings.gradle file:
startParameter.with {
if (taskNames == ['build']) {
taskNames = ['clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz']
}
}
This piece of code checks the task name input you entered via command line and replaces it, if it only contains the build task. This way you would not have to struggle with the task order, since the command line tasks are executed consecutively.
However, this is not a clean solution. A good solution would include the definition of task dependencies for all tasks that really depend on each other and the invocation of multiple tasks via command line (which you want to avoid). Especially the hard connection between the clean and the build task bypasses a lot of useful features from the Gradle platform, e.g. incremental builds.
Regarding your second point in the update, it is wrong that the fizzbuzz task is running first. It is not running at all. The command line output is printed when the task is configured. Please move the println call to a doFirst / doLast closure:
task fizzbuzz {
doFirst {
println "Fizzbuzz!"
}
}
One of the possible causes of that error could be because Gradle couldn't compile the task of the method shouldRunAfter or mustRunAfter.
Also it could happen when there is another entity of other type (not a task) with the same name of the task of the method shouldRunAfter or mustRunAfter. In this case you could use the syntax tasks['task1_name'].shouldRunAfter tasks['task2_name'] or tasks['task1_name'].mustRunAfter tasks['task2_name'] to make sure Gradle is referencing a task type entity.

What is the proper way to run tasks in succession in Gradle

I have a task like this in gradle: task startServer (dependsOn: [':backend:appengineStop', ':backend:appengineRun']). The problem is appengineStop is not run or doesn't seem to be run before appengineRun runs.
I am saying this because when the server is running and I execute this task, it should stop the server first (appengineStop) and start the server again (appengineRun), but this is not happening and build fails saying "Port already in use".
That is why I listed appengineStop first so it will stop the server. Can someone please explain.
Setting of deppendsOn of your task just saying, that both tasks on wich you depends (it's ':backend:appengineStop' and ':backend:appengineRun' in your case) will be executed before your dependent startServer task. The order of execution of this tasks is not determined. Probably, they'll be executed in alphabetical order, but it's a gradle implementation's behavior and you don't use to rely on it.
Gardle tasks have a capacity to determine their order using mustRunAfter method, which make a task running just after task specified as an argument is executed.
You can try to do it by adding to your build script somthing like:
task startServer (dependsOn: [':backend:appengineStop', ':backend:appengineRun']) {
tasks.getByPath(':backend:appengineRun').mustRunAfter ':backend:appengineStop'
}

Resources