Task based on Copy appears not to execute() - gradle

I have the following code in my build.gradle file:
task untarServer(type:Copy) {
from tarTree('build/libs/server.tar.gz')
into project.ext.tomcat + '../'
} << {
println 'Unpacked, waiting for tomcat to deploy wars ...'
sleep 10000
}
task deploy << {
tarball.execute()
untarServer.execute()
stopTomcat.execute()
startTomcat.execute()
}
Everything works great except untarServer, which appears not to run at all. Untar is based on an example from the documentation. Probably I've done something silly due to the late hour, but I'm missing it. How can I fix this? I have in the back of my mind that I could drop down to using ant.untar, but I'd like to do it the native gradle way if possible.
Edit: How do I know it's not running? because the println statement never shows up, the buld does not pause for 10 seconds, and the contents of the tarball do not show up in the "into" location.

I haven't seen the } << { syntax before; I'd change it to doLast { ... } inside the curly braces or untarServer << { (as a separate statement). Also, you should never call execute() on a task. It's totally unsupported and bad things will happen. Instead you should establish a task relationship (dependsOn, mustRunAfter, finalizedBy).

Related

Set a stage status in Jenkins Pipelines

Is there any way in a scripted pipeline to mark a stage as unstable but only show that stage as unstable without marking every stage as unstable in the output?
I can do something like this:
node()
{
stage("Stage1")
{
// do work (passes)
}
stage("Stage2")
{
// something went wrong, but it isn't catastrophic...
currentBuild.result = 'UNSTABLE'
}
stage("Stage3")
{
// keep going...
}
}
But when I run this, Jenkins marks everything as unstable... but I'd like the first and last stages to show green if possible and just the stage that had an issue to go yellow.
It's ok if the whole pipeline gets flagged unstable, but it might also be nice to have a later stage over ride that and set the final-result to pass if possible too.
This is now possible:
pipeline {
agent any
stages {
stage('1') {
steps {
sh 'exit 0'
}
}
stage('2') {
steps {
catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
sh "exit 1"
}
}
}
stage('3') {
steps {
sh 'exit 0'
}
}
}
}
In the example above, all stages will execute, the pipeline will be successful, but stage 2 will show as unstable. I use a declarative pipeline in the example, but it should work the same in a scripted pipeline.
As you might have guessed, you can freely change the buildResult and stageResult to any combination. You can even fail the build and continue the execution of the pipeline.
Just make sure your Jenkins is up to date, since this is a fairly new feature. Upgrade any plugins affected by bug JENKINS-39203, such as:
Pipeline Graph Analysis plugin (at least version 1.10 to mark single stages as 'UNSTABLE')
Pipeline Basic Steps plugin (at least version 2.18 to set stageResult in catchError)
Also worth mentioning are the warnError and unstable steps, released on Jul/2019, as part of the "Jenkins Pipeline Stage Result Visualization Improvements".
They are meant to allow you to mark a stage as unstable (this appears as an amber warning icon, and not a red error icon), while the rest of the build is still marked as successful.
Examples (lifted from the link above):
warnError acts like catchError, and changes the stage to have a warning if any part of the block fails:
warnError('Script failed!') {
sh('false')
}
unstable is a directive-style step, which you can use to mark the current stage as unstable:
try {
sh('false')
} catch (ex) {
unstable('Script failed!')
}
an elegant way I found to set only the stage result but not change the build result is this:
catchError(stageResult: 'UNSTABLE', buildResult: currentBuild.result) {
error 'example of throwing an error'
}
I know this question is a few years old but would like to offer an alternative for people who are coming across this problem. The accepted answer is close to what I needed, but the issue is that catchError does not allow for an alternate set of code to execute when an error occurs in its block like a try/catch does. I got around this in the following way:
stage('Stage 2') {
steps {
echo 'In stage 2'
script {
try {
echo 'In stage 2: try block'
sh 'python3 ./python/script.py'
}
catch(Exception e) {
echo 'In stage 2: catch block'
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
echo 'In stage 2: catchError block'
sh 'exit 1'
}
}
}
}
}
When my Python script raises an exception, whatever is in the catch block will execute per usual try/catch logic. Putting the catchError there as well and raising a bogus exception in it guarantees that my build and stage statuses will come out how I want (e.g. all stages with status = SUCCESS except for Stage 2, and a build status = UNSTABLE).
There's no question that this is an awkward workaround. However, the Jenkins developers insist (see here) that "To ensure consistency the FAILED state should always fail the pipeline."
My code snippet above is just simple proof of concept, but in my production code I have a legitimate need to fail a stage, yet mark the entire build as UNSTABLE. The noble intentions behind designing Jenkins declarative pipelines with so much rigor are admirable, but really inconvenient and unnecessary in my opinion.
Hopefully this workaround helps someone. If I'm missing something then I'm open to looking at a cleaner way of doing this.

