don't fail jenkins build if execute shell fails
Asked Answered
R

14

174

As part of my build process, I am running a git commit as an execute shell step. However, if there are no changes in the workspace, Jenkins is failing the build. This is because git is returning an error code when there are no changes to commit. I'd like to either abort the build, or just mark it as unstable if this is the case. Any ideas?

Receivership answered 18/1, 2013 at 4:22 Comment(2)
Check if there is anything to commit, and only commit in those cases? #5139790Pollux
In a Pipeline job, if you want sh step to continue on failure use returnStatus: true (the exit code is returned if you need to evaluate it).Irena
D
281

To stop further execution when command fails:

command || exit 0

To continue execution when command fails:

command || true

Dehisce answered 9/9, 2014 at 13:13 Comment(9)
You don't need the || exit 0 in the first case, if command returns false the execution will stop. That said, the second option is very helpful!Vermicelli
@alfasin You don't understand the problem. OP doesn't want the Jenkins build to fail; ergo we must exit 0 because any non-zero exit code will fail the build.Dehisce
I see, in that case I would change the wording from: "To stop further execution when command fails:" to: "To stop further execution when command fails and mark Jenkins job as successful:".Vermicelli
Let's keep it professional please. You wrote: " it doesn't mark a job as successful" - I disagree: when you're doing command || exit 0 - if the command failed - it will indeed stop further execution, but it will also mark the job as successful.Vermicelli
@alfasin While I agree that Quolonel Questions snappy remark was unprofessional, he was right in what he said. "exit 0" will NOT mark the job successful. It will just mark the current build step successful. The job can still fail on one of the next build steps.Fledgling
@Fledgling you're right! I was dealing with jobs with only one step of "execute shell" hence the misunderstanding. Thanks for clarifying!Vermicelli
This is the fastest and easiest way of not having Jenkins fail a complete build, in other words, a non-critical build step, so you have my +1. It is actually really stupid that Jenkins does not offer this functionality by default. Good defaults are one thing, offering good alternatives (OOTB) another.Shaughnessy
Thanks this worked! This is especially useful for the "Execute shell on remote host using ssh" plugin feature since you are not able to use /bin/bash +e to not fail on error. I also like the idea I get to choose which commands don't fail the build.Beeson
Please clarify the "command || other" part goes inside the argument that's passed to the shell, i.e. it should be sh "command || true", not sh "command" || true.Soulsearching
L
109

Jenkins is executing shell build steps using /bin/sh -xe by default. -x means to print every command executed. -e means to exit with failure if any of the commands in the script failed.

So I think what happened in your case is your git command exit with 1, and because of the default -e param, the shell picks up the non-0 exit code, ignores the rest of the script and marks the step as a failure. We can confirm this if you can post your build step script here.

If that's the case, you can try to put #!/bin/sh so that the script will be executed without option; or do a set +e or anything similar on top of the build step to override this behavior.


Edited: Another thing to note is that, if the last command in your shell script returns non-0 code, the whole build step will still be marked as fail even with this setup. In this case, you can simply put a true command at the end to avoid that.

Another related question

Lati answered 11/2, 2015 at 7:0 Comment(1)
This actually solved my problem with Jenkins failing even when trying to suppress errors with 2>/dev/null. Thanks!Wilda
M
44

If there is nothing to push git returns exit status 1. Execute shell build step is marked as failed respectively. You can use OR statement || (double pipe).

git commit -m 'some messasge' || echo 'Commit failed. There is probably nothing to commit.'

That means, execute second argument if first failed (returned exit status > 0). Second command always returns 0. When there is nothing to push (exit status 1 -> execute second command) echo will return 0 and build step continues.

To mark build as unstable you can use post-build step Jenkins Text Finder. It can go through console output, match pattern (your echo) and mark build as unstable.

Megilp answered 17/10, 2013 at 10:37 Comment(0)
T
33

There is another smooth way to tell Jenkins not to fail. You can isolate your commit in a build step and set the shell to not fail:

set +e
git commit -m "Bla."
set -e
Trombone answered 4/6, 2014 at 8:58 Comment(1)
Make sure to add set -e after the command that you want to run irrespective of exit code. Otherwise, you may end up executing commands you don't intend to. I wanted to handle the error myself, so I did something like: ` set +e commit -m "bla" EXIT_CODE="${?}" set -e # handle exit code logic `Undercut
S
22

This answer is correct, but it doesn't specify the || exit 0 or || true goes inside the shell command. Here's a more complete example:

sh "adb uninstall com.example.app || true"

The above will work, but the following will fail:

sh "adb uninstall com.example.app" || true

Perhaps it's obvious to others, but I wasted a lot of time before I realized this.

Soulsearching answered 29/6, 2020 at 21:11 Comment(0)
A
15

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script

if you include a returnStatus: true property, then the shell return is ignored.

