Reputation: 41
I run a Jenkins pipeline job with Groovy. The Groovy calls bash scripts for each step.
I want to fail the whole job when something in the way has errors.
For Groovy I use the returnStatus: true
.
For Bash I use set -e
.
But a bash script with set -e
, does not exit if, for example, a while
statement has errors. This is what should actually happen, according to the Linux manual page for 'set'.
I would like to know how to exit immediately in that scenario.
The script:
[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash
set -xe
FILE=commands.txt
echo "echos before while"
# Run the commands in the commands file
while read COMMAND
do
$COMMAND
done < $FILE
echo $?
echo "echos after faulty while"
Let's say 'commands.txt' doesn't exist. Running script:
[jenkins-user@jenkins ~]$ sh script.sh
echos before while
script.sh: line 13: commands.txt: No such file or directory
1
echos after faulty while
[jenkins-user@jenkins ~]$ echo $?
0
Although the while
statement returns exit code 1, the script continues and ends successfully, as checked right after, with echo $?
.
This is how I force the Groovy to fail, after a step with bash/python/etc command/script returns a none-zero exit code:
pipeline {
agent any
stages {
stage("A") {
steps {
script {
def rc = sh(script: "sh A.sh", returnStatus: true)
if (rc != 0) {
error "Failed, exiting now..."
}
}
}
}
}
}
First question, how can I make the SHELL script to fail when the while/if/etc statements have errors? I know I can use command || exit 1
but it doesn't seem elegant if I have dozens of statements like this in the script.
Second question, is my Groovy error handling correct? Can anyone suggest an event better way? Or maybe there is a Jenkins plugin/official way to do so?
Upvotes: 4
Views: 2999
Reputation: 4205
About the Bash script.
Your issue is that the fail redirection does not abort the bash script, despite the use of set -e
. I was surprised my-self. But it's my first disappointment about set -e
, so now I consider to not trust it and I abuse of stuff like $command || exit 1
...
Here you can do the following:
set -xe -o pipefail
cat $FILE | while read command; do $command ; done
But the whole loop should be simplified into:
bash $FILE
Upvotes: 1
Reputation: 11
[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash
set -xe
FILE=commands.txt
echo "echos before while"
# Run the commands in the commands file
while read COMMAND
do
$COMMAND
done < $FILE
echo $?
echo "echos after faulty while"
When yor perform a echo $?
after this script it will always be 0, because the last command was echo "echos after faulty while"
you can ad an exit 1
at the end of your script. In exit 1
the number 1 will be the error code, you can use other. So the script will be
[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash
set -xe
FILE=commands.txt
echo "echos before while"
# Run the commands in the commands file
while read COMMAND
do
$COMMAND
done < $FILE
echo $?
exit 1
Upvotes: 0
Reputation: 425
First question this link may be helpful Aborting a shell script if any command returns a non-zero value
Second question: You can improve your error handling using try and catch for exception handling.
try{
def rc = sh(script: "sh A.sh", returnStatus: true)
if (rc != 0) {
error "Failed, exiting now..."
}
}
catch (Exception er){
errorMessage = er.getMessage();
}
Upvotes: 1
Reputation: 374
Why don't you just use the while
exit code and return it? (See this modified version of your script, the last lines)
[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash
set -xe
FILE=commands.txt
echo "echos before while"
# Run the commands in the commands file
while read COMMAND
do
$COMMAND
done < $FILE
status=$?
echo "echos after faulty while"
exit $status
Upvotes: 0