What is the equivalent of an Ant taskdef in Gradle?

I've been struggling with this for a day and a half or so. I'm trying to replicate the following Ant concept in Gradle:
<target name="test">
...
<runexe name="<filename> params="<params>" />
...
</target>
where runexe is declared elsewhere as
<macrodef name="runexe" >
...
</macrodef>
and might also be a taskdef or a scriptdef i.e. I'd like to be able to call a reusable, pre-defined block of code and pass it the necessary parameters from within Gradle tasks. I've tried many things. I can create a task that runs the exe without any trouble:
task runexe(type: Exec){
commandLine 'cmd', '/c', 'dir', '/B'
}
task test(dependsOn: 'runexe') {
runexe {
commandLine 'cmd', '/c', 'dir', '/N', 'e:\\utilities\\'
}
}
test << {
println "Testing..."
// I want to call runexe here.
...
}
and use dependsOn to have it run. However this doesn't allow me to run runexe precisely when I need to. I've experimented extensively with executable, args and commandLine. I've played around with exec and tried several different variations found here and around the 'net. I've also been working with the free books available from the Gradle site.
What I need to do is read a list of files from a directory and pass each file to the application with some other arguments. The list of files won't be known until execution time i.e. until the script reads them, the list can vary and the call needs to be made repeatedly.
My best option currently appears to be what I found here, which may be fine, but it just seems that there should be a better way. I understand that tasks are meant to be called once and that you can't call a task from within another task or pass one parameters but I'd dearly like to know what the correct approach to this is in Gradle. I'm hoping that one of the Gradle designers might be kind enough to enlighten me as this is a question asked frequently all over the web and I'm yet to find a clear answer or a solution that I can make work.
If your task needs to read file names, then I suggest to use the provided API instead of executing commands. Also using exec will make it OS specific, therefore not necessarily portable on different OS.
Here's how to do it:
task hello {
doLast {
def tree = fileTree(dir: '/tmp/test/txt')
def array = []
tree.each {
array << it
print "${it.getName()} added to array!\n"
}
}
}
I ultimately went with this, mentioned above. I have exec {} working well in several places and it seems to be the best option for this use case.
To please an overzealous moderator, that means this:
def doMyThing(String target) {
exec {
executable "something.sh"
args "-t", target
}
}
as mentioned above. This provides the same ultimate functionality.

How do I force a reconfiguration of projects in Gradle?

