¿Cómo puedo ejecutar el resultado de un comando de shell usando una variable de Jenkinsfile (groovy)?
Tengo algo como esto en un archivo Jenkins (Groovy) y quiero registrar la salida estándar y el código de salida en una variable para poder usar la información más adelante.
sh "ls -l"
¿Cómo puedo hacer esto, especialmente porque parece que realmente no se puede ejecutar ningún tipo de código maravilloso dentro del archivo Jenkinsfile
?
La última versión del sh
paso de canalización le permite hacer lo siguiente;
// 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}"
Otra característica es la returnStatus
opción.
// 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}"
Estas opciones se agregaron en función de este problema.
Consulte la documentación oficial del sh
comando.
Para canalizaciones declarativas (ver comentarios), debe ajustar el código al script
paso:
script {
GIT_COMMIT_EMAIL = sh (
script: 'git --no-pager show -s --format=\'%ae\'',
returnStdout: true
).trim()
echo "Git committer email: ${GIT_COMMIT_EMAIL}"
}
La versión actual de Pipeline admite de forma nativa returnStdout
y returnStatus
, lo que permite obtener resultados o estados de los pasos sh
/ bat
.
Un ejemplo:
def ret = sh(script: 'uname', returnStdout: true)
println ret
Una documentación oficial .
la respuesta rápida es esta:
sh "ls -l > commandResult"
result = readFile('commandResult').trim()
Creo que existe una solicitud de función para poder obtener el resultado del paso sh, pero hasta donde yo sé, actualmente no hay otra opción.
EDITAR: JENKINS-26133
EDIT2: No estoy seguro de qué versión, pero los pasos de sh/bat ahora pueden devolver la salida estándar, simplemente:
def output = sh returnStdout: true, script: 'ls -l'
Si desea obtener la salida estándar Y saber si el comando se realizó correctamente o no, simplemente úselo returnStdout
y envuélvalo en un controlador de excepciones:
canalización con guión
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}")
}
producción :
[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
Desafortunadamente, a hudson.AbortException le falta algún método útil para obtener ese estado de salida, por lo que si se requiere el valor real, deberá analizarlo y eliminarlo del mensaje (¡uf!).
Al contrario del Javadoc https://javadoc.jenkins-ci.org/hudson/AbortException.html , la compilación no falla cuando se detecta esta excepción. ¡Falla cuando no se atrapa!
Actualización: si también desea la salida STDERR del comando de shell, lamentablemente Jenkins no admite adecuadamente ese caso de uso común. Un ticket de 2017, JENKINS-44930 , está atascado en un estado de ping-pong obstinado sin avanzar hacia una solución; considere agregarle su voto a favor.
En cuanto a una solución ahora , podría haber un par de enfoques posibles:
a) Redirigir STDERR a STDOUT 2>&1
, pero depende de usted analizarlo de la salida principal, y no obtendrá la salida si el comando falla, porque está en el controlador de excepciones.
b) redirigir STDERR a un archivo temporal (cuyo nombre preparó anteriormente) 2>filename
(pero recuerde limpiar el archivo después), es decir. El código principal se convierte en:
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) Vaya al otro lado, configúrelo returnStatus=true
, prescinda del controlador de excepciones y capture siempre la salida en un archivo, es decir:
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
}
Advertencia: el código anterior es específico de Unix/Linux: Windows requiere comandos de shell completamente diferentes.