Avernus answered 4/7, 2018 at 16:17 Comment(1)
this is the real answer, a full example would look like: def rc = sh(script: "git commit", returnStatus: true) ; echo "git commit return code was: ${rc} moving on"Lakia
R
10

I was able to get this working using the answer found here:

How to git commit nothing without an error?

git diff --quiet --exit-code --cached || git commit -m 'bla'
Receivership answered 18/1, 2013 at 18:6 Comment(2)
What the above does is: "Do git diff command, and if that fails, do git commit command. Basically, it only does the commit, if the git diff found something to commit. However @jwernerny answer was correct that you should be able to add exit 0 as the last statement to any script to make Jenkins treat it as success. I can think of one scenario where this would fail if you were doing Linux shell step, but in Batch this should always work.Satiable
@Receivership Jenkins is executing shell build steps using /bin/sh -xe by default as mentioned here (in the middle). So you can try to put #!/bin/bash or do a set +e on top of the build step to override this behavior, which will continue the rest of the step even one command inside exit with non-0 codeLati
L
8

Jenkins determines the success/failure of a step by the return value of the step. For the case of a shell, it should be the return of the last value. For both Windows CMD and (POSIX) Bash shells, you should be able to set the return value manually by using exit 0 as the last command.

Lark answered 18/1, 2013 at 14:55 Comment(4)
this doesn't seem to work for an 'execute windows bat' that has 2 lines: git commit -m "message" exit 0Receivership
@Receivership I use exit 0 with "execute windows batch command" in multiple builds on my Windows Jenkins install, and it works as expected. Something else must be going on. Could you post the relevant part of the console log?Lark
are you using it with git commit -m "blah" in your first step? I tried creating a bat script on the machine manually, and put an echo and an exit 0 after the git command. Neither of the other commands are run when there is nothing to commit...Receivership
See answer from @xiawei. The default behavior of Jenkins it to execute a shell with #!/bin/sh -xv which results in stopping the script if any error is encountered.Beaverette
A
8

On the (more general) question in title - to prevent Jenkins from failing you can prevent it from seeing exit code 1. Example for ping:

bash -c "ping 1.2.3.9999 -c 1; exit 0"

And now you can e.g. get output of ping:

output=`bash -c "ping 1.2.3.9999 -c 1; exit 0"`

Of course instead of ping ... You can use any command(s) - including git commit.

Assistant answered 20/11, 2013 at 11:5 Comment(0)
C
6

You can use the Text-finder Plugin. It will allow you to check the output console for an expression of your choice then mark the build as Unstable.

Crisper answered 18/1, 2013 at 9:11 Comment(1)
this looked promising, but for some reason it kept failing the build.Receivership
C
6

For multiple shell commands, I ignores the failures by adding:

set +e commands true

enter image description here

Coup answered 11/3, 2019 at 10:31 Comment(1)
I discourage unsetting -e in general. If you want to ignore some specific command's return value, you can add "|| true" or something more meaningful returning true, such as: stop-service.sh || echo Service was already downLetitialetizia
L
4

If you put this commands into shell block:

false
true

your build will be marked as fail ( at least 1 non-zero exit code ), so you can add (set +e) to ignore it:

set +e
false
true

will not fail. However, this will fail even with the (set +e) in place:

set +e
false

because the last shell command must exit with 0.

Ludmilla answered 30/11, 2016 at 19:35 Comment(0)
C
2

The following works for mercurial by only committing if there are changes. So the build only fails if the commit fails.

hg id | grep "+" || exit 0
hg commit -m "scheduled commit"
Capo answered 5/2, 2013 at 18:18 Comment(0)
P
1

Another one answer with some tips, can be helpful for somebody:

remember to separate your commands with the following rule:

command1 && command2 - means, that command2 will be executed, only if command1 success

command1 ; command2 - means, that command 2 will be executed despite on result of command1

for example:

String run_tests = sh(script: "set +e && cd ~/development/tests/ && gmake test ;set -e;echo 0 ", returnStdout: true).trim()
println run_tests 

will be executed successfully with set -e and echo 0 commands if gmake test failed (your tests failed), while the following code snipped:

String run_tests = sh(script: "set +e && cd ~/development/tests/ && gmake test && set -e && echo 0 ", returnStdout: true).trim()
println run_tests 

a bit wrong and commands set -e and echo 0 in&& gmake test && set -e && echo 0 will be skipped, with the println run_tests statement, because failed gmake test will abort the jenkins build. As workaround you can switch to returnStatus:true, but then you will miss the output from your command.

Poyang answered 11/3, 2019 at 12:24 Comment(2)
context is everything - and if you don't want to capture console output, then you can even make that sh() function return (instead of failing for a non-0) the status code. sometimes you want both, then you might want to pipe the command outputs to a file - or hope for some simple solution to do so with the status code. ;-)Szymanski
@AlexanderStohr true fact! Can't disagreePoyang

© 2022 - 2024 — McMap. All rights reserved.