Wie kann ich die Ausgabe eines Shell-Befehls ausführen, der mit einer Variablen aus Jenkinsfile (groovy) ausgeführt wird?

213

Ich habe so etwas in einer Jenkins-Datei (Groovy) und möchte den Standard- und den Exit-Code in einer Variablen aufzeichnen, um die Informationen später zu verwenden.

sh "ls -l"

Wie kann ich das tun, zumal es den Anschein hat, dass Sie keinen wirklich groovigen Code innerhalb von ausführen können Jenkinsfile?

Sorin
quelle

Antworten:

390

Mit der neuesten Version des Pipeline- shSchritts können Sie Folgendes tun:

// Git committer email
GIT_COMMIT_EMAIL = sh (
    script: 'git --no-pager show -s --format=\'%ae\'',
    returnStdout: true
).trim()
echo "Git committer email: ${GIT_COMMIT_EMAIL}"

Ein weiteres Feature ist die returnStatusOption.

// Test commit message for flags
BUILD_FULL = sh (
    script: "git log -1 --pretty=%B | grep '\\[jenkins-full]'",
    returnStatus: true
) == 0
echo "Build full flag: ${BUILD_FULL}"

Diese Optionen wurden aufgrund dieses Problems hinzugefügt .

Siehe offizielle Dokumentation zum shBefehl.

G. Roggemans
quelle
11
Sieht so aus, als wäre es jetzt dokumentiert -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/…
zot24
Funktioniert bei mir jedoch nicht mit dem Präfix "vars". Wenn ich nur GIT_COMMIT_EMAIL als Variablennamen ohne Präfix verwende, ist alles in Ordnung.
Bastian Voigt
Bitte helfen Sie mir für stackoverflow.com/questions/40946697/…
Jitesh Sojitra
6
Wenn ich eine deklarative Jenkins-Dateisyntax verwende, funktioniert dies nicht. Die Fehlermeldung lautet:WorkflowScript: 97: Expected a step @ line 97, column 17.
Wrench
16
Es scheint, dass dies nur innerhalb eines scriptSchrittblocks funktioniert . jenkins.io/doc/book/pipeline/syntax/#declarative-steps
Messingaffe
51

Die aktuelle Pipeline-Version unterstützt nativ returnStdoutund returnStatus, wodurch die Ausgabe oder der Status von sh/ batstep abgerufen werden kann.

Ein Beispiel:

def ret = sh(script: 'uname', returnStdout: true)
println ret

Eine offizielle Dokumentation .

luka5z
quelle
Kann mir jemand bei stackoverflow.com/questions/40946697/… helfen ? Danke im Voraus!
Jitesh Sojitra
2
Die Anweisungen sind in einem script { }Schritt zu verpacken .
X-Yuri
40

Die schnelle Antwort lautet:

sh "ls -l > commandResult"
result = readFile('commandResult').trim()

Ich denke, es gibt eine Feature-Anfrage, um das Ergebnis von sh step zu erhalten, aber soweit ich weiß, gibt es derzeit keine andere Option.

EDIT: JENKINS-26133

EDIT2: Nicht ganz sicher seit welcher Version, aber sh / bat Schritte können jetzt die Standardausgabe zurückgeben, einfach:

def output = sh returnStdout: true, script: 'ls -l'
vehovmar
quelle
1
Zu Ihrer Information: Bat-Schritte geben den ausgeführten Befehl wieder, sodass Sie Bat-Befehle mit @ starten müssen, um nur die Ausgabe zu erhalten (z. B. "@dir").
Russell Gallop
21

Wenn Sie die Standardausgabe erhalten möchten UND wissen möchten, ob der Befehl erfolgreich war oder nicht, verwenden Sie ihn einfach returnStdoutund verpacken Sie ihn in einen Ausnahmebehandler:

Skript-Pipeline

try {
    // Fails with non-zero exit if dir1 does not exist
    def dir1 = sh(script:'ls -la dir1', returnStdout:true).trim()
} catch (Exception ex) {
    println("Unable to read dir1: ${ex}")
}

Ausgabe :

[Pipeline] sh
[Test-Pipeline] Running shell script
+ ls -la dir1
ls: cannot access dir1: No such file or directory
[Pipeline] echo
unable to read dir1: hudson.AbortException: script returned exit code 2

Leider fehlt bei hudson.AbortException eine nützliche Methode, um diesen Exit-Status zu erhalten. Wenn also der tatsächliche Wert erforderlich ist, müssen Sie ihn aus der Nachricht analysieren (ugh!).

Im Gegensatz zu Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html ist der Build nicht fehlgeschlagen, wenn diese Ausnahme abgefangen wird. Es schlägt fehl, wenn es nicht gefangen wird!

Update: Wenn Sie auch die STDERR-Ausgabe vom Shell-Befehl erhalten möchten, unterstützt Jenkins diesen allgemeinen Anwendungsfall leider nicht richtig. Ein Ticket für 2017 JENKINS-44930 steckt in einem Ping-Pong-Zustand, ohne Fortschritte bei der Lösung zu machen. Bitte fügen Sie Ihre Gegenstimme hinzu.

