Jak uzyskać dane wyjściowe polecenia powłoki wykonane za pomocą zmiennej w Jenkinsfile (groovy)?

213

Mam coś takiego na Jenkinsfile (Groovy) i chcę zapisać stdout i kod wyjścia w zmiennej, aby móc później wykorzystać te informacje.

sh "ls -l"

Jak mogę to zrobić, tym bardziej, że wydaje się, że nie da się tak naprawdę uruchomić żadnego fajnego kodu wewnątrz Jenkinsfile?

sorin
źródło

Odpowiedzi:

391

Najnowsza wersja shkroku potoku pozwala wykonać następujące czynności;

// 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}"

Inną funkcją jest returnStatusopcja.

// 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}"

Te opcje zostały dodane na podstawie tego problemu.

Zobacz oficjalną dokumentację dla shkomendy.

G. Roggemans
źródło
11
Wygląda na to, że teraz jest to udokumentowane -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/…
zot24
Jednak nie działa dla mnie z prefiksem „vars”. Kiedy używam GIT_COMMIT_EMAIL jako nazwy zmiennej bez prefiksu, wszystko jest w porządku.
Bastian Voigt,
Proszę o pomoc w przypadku stackoverflow.com/questions/40946697/…
Jitesh Sojitra,
7
Kiedy używam deklaratywnej składni pliku jenkinsfile, to nie działa, komunikat o błędzie to:WorkflowScript: 97: Expected a step @ line 97, column 17.
Klucz
17
Wygląda na to, że działa to tylko w scriptbloku kroków. jenkins.io/doc/book/pipeline/syntax/#declarative-steps
mosiężna małpa
51

Obecna wersja Pipeline natywnie obsługuje returnStdouti returnStatus, które umożliwiają uzyskanie danych wyjściowych lub statusu z sh/ batsteps.

Przykład:

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

Oficjalna dokumentacja .

luka5z
źródło
Czy ktoś może mi pomóc w przypadku stackoverflow.com/questions/40946697/... ? Z góry dziękuję!
Jitesh Sojitra
3
Instrukcje należy zawinąć w script { }krok.
x-yuri
40

szybka odpowiedź brzmi:

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

Myślę, że istnieje żądanie funkcji, aby móc uzyskać wynik kroku sh, ale o ile wiem, obecnie nie ma innej opcji.

EDYTOWAĆ: JENKINS-26133

EDYCJA 2: Nie jestem do końca pewien, która wersja, ale kroki sh / bat mogą teraz zwrócić standardowe wyjście, po prostu:

def output = sh returnStdout: true, script: 'ls -l'
pojazd
źródło
1
Również FYI, kroki nietoperza powtarzają uruchamiane polecenie, więc musisz uruchomić polecenia nietoperza za pomocą @, aby uzyskać wynik (np. „@Dir”).
Russell Gallop
21

Jeśli chcesz uzyskać standardowe wyjście ORAZ wiedzieć, czy polecenie się powiodło, czy nie, po prostu użyj returnStdouti umieść je w module obsługi wyjątków:

potok skryptowy

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}")
}

wynik :

[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

Niestety hudson.AbortException nie ma żadnej użytecznej metody uzyskania tego statusu wyjścia, więc jeśli wymagana jest rzeczywista wartość, musisz ją przeanalizować z komunikatu (ugh!)

W przeciwieństwie do Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html kompilacja nie kończy się niepowodzeniem, gdy ten wyjątek zostanie przechwycony. Kończy się niepowodzeniem, gdy jest zostanie złapany!

Aktualizacja: Jeśli chcesz również otrzymać wynik STDERR z polecenia powłoki, Jenkins niestety nie obsługuje poprawnie tego typowego przypadku użycia. Bilet na 2017 rok JENKINS-44930 na rok utknął w stanie upartego ping-ponga, nie czyniąc postępów w kierunku rozwiązania - prosimy o dodanie do niego opinii.

Co do rozwiązania teraz , nie może być kilka możliwych rozwiązań:

a) Przekieruj STDERR do STDOUT 2>&1 - ale to od Ciebie zależy, czy parsujesz to z głównego wyjścia, ale nie dostaniesz wyjścia, jeśli polecenie się nie powiedzie - ponieważ jesteś w procedurze obsługi wyjątków.

b) przekieruj STDERR do pliku tymczasowego (którego nazwę przygotujesz wcześniej) 2>filename(ale pamiętaj, aby wyczyścić plik później) - tj. główny kod staje się:

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) Idź w drugą stronę, returnStatus=truezamiast tego ustaw , zrezygnuj z procedury obsługi wyjątków i zawsze przechwytuj dane wyjściowe do pliku, tj .:

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
}

Uwaga: powyższy kod jest specyficzny dla Uniksa / Linuksa - Windows wymaga zupełnie innych poleceń powłoki.

Ed Randall
źródło
1
czy jest szansa na uzyskanie wyniku jako „ls: nie można uzyskać dostępu do katalogu 1: brak takiego pliku lub katalogu”, a nie tylko „hudson.AbortException: skrypt zwrócił kod wyjścia 2”?
user2988257,
Nie rozumiem, jak to może kiedykolwiek działać. W moich testach tekst wyjściowy nigdy nie jest przypisywany i należy tego oczekiwać. Wyjątek zgłoszony z kroku powłoki uniemożliwia przypisanie wartości zwracanej
Jakub Bochenski
2
returnStatus i returnStdout niestety nie działają w tym samym czasie. Oto bilet. Głosuj: Issues.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov,
1
@AlexanderSamoylov Musisz obejść ten problem, używając pliku jak w opcji (c) powyżej. Niestety autorzy tych narzędzi są często wypowiadani i nie przewidują innych typowych przypadków użycia, w tym przypadku „sh”.
Ed Randall
1
@Ed Randall, w pełni się z tobą zgadzam. Dlatego opublikowałem ten numer, mając nadzieję, że z powodu większej liczby głosów zaczną coś robić.
Alexander Samoylov,
12

to przykładowy przypadek, który, jak sądzę, ma sens!

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
źródło
Nie wiem jak, ale twoja odpowiedź bardzo mi pomaga, dziękuję :)
shaharnakash
5

Dla tych, którzy potrzebują użyć danych wyjściowych w kolejnych poleceniach powłoki, a nie groovy, można zrobić coś takiego:

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

Uważam, że przykłady kodu maven są całkiem przydatne.

Nagev
źródło
-6

Najprostszym sposobem jest użycie w ten sposób

my_var=`echo 2` echo $my_var wyjście: 2

zauważ, że to nie jest proste pojedynczy cytat to powrót cytatu (`).

Ajay Gadhavana
źródło
Pozytywne, ale sugeruję, abyś pokazał, że powinny być one zawinięte pod shinnym, w przeciwnym razie ludzie mogliby pomyśleć, że jest świetny, szczególnie jeśli nie znają skryptów bash. Właśnie wypróbowałem to na Jenkins, używając ls -lzamiast echo 2i to działa. Tak naprawdę wcześniej korzystałem z tego podejścia, ale szukałem alternatywy, ponieważ nie jest ona zbyt wiarygodna. Mam wyjście bardziej złożonego polecenia przechwyconego na standardowej powłoce w ten sposób, ale po przeniesieniu do Jenkinsa shzmienna nie zawiera niczego, z nieznanego powodu.
Nagev