I have a build.gradle file that calls some SVNKit stuff to svn export some directories that make up a Gradle multi-project.
I have a task dedicated to doing this that looks something like this:
task checkoutIntoDir() << {
mkdir 'dirForSvnProjects_2014_07_17_19_50' // timestamp not hard-coded ;)
// prompt for username/password
// run svn export which places projects in dirForSvnProjects_2014_07_17_19_50
}
with another GradleBuild task that depends on it:
task buildCheckedOutStuff(type: GradleBuild, dependsOn: checkoutIntoDir) {
dir = "dirForSvnProjects_2014_07_17_19_50/svnProjectIExported"
tasks = ['buildMyProj']
}
But it says task 'buildMyProj' not found in root project when it gets there. Now if I take out the task dependency checkoutIntoDir and run it on a directory that's there before I start the build, it works fine. I'm guessing I need to run some kind of "reconfiguration" to make the project aware of the new gradle project in dirForSvnProjects_2014_07_17_19_50?
I finally figured it out.
It was actually related to the way I was setting variables, not about Gradle.
I had a createDir task defined that set a variable that was defined (but not set) at the "root" level of the script. It looked something like this:
def myBuildDir
task createDir << {
def nowDate = String.format('%tY_%<tm_%<td_%<tH_%<tM',Calendar.instance)
myBuildDir= "_build_$nowDate"
mkdir myBuildDir
}
task checkoutIntoDir(dependsOn: createDir) << {
// prompt for username/password
// run svn export which places projects in myBuildDir
}
And as Perryn Fowler pointed out in the comments, any block that's not in a doLast (or the << shorthand)-type block will be run at configuration time when createDir was being run at runtime. Therefore the variable was not set for the buildCheckedOutStuff task.
So I just changed it to set the date at the root as well and it worked:
def nowDate = String.format('%tY_%<tm_%<td_%<tH_%<tM',Calendar.instance)
def eqipBuildDir = "_build_$nowDate"
task createDir << {
mkdir eqipBuildDir
}
That's what I get for leaving out pieces for brevity!

Synchronize directories with Gradle

How can I synchronize two directories after task execution? I can do it like this:
task syncDirs(type: Sync) {
...
}
task someTask {
doLast {
syncDirs.execute()
}
}
But method "execute" is internal and I have to avoid it.
Thanks for the answer in advance.
Depending on your exact needs, you can use syncDirs.dependsOn(someTask), or call the delete and copy methods inside someTask.doLast (that's how Sync is currently implemented).
task myTask << {
copy {
from 'src_dir'
into 'dst_dir'
include 'myfile.txt'
}
sync {
from "src_dir/foo"
into "dst_dir/bar"
}
}
In Gradle 1.10, you can do things like copy files and sync dirs all in a single task. I prefer this to having separate tasks for copying and syncing.
For syncing, the idea of doing a separate delete and copy, as suggested above, seems tedious. I'm glad I can call sync to do both.

Controlling Gradle task execution

In my build.gradle script, I have a lot of tasks, each depending on zero or more other tasks.
There are three 'main' tasks which can be called: moduleInstallation, backupFiles and restoreFiles.
Here's the question: I would like to be able to tell Gradle which tasks to execute and which don't need to execute. For example, when calling moduleInstallation, I want all depending tasks to execute (regardless of their UP-TO-DATE flag), but not the restore tasks. I've tried altering the phase in which the tasks get executed (e.g. config phase, execution phase,...) and a couple of other things, but all tasks just keep getting executed.
A solution I've thought of was just stating in the main tasks that, when this main task is called (f.e. moduleInstallation), we set the UP-TO-DATE flag of all non-related tasks to false, so they don't get executed. Is that possible?
EDIT: Here's an example:
When moduleInstallation is called (which depends on backupFiles), restoreFiles (which depends on restoreFromDate) is executed too.
First main action
task moduleInstallation << {
println "Hello from moduleInstallation"
}
task backupFiles {
doLast {
println "Hello from backupFiles"
}
}
Second main action
task restoreFiles {
println "Hello from restoreFiles"
}
task restoreFromDate {
println "Hello from restoreFromDate"
}
Dependencies:
moduleInstallation.dependsOn backupFiles
restoreFiles.dependsOn restoreFromDate
So when I type gradle moduleInstallation in the terminal, I get the following output:
Hello from restoreFromDate
Hello from restoreFiles
Hello from backupFiles
Hello from moduleInstallation
The second snippet has to use doLast (or its << shortcut) like the first snippet. Otherwise, the code is configuration code and will always be evaluated, no matter which tasks are eventually going to be executed. In other words, it's not the restoreFiles and restoreFromDate tasks that are being executed here (as one can tell from the bits of command line output that you don't show), but (only) their configuration code.
To better understand what's going on here (which is crucial for understanding Gradle), I recommend to study the Build Lifecycle chapter in the Gradle User Guide.

Resources