Nicht fehlschlagen Jenkins Build, wenn Execute Shell fehlschlägt

132

Als Teil meines Erstellungsprozesses führe ich ein Git-Commit als Ausführungs-Shell-Schritt aus. Wenn jedoch keine Änderungen im Arbeitsbereich vorgenommen werden, schlägt Jenkins die Erstellung fehl. Dies liegt daran, dass git einen Fehlercode zurückgibt, wenn keine Änderungen festgeschrieben werden müssen. Ich möchte den Build entweder abbrechen oder ihn einfach als instabil markieren, wenn dies der Fall ist. Irgendwelche Ideen?

Ben
quelle
Überprüfen Sie, ob etwas festgeschrieben werden muss, und legen Sie nur in diesen Fällen fest? stackoverflow.com/questions/5139290/…
Anders Lindahl

Antworten:

210

So stoppen Sie die weitere Ausführung, wenn der Befehl fehlschlägt:

command || exit 0

So setzen Sie die Ausführung fort, wenn der Befehl fehlschlägt:

command || true

Quolonel Fragen
quelle
12
Sie brauchen das || exit 0im ersten Fall nicht. Wenn commandfalse zurückgegeben wird, wird die Ausführung gestoppt. Die zweite Option ist jedoch sehr hilfreich!
Alfasin
20
@alfasin Du verstehst das Problem nicht. OP möchte nicht, dass der Jenkins-Build fehlschlägt. Ergo müssen wir, exit 0weil jeder Exit-Code ungleich Null den Build fehlschlagen wird.
Quolonel Fragen
1
Ich sehe, in diesem Fall würde ich den Wortlaut ändern von: "Weitere Ausführung stoppen, wenn Befehl fehlschlägt:" zu: "Weitere Ausführung stoppen, wenn Befehl fehlschlägt und Jenkins Job als erfolgreich markieren:".
Alfasin
1
@alfasin Obwohl ich damit einverstanden bin, dass die bissige Bemerkung von Quolonel Questions unprofessionell war, hatte er Recht mit dem, was er sagte. "exit 0" markiert den Job NICHT als erfolgreich. Es wird nur der aktuelle Build-Schritt als erfolgreich markiert. Der Job kann bei einem der nächsten Erstellungsschritte immer noch fehlschlagen.
Noamik
1
Danke das hat funktioniert! Dies ist besonders nützlich für die Plugin-Funktion "Shell auf Remote-Host mit ssh ausführen", da Sie / bin / bash + e nicht verwenden können, um bei Fehlern nicht fehlzuschlagen. Ich mag auch die Idee, zu entscheiden, welche Befehle den Build nicht fehlschlagen lassen.
Leeman24
80

Jenkins führt /bin/sh -xestandardmäßig Shell-Build-Schritte aus. -xbedeutet, jeden ausgeführten Befehl zu drucken. -ebedeutet, mit einem Fehler zu beenden, wenn einer der Befehle im Skript fehlgeschlagen ist.

Ich denke also, was in Ihrem Fall passiert ist, ist Ihr git-Befehl exit mit 1, und aufgrund des Standardparameters -enimmt die Shell den Exit-Code ungleich 0 auf, ignoriert den Rest des Skripts und markiert den Schritt als Fehler. Wir können dies bestätigen, wenn Sie Ihr Build-Step-Skript hier veröffentlichen können.

Wenn dies der Fall ist, können Sie versuchen, #!/bin/shso zu setzen , dass das Skript ohne Option ausgeführt wird. oder führen Sie zusätzlich set +ezum Build-Schritt einen oder einen ähnlichen Vorgang aus, um dieses Verhalten zu überschreiben.


Bearbeitet: Eine andere zu beachtende Sache ist, dass, wenn der letzte Befehl in Ihrem Shell-Skript Nicht-0-Code zurückgibt , der gesamte Erstellungsschritt auch bei diesem Setup als fehlgeschlagen markiert wird. In diesem Fall können Sie einfach einen echoBefehl am Ende einfügen, um dies zu vermeiden.

