Comment obtenir la sortie d'une commande shell exécutée à l'aide d'une variable de Jenkinsfile (groovy)?

213

J'ai quelque chose comme ça sur un fichier Jenkins (Groovy) et je veux enregistrer la sortie standard et le code de sortie dans une variable afin d'utiliser les informations plus tard.

sh "ls -l"

Comment puis-je faire cela, d'autant plus qu'il semble que vous ne pouvez pas vraiment exécuter de code groovy à l'intérieur de Jenkinsfile?

Sorin
la source

Réponses:

393

La dernière version de l' shétape du pipeline vous permet d'effectuer les opérations suivantes;

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

Une autre caractéristique est l' 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}"

Ces options ont été ajoutées en fonction de ce problème.

Voir la documentation officielle de la shcommande.

G. Roggemans
la source
11
On dirait que maintenant c'est documenté -> jenkins.io/doc/pipeline/steps/workflow-durable-task-step/…
zot24
Ne fonctionne pas pour moi avec le préfixe "vars". Quand j'utilise simplement GIT_COMMIT_EMAIL comme nom var sans le préfixe, tout va bien.
Bastian Voigt du
Aidez-moi s'il vous plaît pour stackoverflow.com/questions/40946697/…
Jitesh Sojitra
7
Lorsque j'utilise la syntaxe déclarative jenkinsfile, cela ne fonctionne pas, le message d'erreur est le suivant:WorkflowScript: 97: Expected a step @ line 97, column 17.
Clé
17
Il semble que cela ne fonctionne qu'à l'intérieur d'un scriptbloc d'étapes. jenkins.io/doc/book/pipeline/syntax/#declarative-steps
laiton singe
51

La version actuelle du Pipeline prend en charge nativement returnStdoutet returnStatus, ce qui permet d'obtenir la sortie ou l'état à partir de sh/ batsteps.

Un exemple:

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

Une documentation officielle .

luka5z
la source
Quelqu'un peut-il m'aider pour stackoverflow.com/questions/40946697/… ? Merci d'avance!
Jitesh Sojitra du
3
Les instructions doivent être regroupées en une script { }étape.
x-yuri
40

la réponse rapide est la suivante:

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

Je pense qu'il existe une demande de fonctionnalité pour pouvoir obtenir le résultat de l'étape sh, mais pour autant que je sache, il n'y a actuellement aucune autre option.

EDIT: JENKINS-26133

EDIT2: Je ne sais pas trop depuis quelle version, mais les étapes sh / bat peuvent maintenant retourner la sortie std, simplement:

def output = sh returnStdout: true, script: 'ls -l'
vehovmar
la source
1
Aussi, pour info, les étapes de chauve-souris font écho à la commande en cours d'exécution, vous devez donc démarrer les commandes de chauve-souris avec @ pour obtenir simplement la sortie (par exemple "@dir").
Russell Gallop
21

Si vous voulez obtenir la sortie standard ET savoir si la commande a réussi ou non, utilisez simplement returnStdout et encapsulez-la dans un gestionnaire d'exceptions:

pipeline scripté

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

sortie :

[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

Malheureusement, hudson.AbortException ne contient aucune méthode utile pour obtenir ce statut de sortie, donc si la valeur réelle est requise, vous devrez l'analyser hors du message (ugh!)

Contrairement au Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html, la génération n'est pas échouée lorsque cette exception est interceptée. Il échoue quand il n'est pas pris!

Mise à jour: si vous souhaitez également la sortie STDERR de la commande shell, Jenkins ne parvient malheureusement pas à prendre correctement en charge ce cas d'utilisation courant. Un billet 2017 JENKINS-44930 est coincé dans un état de ping-pong avisé sans faire de progrès vers une solution - veuillez envisager d'y ajouter votre vote positif.

En ce qui concerne une solution maintenant , il pourrait y avoir deux approches possibles:

a) Redirigez STDERR vers STDOUT 2>&1 - mais c'est ensuite à vous de l'analyser hors de la sortie principale, et vous n'obtiendrez pas la sortie si la commande a échoué - parce que vous êtes dans le gestionnaire d'exceptions.

b) rediriger STDERR vers un fichier temporaire (dont vous préparez le nom plus tôt) 2>filename(mais n'oubliez pas de nettoyer le fichier par la suite) - ie. le code principal devient:

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) Dans l'autre sens, définissez returnStatus=trueplutôt, supprimez le gestionnaire d'exceptions et capturez toujours la sortie dans un fichier, c'est-à-dire:

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
}

Attention: le code ci-dessus est spécifique à Unix / Linux - Windows nécessite des commandes shell complètement différentes.

Ed Randall
la source
1
est-il possible d'obtenir la sortie sous la forme "ls: impossible d'accéder à dir1: aucun fichier ou répertoire" et pas seulement "hudson.AbortException: le script a renvoyé le code de sortie 2"?
user2988257
Je ne vois pas comment cela pourrait fonctionner. Lors de mes tests, le texte de sortie n'est jamais attribué et cela est normal. Une exception levée à partir de l'étape de shell empêche la valeur de retour d'être affectée
Jakub Bochenski
2
returnStatus et returnStdout ne fonctionnent malheureusement pas en même temps. Voici le ticket. Veuillez voter: issues.jenkins-ci.org/browse/JENKINS-44930 .
Alexander Samoylov
1
@AlexanderSamoylov Vous devez contourner l'utilisation d'un fichier comme dans l'option (c) ci-dessus. Malheureusement, les auteurs de ces outils sont souvent d'opinion et ne pensent pas à l'avenir pour d'autres cas d'utilisation courants, «sh» étant ici un cas d'espèce.
Ed Randall
1
@Ed Randall, entièrement d'accord avec vous .. C'est pourquoi j'ai publié ce numéro en espérant qu'en raison du plus grand nombre de votes, ils commencent à faire quelque chose.
Alexander Samoylov
12

ceci est un exemple de cas, ce qui aura du sens je crois!

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
la source
Je ne sais pas comment mais ta réponse m'aide beaucoup, merci :)
shaharnakash
5

Pour ceux qui ont besoin d'utiliser la sortie dans les commandes shell suivantes, plutôt que groovy, quelque chose comme cet exemple pourrait être fait:

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

J'ai trouvé les exemples sur le code maven très utiles.

Nagev
la source
-6

Le moyen le plus simple est d'utiliser de cette façon

my_var=`echo 2` echo $my_var sortie: 2

notez que ce n'est pas une simple citation simple, c'est une citation de retour (`).

Ajay Gadhavana
la source
Surévalué, mais je suggère que vous montriez que ceux-ci devraient être enveloppés sous un shautre, sinon les gens pourraient penser que c'est groovy, surtout s'ils ne sont pas familiers avec les scripts bash. Je viens de l'essayer sur Jenkins, en utilisant ls -lau lieu de echo 2et cela fonctionne. J'avais déjà utilisé cette approche auparavant, mais je cherchais une alternative parce que ce n'est pas très fiable. J'ai la sortie d'une commande plus complexe capturée sur un shell standard de cette façon, mais lorsqu'elle est portée sur Jenkins, shla variable ne contient rien, pour une raison inconnue.
Nagev