4

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?

  • A bit late, but did you get a solution to this, i.e. having errors in bash built-ins automatically detected? Thanks for letting me know 'while' is not covered by '-e'. One more reason to code defensively, i.e. `[[ -f $FILE ]]`, before using it. – akauppi Aug 01 '21 at 10:15

4 Answers4

1

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();
    }
niri9428480
  • 415
  • 4
  • 11
1

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
mcoolive
  • 3,805
  • 1
  • 27
  • 32
  • 1
    For clarity (and for careless readers like me): adding `-o pipefail` to the original question does not change its behaviour. One needs to turn it into a pipe. – akauppi Aug 01 '21 at 10:20
0

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
Yannoff
  • 367
  • 2
  • 9
0
[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
W4nn4Die
  • 11
  • 3
  • I think the poster's point is that it should never reach the `echo "echos after faulty while"` line, since they have a `set -xe` at the top; it should exit when the while loop fails. – Simon Rose Apr 09 '21 at 06:45