Eine andere verwandte Frage

Xiawei Zhang
quelle
41

Wenn es nichts zu pushen gibt, gibt git den Exit-Status zurück. 1. Der Shell-Build-Schritt ausführen wird als fehlgeschlagen markiert. Sie können die OR-Anweisung || verwenden (Doppelrohr).

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

Das heißt, führen Sie das zweite Argument aus, wenn das erste fehlgeschlagen ist (zurückgegebener Exit-Status> 0). Der zweite Befehl gibt immer 0 zurück. Wenn nichts zu drücken ist (Exit-Status 1 -> zweiten Befehl ausführen), gibt das Echo 0 zurück und der Erstellungsschritt wird fortgesetzt.

Um Build als instabil zu markieren, können Sie den Jenkins Text Finder nach dem Build verwenden. Es kann die Konsolenausgabe durchlaufen, das Muster (Ihr Echo) abgleichen und den Build als instabil markieren.

ecervena
quelle
27

Es gibt noch eine andere Möglichkeit, Jenkins zu sagen, dass er nicht scheitern soll. Sie können Ihr Commit in einem Build-Schritt isolieren und die Shell so einstellen, dass sie nicht fehlschlägt:

set +e
git commit -m "Bla."
set -e
Joecks
quelle
2
Stellen Sie sicher, set -edass Sie nach dem Befehl, den Sie ausführen möchten, unabhängig vom Exit-Code hinzufügen . Andernfalls führen Sie möglicherweise Befehle aus, die Sie nicht beabsichtigen. Ich wollte den Fehler selbst behandeln, also tat ich etwas wie: `set + e commit -m" bla "EXIT_CODE =" $ {?} "Set -e # handle Exit-Code-
Logik`
8

Jenkins bestimmt den Erfolg / Misserfolg eines Schritts anhand des Rückgabewerts des Schritts. Für den Fall einer Shell sollte dies die Rückgabe des letzten Werts sein. Sowohl für Windows CMD- als auch für (POSIX) Bash-Shells sollten Sie in der Lage sein, den Rückgabewert manuell festzulegen, indem Sie exit 0als letzten Befehl verwenden.

jwernerny
quelle
Dies scheint nicht zu funktionieren für einen 'Windows Fledermaus ausführen', der 2 Zeilen hat: git commit -m "message" exit 0
Ben
@Ben Ich verwende exit 0mit "Windows-Batch-Befehl ausführen" in mehreren Builds meiner Windows Jenkins-Installation und es funktioniert wie erwartet. Es muss noch etwas los sein. Könnten Sie den relevanten Teil des Konsolenprotokolls veröffentlichen?
Jwernerny
Verwenden Sie es mit git commit -m "blah" in Ihrem ersten Schritt? Ich habe versucht, manuell ein Bat-Skript auf dem Computer zu erstellen, und nach dem Befehl git ein Echo und eine Exit-0 eingefügt. Keiner der anderen Befehle wird ausgeführt, wenn nichts festgeschrieben werden muss ...
Ben
Siehe Antwort von @xiawei. Das Standardverhalten von Jenkins besteht darin, eine Shell auszuführen, mit #!/bin/sh -xvder das Skript gestoppt wird, wenn ein Fehler auftritt.
Steven der leicht amüsierte
8

Ich konnte dies mit der hier gefundenen Antwort zum Laufen bringen:

Wie kann man nichts ohne Fehler festschreiben?

git diff --quiet --exit-code --cached || git commit -m 'bla'
Ben
quelle
1
Was das Obige tut, ist: " git diffBefehl ausführen , und wenn dies fehlschlägt, git commitBefehl git diffausführen . Grundsätzlich wird das Festschreiben nur ausgeführt, wenn etwas gefunden wurde, das festgeschrieben werden soll. Die Antwort von @jwernerny war jedoch korrekt, die Sie exit 0als letzte Anweisung hinzufügen sollten Ich kann mir ein Szenario vorstellen, in dem dies fehlschlagen würde, wenn Sie einen Linux-Shell-Schritt ausführen würden, aber in Batch sollte dies immer funktionieren.
Slav
@Ben Jenkins führt Shell-Build-Schritte /bin/sh -xestandardmäßig aus, wie hier erwähnt (in der Mitte). Sie können also versuchen, #!/bin/basheinen set +eSchritt über den Build-Schritt zu setzen oder zu tun , um dieses Verhalten zu überschreiben.
Dadurch
8

