12

When I run an Execute shell build step to execute a script and that script returns 0, Jenkins flags the build as SUCCESS, otherwise it flags it as FAILURE which is the expected default behaviour as 0 means no errors and any other value represents an error.

Is there a way to mark a build as SUCCESS only if the return value matches a specific value other than 0 (e.g. 1,2,3...)?

PS: in case you're wondering why I'm looking for that, this will allow me to perform unit testing of Jenkins itself as my scripts are written to return different exit values depending on various factors, thus allowing me to expect certain values depending on certain setup mistakes and making sure my whole Jenkins integration picks up on those.

Max
  • 12,794
  • 30
  • 90
  • 142

6 Answers6

19

Alright, I went on IRC #jenkins and no-one new about a plugin to set a particular job status depending on a particular exit code :( I managed to do what I wanted by creating an Execute shell step with the following content:

bash -c "/path/to/myscript.sh; if [ "\$?" == "$EXPECTED_EXIT_CODE" ]; then exit 0; else exit 1; fi"

-Running the script under bash -c allows catching the exit code and prevents Jenkins from stopping build execution when that exit code is different than 0 (which it normally does).

-\$? is interpreted as $? after the script execution and represents its exit code.

-$EXPECTED_EXIT_CODE is one of my job parameters which defines the exit code I'm expecting.

-The if statement simply does the following: if I get the expected exit code, exit with 0 so that the build is marked as SUCCESS, else exit with 1 so that the build is marked as FAILURE.

Max
  • 12,794
  • 30
  • 90
  • 142
  • Note there is no need to call 'bash', as you are already in a shell. This should work just as well: `/path/to/myscript.sh; if [ "$?" == "$EXPECTED_EXIT_CODE" ]; then exit 0; else exit 1; fi` (can even replace the ';'s with new-lines like in any other shell-script). – Gonen Nov 30 '12 at 15:53
  • 1
    First I tried what you suggested but it didn't work: in my setup (which is a default install) as soon as jenkins detects the exit code from the script being different than 0 it stops and doesn't evaluate the other commands, that's because the `Execute shell` step is executed with the `-e` switch by Jenkins which tells the bash interpreter to stop on the first error. `Is there a way to prevent jenkins from usign -e?` – Max Nov 30 '12 at 16:29
  • I currently have a Windows-based config so cannot confirm, but AFAIK , Jenkins only checks the **result of the last command** in each _Execute shell_ block. (Did you set it in **two** _Execute shell_ blocks, maybe?) – Gonen Dec 02 '12 at 07:51
  • Sounds like a bug, and you've got a workaround... I'll get me a linux and check. – Gonen Dec 04 '12 at 21:10
  • 4
    jenkins by default runs shell with set -xe so that it exits at the first line of code that produces anything other than an exit code of 0. wrap your sh code wtih set +e and set -e to bypass this. – stanleykylee Feb 24 '16 at 23:18
  • @Max What exactly is in 'myscript.sh'? May you please help to show the contents? – superloopnetworks Jan 04 '22 at 19:26
  • @Max Also, is $EXPECTED_EXIT_CODE a list of exit code numbers stored as an env. variable? – superloopnetworks Jan 04 '22 at 21:40
  • @superloopnetworks: it's a job parameter coming from Jenkins, as mentioned in my post – Max Jan 05 '22 at 09:15
  • @Max: I'm sorry, I missed that... Can $EXPECTED_EXIT_CODE be in the form of a list? How do you store multiple exit codes deemed as successful? ex. 0,1,2,3... What's myscript.sh? What's inside that file? Is that just a task you want to run? I'm trying to basically achieve what you have, but in pipeline format. – superloopnetworks Jan 05 '22 at 14:17
5
/path/to/myscript.sh || if [ "$?" == "$EXPECTED_EXIT_CODE" ]; then continue; else exit 1; fi

I would use continue instead of exit 0 in case you have other items below that you need to run through.

demongolem
  • 9,474
  • 36
  • 90
  • 105
Bruce Wayne
  • 51
  • 1
  • 1
  • This was my case with Jenkins Text Finder plugin since that bastard always defaulted to Failure even if "exit 0" was used. – HX_unbanned Jul 14 '16 at 05:41
3

Can handle it via the Text-finder Plugin:

  • Have your script print the exit-code it is about to exit with, like:
    Failed on XXX - Exiting with RC 2

  • Use the Text-finder Plugin to catch that error-message and mark the build as 'Failed' or 'Unstable',
    for example, if you decide RC 2, 3 and 4 should mark the build as 'Unstable', look for text in this pattern:
    Exiting with RC [2-4].
Gonen
  • 4,005
  • 1
  • 31
  • 39
  • That will work (although I will set the jobs in the opposite fashion: if I get the error I want, then I mark the job as `SUCCESS`, the point being to create several jobs in known failing conditions and make sure the scripts report those failures, and if they do, consider success). I just wish there was a similar plugin which would inspect the return code instead of the output, as I somehow trust the return code more, but if I don't find it the `Text-finder` plugin will do the trick. Many thanks. – Max Nov 26 '12 at 12:34
  • Only problem, as stated by the documentation: `"The search is always performed, even on builds which returned a non-zero exit status, but the reclassification only applies to builds which returned an overall exit status of zero"` which means I have to force my scripts not to return 0 even on failure for this plugin to work :( which I obviously don't want because these same scripts will be used for production jobs and must return proper exit codes. – Max Nov 26 '12 at 12:52
  • Yes, it assumes that a non-zero return-value is an error, before parsing the log. – Gonen Nov 28 '12 at 11:39
1

Create a wrapper for your shell script. Have that wrapper execute your tests and then set the resturn value according to whatever criteria you want.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    Thought about it but don't like the idea as it will add another layer (and potential source of problems) between Jenkins and the scripts I normally run, thus defeating the reason why I'm making these tests in the first place. I have been looking for a plugin that would allow me to do what I want but haven't found one yet :( – Max Nov 25 '12 at 14:14
1

I do it like this:

set +e
./myscript.sh
rc="$?"
set -e
if [ "$rc" == "$EXPECTED_CODE_1" ]; then
    #...actions 1 (if required)
    exit 0
elif [ "$rc" == "$EXPECTED_CODE_2" ]; then
    #...actions 2 (if required)
    exit 0
else
    #...actions else (if required)
    exit "$rc"
fi
echo "End of script" #Should never happen, just to indicate there's nothing further

Here +e is to avoid default Jenkins behavior to report FAILURE on any sneeze during your script execution. Then get back with -e.

So that you can handle your exit code as appropriate, else eventually FAIL with the returned code.

RAM237
  • 903
  • 11
  • 17
0
robocopy "srcDir" "destDir" /"copyOption" if %ERRORLEVEL% LEQ 2 exit 0

If robocopy exit code is less than or equal to 2 then it will exit successfully.

Robocopy Exit Codes:

0×00   0       No errors occurred, and no copying was done.
               The source and destination directory trees are completely synchronized. 

0×01   1       One or more files were copied successfully (that is, new files have arrived).

0×02   2       Some Extra files or directories were detected. No files were copied
               Examine the output log for details. 

0×04   4       Some Mismatched files or directories were detected.
               Examine the output log. Housekeeping might be required.

0×08   8       Some files or directories could not be copied
               (copy errors occurred and the retry limit was exceeded).
               Check these errors further.

0×10  16       Serious error. Robocopy did not copy any files.
               Either a usage error or an error due to insufficient access privileges
               on the source or destination directories.
Ankit Patel
  • 321
  • 2
  • 8