Für eine Lösung könnte es jetzt einige mögliche Ansätze geben:

a) Leiten 2>&1 Sie STDERR zu STDOUT um - aber es liegt dann an Ihnen, dies aus der Hauptausgabe zu analysieren, und Sie erhalten die Ausgabe nicht, wenn der Befehl fehlschlägt - weil Sie sich im Ausnahmebehandler befinden.

b) Leiten Sie STDERR in eine temporäre Datei um (deren Namen Sie zuvor vorbereitet haben) 2>filename(denken Sie jedoch daran, die Datei anschließend zu bereinigen). Hauptcode wird:

def stderrfile = 'stderr.out'
try {
    def dir1 = sh(script:"ls -la dir1 2>${stderrfile}", returnStdout:true).trim()
} catch (Exception ex) {
    def errmsg = readFile(stderrfile)
    println("Unable to read dir1: ${ex} - ${errmsg}")
}

c) Gehen Sie in die andere Richtung, setzen Sie returnStatus=truestattdessen, verzichten Sie auf den Ausnahmebehandler und erfassen Sie die Ausgabe immer in einer Datei, dh:

def outfile = 'stdout.out'
def status = sh(script:"ls -la dir1 >${outfile} 2>&1", returnStatus:true)
def output = readFile(outfile).trim()
if (status == 0) {
    // output is directory listing from stdout
} else {
    // output is error message from stderr
}

Vorsichtsmaßnahme: Der obige Code ist Unix / Linux-spezifisch - Windows erfordert völlig andere Shell-Befehle.

Ed Randall
quelle
1
Gibt es eine Chance, die Ausgabe als "ls: kann nicht auf dir1 zugreifen: Keine solche Datei oder kein solches Verzeichnis" und nicht nur als "hudson.AbortException: Skript hat Exit-Code 2 zurückgegeben" zu erhalten?
user2988257
Ich sehe nicht ein, wie das jemals funktionieren könnte. In meinen Tests wird der Ausgabetext nie zugewiesen und dies ist zu erwarten. Eine vom Shell-Schritt ausgelöste Ausnahme verhindert, dass der Rückgabewert zugewiesen wird
Jakub Bochenski
2
returnStatus und returnStdout funktionieren leider nicht gleichzeitig. Hier ist das Ticket. Bitte stimmen Sie ab: issue.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov
1
@AlexanderSamoylov Sie müssen eine Datei wie in Option (c) oben umgehen. Leider sind die Autoren dieser Tools oftmals einer Meinung und denken nicht voraus für andere gängige Anwendungsfälle, wobei "sh" hier ein typisches Beispiel ist.
Ed Randall
1
@ Ed Randall, stimme dir voll und ganz zu. Deshalb habe ich diese Ausgabe gepostet, in der Hoffnung, dass sie aufgrund der größeren Anzahl von Stimmen anfangen, etwas zu tun.
Alexander Samoylov
12

Dies ist ein Beispielfall, der meiner Meinung nach Sinn machen wird!

node('master'){
    stage('stage1'){
    def commit = sh (returnStdout: true, script: '''echo hi
    echo bye | grep -o "e"
    date
    echo lol''').split()


    echo "${commit[-1]} "

    }
}
Bibek Mantree
quelle
Ich weiß nicht wie, aber deine Antwort hilft mir sehr, danke :)
shaharnakash
5

Für diejenigen, die die Ausgabe in nachfolgenden Shell-Befehlen verwenden müssen, anstatt groovig zu sein, könnte so etwas wie dieses Beispiel getan werden:

    stage('Show Files') {
        environment {
          MY_FILES = sh(script: 'cd mydir && ls -l', returnStdout: true)
        }
        steps {
          sh '''
            echo "$MY_FILES"
          '''
        }
    }

Ich fand die Beispiele auf Code Maven sehr nützlich.

Nagev
quelle
-6

Der einfachste Weg ist, diesen Weg zu benutzen

my_var=`echo 2` echo $my_var Ausgabe: 2

Beachten Sie, dass ein einfaches Anführungszeichen kein einfaches Anführungszeichen (`) ist.

Ajay Gadhavana
quelle
Upvoted, aber ich würde vorschlagen, dass Sie zeigen, dass diese unter einem shanderen verpackt werden sollten, sonst könnten die Leute denken, dass es groovig ist, besonders wenn sie nicht mit Bash-Skripten vertraut sind. Ich habe es gerade bei Jenkins ausprobiert, ls -lstatt echo 2und es funktioniert. Ich hatte diesen Ansatz schon einmal verwendet, habe aber nach einer Alternative gesucht, weil sie nicht sehr zuverlässig ist. Ich habe die Ausgabe eines komplexeren Befehls auf diese Weise auf einer Standard-Shell erfasst, aber wenn sie auf die Jenkins portiert wird, enthält shdie Variable aus einem unbekannten Grund nichts.
Nagev