Bei der (allgemeineren) Frage im Titel: Um zu verhindern, dass Jenkins fehlschlägt, können Sie verhindern, dass der Exit-Code 1 angezeigt wird. Beispiel für Ping:

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

Und jetzt können Sie zB Ping ausgeben:

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

Natürlich ping ...können Sie stattdessen auch beliebige Befehle verwenden - einschließlich git commit.

Nux
quelle
6

Sie können das Text-Finder-Plugin verwenden . Sie können die Ausgabekonsole auf einen Ausdruck Ihrer Wahl überprüfen und dann den Build als markieren Unstable.

jphuynh
quelle
Das sah vielversprechend aus, aber aus irgendeinem Grund schlug der Build immer wieder fehl.
Ben
4

Bei mehreren Shell-Befehlen ignoriere ich die Fehler, indem ich Folgendes hinzufüge:

set +e commands true

Geben Sie hier die Bildbeschreibung ein

Megha
quelle
Ich rate davon ab, -e im Allgemeinen zu deaktivieren. Wenn Sie den Rückgabewert eines bestimmten Befehls ignorieren möchten, können Sie "|| true" oder eine aussagekräftigere Rückgabe von true hinzufügen, z. B.: Stop-service.sh || Echo Service war bereits
Raúl Salinas-Monteagudo
3

Wenn Sie diese Befehle in den Shell-Block einfügen:

false
true

Ihr Build wird als fehlgeschlagen markiert (mindestens 1 Exit-Code ungleich Null). Sie können also hinzufügen (set + e), um ihn zu ignorieren:

set +e
false
true

wird nicht scheitern. Dies schlägt jedoch auch dann fehl, wenn (set + e) ​​vorhanden ist:

set +e
false

weil der letzte Shell-Befehl mit 0 beendet werden muss.

chenchuk
quelle
2

Das Folgende funktioniert für mercurial, indem es nur festgeschrieben wird, wenn es Änderungen gibt. Der Build schlägt also nur fehl, wenn das Commit fehlschlägt.

hg id | grep "+" || exit 0
hg commit -m "scheduled commit"
Shaun Lebron
quelle
0

Eine andere Antwort mit einigen Tipps kann für jemanden hilfreich sein:

Denken Sie daran, Ihre Befehle mit der folgenden Regel zu trennen :

Befehl1 && Befehl2 - bedeutet, dass Befehl2 nur ausgeführt wird, wenn Befehl1 erfolgreich ist

Befehl1 ;Befehl2 - bedeutet, dass Befehl 2 trotz des Ergebnisses von Befehl1 ausgeführt wird

beispielsweise:

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

wird erfolgreich ausgeführt mit set -eund echo 0Befehle, wenn dies gmake testfehlschlägt (Ihre Tests sind fehlgeschlagen), während der folgende Code abgeschnitten wurde:

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

Ein bisschen falsch und Befehle set -eund echo 0In && gmake test && set -e && echo 0werden mit der println run_testsAnweisung übersprungen , da gmake testein Fehlschlagen den Jenkins-Build abbricht. Als Problemumgehung können Sie zu wechseln returnStatus:true, aber dann werden Sie die Ausgabe Ihres Befehls verpassen.

Sysanin
quelle
0

Diese Antwort ist korrekt, gibt jedoch nicht das || exit 0oder || truegeht in den Shell-Befehl ein . Hier ist ein vollständigeres Beispiel:

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

Das Obige wird funktionieren, aber das Folgende wird fehlschlagen:

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

Vielleicht ist es für andere offensichtlich, aber ich habe viel Zeit verschwendet, bevor ich das realisiert habe.

Big McLargeHuge
quelle