I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}
Related
task('copytask', type: Copy) {
def SRC_FOLDER = "$rootDir"
def DEST_FOLDER = 'C:\\Users\\IdeaProjects\\destfolder'
copy {
from("$SRC_FOLDER\\controller\\app")
into("$DEST_FOLDER\\controller\\app")
}
}
This is my small Gradle task to copy.
Whenever I am reloading/refreshing my Gradle or starting my IDEA this task is executing, i want this task to execute only when I call it.
Your task is not really executing. Instead, your task is getting configured, but during configuration you are copying using the copy method of the Project instance. Your actual task copytask of type Copy remains unconfigured and won't do anything, even if it would be executed.
Change your code and remove the copy method and the files should only be copied when running the task copytask:
task('copytask', type: Copy) {
def SRC_FOLDER = "$rootDir"
def DEST_FOLDER = 'C:\\Users\\IdeaProjects\\destfolder'
from("$SRC_FOLDER\\controller\\app")
into("$DEST_FOLDER\\controller\\app")
}
I'm trying to create a custom Gradle 4.3.1 task that will:
Run ./gradlew build which produces a build/libs/myapp.jar artifact; then
Creates a myapp-1.0.zip ZIP file whose contents include:
build/libs/myapp.jar; and
./AppGuide.md; and
./app-config.json
Here's my best attempt:
task zipMeUp(type: Zip) {
String zipName = 'myapp-1.0.zip'
doFirst {
tasks.build
}
from 'build/libs/myapp.jar'
from 'AppGuide.md'
from 'app-config.json'
into zipName
}
When I run this (./gradlew zipMeUp) I get the following output:
HarveyZ:myapp myuser$ ./gradlew zipMeUp
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
But nothing actually seems to happen (no myapp-1.0.zip file in the directory). Any idea what the fix/solution is?
Don't use doFirst, use dependsOn
task zipMeUp(type:Zip, dependsOn :[build]) {
String zipName = 'myapp-1.0.zip'
from 'build/libs/myapp.jar'
from 'AppGuide.md'
from 'app-config.json'
version = "1.0"
baseName = "myapp"
}
We have an optional gradle task docker that depends on task war, which if executed, needs a war file generated with an extra file in it. This extra file can be added to the resources within the processResources task (or potentially directly in the war task). However, the corresponding code block must not run if task docker has not been requested and will not be run.
We need a correct condition in the following block checking if task docker is in the pipeline:
processResources {
if (/* CONDITION HERE: task docker is requested */) {
from ("${projectDir}/docker") {
include "app.properties"
}
}
}
task docker(type: Dockerfile) {
dependsOn build
...
Clarification: processResources is a standard dependency of the war task and the latter is a standard dependency of the build task. processResources is always executed on build, with or without the docker task to collect resources for assembling the war and may not be fully disabled in this case. One could move the code in question to a separate task dependent on docker and working on the output directory of processResources, yet before war is run, however, such a construct will result in much less clarity for such a simple thing.
You can simply add additional dependency to your docker task, to make it relying not only on build task, but also on processResources. In that case, your processResources task will be called only if docker should be executed.
Another solution is to use TaskExecutionGraph. This let you initialize some variable, which could tell you, whether or not some task will be executed. But you have to understand, that graph is prepared only after all the configuration is done and you can rely on it only during the execution phase. Here is a short example, how it could be used:
//some flag, whether or not some task will be executed
def variable = false
//task with some logic executed during the execution phase
task test1 << {
if (variable) {
println 'task2 will be executed'
} else {
println 'task2 will not be executed'
}
}
//according to whether or not this task will run or not,
//will differs test1 task behavior
task test2(dependsOn: test1) {
}
//add some logic according to task execution graph
gradle.taskGraph.whenReady {
taskGraph ->
//check the flag and execute only if it's true
if (taskGraph.hasTask(test2)) {
variable = true
println 'task test2 will be executed'
}
}
Furthermore, you can try to configure your custom task to make it disabled by setting is enabled property to false, if docker task is not in the execution graph. In that case you don't have to provide some flags and logic in execution phase. Like:
task test1 {
//some logic for execution
doLast {
println "execute some logic"
}
}
task test2(dependsOn: test1) {
}
gradle.taskGraph.whenReady {
taskGraph ->
if (!taskGraph.hasTask(test2)) {
//Disable test1 task if test2 will not run
test1.enabled = false
}
}
But it'll be impossible to run this custom task separately without some additional configuration.
I have a very simple build script like so
task hello{
println("hello World")
}
task bye {
println("bye")
}
On the command line I run
gradle hello and I get the following output:
hello World
bye
:hello UP-TO-DATE
Why is it executing the task "bye" (I'm assuming it gets executed since "bye" gets printed)? Thanks.
It's a common pitfall:
task hello {
println("Any code in here is about *configuring* the\
task. By default, all tasks always get configured.")
doLast {
println("Any code in here is about *executing* the task.\
This code only gets run if and when Gradle decides to execute the task.")
}
}
The distinction between configuration phase and execution phase is probably the single most important concept to understand in Gradle. It can be confusing at first, and may go away in the future. A kind of analogue in the Ant/Maven world is that these tools first parse XML build scripts and build an object model (perhaps resolving some properties along the way), and only then execute the build.
Adding to Peter answer, If you want to execute all task , you can specify the defaultTasks list.
defaultTasks 'clean', 'run'
task clean {
doLast {
println 'Default Cleaning!'
}
}
task run {
doLast {
println 'Default Running!'
}
}
task other {
doLast {
println "I'm not a default task!"
}
}
Output
Output of gradle -q
> gradle -q
Default Cleaning!
Default Running!
More details can be found here
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
I am writing a Gradle build for a non-java project for assembling existing directories and tar archives into a .tar.gz The tar task skips if I use the definition like so:
task archive(dependsOn: 'initArchive',type: Tar) << {
baseName = project.Name
destinationDir = new File(project.buildDir.path+'/installer')
compression = Compression.GZIP
from (archiveDir)
doLast{
checksum(archivePath)
}
}
here's the console output
:jenkins-maven-sonar:archive
Skipping task ':jenkins-maven-sonar:archive' as it has no source files.
:jenkins-maven-sonar:archive UP-TO-DATE
BUILD SUCCESSFUL
Total time: 9.056 secs
When I try to use tar task as a method it fails complaining cannot find method
task archive(dependsOn: 'initArchive') << {
tar{
baseName = project.Name
destinationDir = new File(project.buildDir.path+'/installer')
compression = Compression.GZIP
from (archiveDir)
doLast{
checksum(archivePath)
}
}
}
FAILURE: Build failed with an exception.
* Where:
Build file '/home/anadi/Code/da-ci-installers/build.gradle' line: 29
* What went wrong:
Execution failed for task ':jenkins-maven-sonar:archive'.
> Could not find method tar() for arguments [build_6a2bckppv2tk8qodr6lkg5tqft$_run_closure3_closure5_closure7#4a5f634c] on task ':jenkins-maven-sonar:archive'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output.
BUILD FAILED
Total time: 8.749 secs
Can we run the tar task in same way as Gradle allows running copy? In the same build I have a block like follows and I want to know if tar can used in the same way
copy {
project.logger.info("Copying bundle :: "+bundle[x])
from(rootProject.projectDir.path+"/3rd-party-tools/"+bundle[x]) {
include '**/*.*'
}
into(archiveDir)
}
if not how to make sure my build does not "skip tar" task if using the first form described above.
You have fallen for the classical mistake of configuring a task in the execution phase rather than the configuration phase. The solution is to remove the << in the first code snippet.
If you find the << (and the difference it makes) confusing, a good solution is to never use << but always the more explicit doLast {}.
There is no tar method, but it's usually better to make these things a separate task anyway. (Methods like copy should only be preferred over the corresponding task if there is a strong reason.)
I had a funny situation where I got hit by this when using doLast{} on a tar task.
It was because of a multi-project build:
build.gradle
--> sub-project
--> build.gradle
In this case if you try to have a tar or a copy task in the main build file that references something from that project(":sub-project") uses it will tempt the developer to wrap it in doLast.
For example, main build.gradle file has:
task distTar(type: Tar, dependsOn: "buildDist") {
description "Package ProjName into a Tar file"
group "Build"
baseName = 'outbasename'
archiveName = baseName + '.tar.gz'
compression = Compression.GZIP
destinationDir = file(project(":packaging").buildDir.path)
extension = 'tar.gz'
into('outdir') {
from project(":sub-project").war
}
}
So they got an error that project(":sub-project").war doesn't exist. So to get around it someone put doLast {} the task and errors went away. BAD!!
task distTar(type: Tar, dependsOn: "buildDist") {
doLast { // <-- BAD!!
description "Package ProjName into a Tar file"
group "Build"
baseName = 'outbasename'
archiveName = baseName + '.tar.gz'
compression = Compression.GZIP
destinationDir = file(project(":packaging").buildDir.path)
extension = 'tar.gz'
into('outdir') {
from project(":sub-project").war
}
}
}
Then i was left to fix it. So the correct was to do it was to add
evaluationDependsOn ":sub-project"
In the main build.gradle file. Now it knows to evaluate it. I remove the incorrect doLast{} block and now the task is no longer ignored.