51

I am writing a bash script to automate the build process. There are two major build blocks, one is an ant task and one is a plain old mvn clean install. I want to do something when there is build error coming from either of this two build processes.

The problem is, these builds will contain test failures or errors from time to time, but the end result is successful. And I believe that the status code ($?) return by these processes should be 0 no matter the build fail or succeed, I could be wrong.

So what is the best way for my script to detect the end result (build fail/succeed) without catching the false info during the mid build (test errors, etc) from them?

zappee
  • 20,148
  • 14
  • 73
  • 129
fei
  • 2,224
  • 9
  • 31
  • 36
  • 2
    Tools should return proper exit statuses. – derobert Sep 03 '09 at 18:30
  • i'm actually not sure what the exit status for ant/maven is, i just assume they will return 0 even the build fail. so are you saying they will return non-zero value when the build fail? that will make my life much easier. – fei Sep 03 '09 at 18:56
  • If your tests sometimes pass and sometimes fail and you don't care either way, why bother running them as part of your build? – Programming Guy May 29 '14 at 05:42
  • 3
    This is one of several ways maven ignores Unix philosophy and makes scripting difficult. (the other being printing a load of garbage to the console when nothing is wrong - maven diarrhea as I call it). Using maven 3 instead of 2 does nothing. – Sridhar Sarnobat Feb 07 '17 at 23:15
  • Haha - maven meaning "the stomach" in my first language! – nsandersen Mar 29 '20 at 21:47

6 Answers6

62
mvn clean test
if [[ "$?" -ne 0 ]] ; then
  echo 'could not perform tests'; exit $rc
fi
  • $? is a special shell variable that contains the exit code (whether it terminated successfully, or not) of the most immediate recently executed command.
  • -ne stands for "not equal". So here we are testing if the exit code from mvn clean is not equal to zero.
Renaud
  • 16,073
  • 6
  • 81
  • 79
  • 6
    It would be a lot better if you could elaborate more on this answer. How and why does this answer the question better than the other answers? – nietonfir May 07 '14 at 20:29
  • 1
    I like this answer best. I googled how to handle error codes from mvn in a bash script and Renaud's answer fits the bill perfectly. I suspect Fei ended up using a technique much like this after discovering that mvn will return a non zero code for test failures. – Programming Guy May 29 '14 at 05:45
  • Almost perfect - but I would either use quotes, if you really want to make that string comparison (see https://www.gnu.org/software/bash/manual/bashref.html / search for "=="), or "-ne", which is the comparison operator for (unquoted) integers. – cslotty Jan 27 '16 at 10:18
  • 4
    Here you find a similar answer but this one has the syntax explained: http://stackoverflow.com/questions/13651723/mvn-in-bash-script-if-statement/13651804#13651804 – Ben Nov 24 '16 at 09:51
11

There are a few issues against Maven 2 returning incorrect return codes (i.e. always returning 0). Notably MNG-3651 that was fixed in Maven 2.0.9.

In older versions, mvn.bat ended with this line:

exit /B %ERROR_CODE%

From Maven 2.0.9 onwards, the last line was changed to this:

cmd /C exit /B %ERROR_CODE%

So a non-0 return code is returned if the build fails. In the case of a build ERROR the return code is 1. If you are unable to upgrade to 2.0.9+, you could consider modifying mvn.bat as above to return the correct code.

riQQ
  • 9,878
  • 7
  • 49
  • 66
Rich Seller
  • 83,208
  • 23
  • 172
  • 177
9

Correct solution for unix/linux:

mvn clean install
rc=$?
if [ $rc -ne 0 ] ; then
  echo Could not perform mvn clean install, exit code [$rc]; exit $rc
fi

The "if" statement itself is a command and if it is successful, it will reset the $? variable to 0. Same goes for echo. So, you have to use an intermediary local var, for example $rc to store the return code from "mvn clean install", then it can be passed to the "exit" command as well.

PrecisionLex
  • 801
  • 11
  • 26
5

According to the Ant manual:

the ant start up scripts (in their Windows and Unix version) return the return code of the java program. So a successful build returns 0, failed builds return other values.

Maven also returns a non-zero exit code on error. Here's a link showing how to interrogate this status using the Maven Invocation API.

So it seems to me that you should be able to explicitly handle the return codes in your script . Presumably you can ignore error codes relating to tests etc. if those are not a concern to you.

exec error codes in Ant are operating system-specific. These may help you:

martin clayton
  • 76,436
  • 32
  • 213
  • 198
ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
3

Here is exactly what I do to get the result you want.

    <exec executable="${env.M2_HOME}/bin/mvn" dir="${basedir}"
          failonerror="true" osfamily="unix">
        <arg value="-DskipTests=${argSkipTests}"/>
        <arg value="-Doffline=${argOffline}"/>
        <arg line="${projectsLine}"/>
        <arg line="${resumeFromLine}"/>
        <arg line="${alsoMakeLine}"/>
        <arg line="${alsoMakeDependentsLine}"/>
        <arg line="${commandsLine}"/>
    </exec>
codefinger
  • 10,088
  • 7
  • 39
  • 51
3

There's a command built-in to bash which performs exactly this.

# exit when any command fails
set -e

I put this at the top of my bash scripts, which I copied from this excellent resource.

# keep track of the last executed command
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG

# echo an error message before exiting
trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT

Will
  • 877
  • 11
  • 25