Cómo marcar una compilación como inestable en Jenkins al ejecutar scripts de shell

93

En un proyecto en el que estoy trabajando, estamos usando scripts de shell para ejecutar diferentes tareas. Algunos son scripts sh / bash que ejecutan rsync y otros son scripts PHP. Uno de los scripts PHP está ejecutando algunas pruebas de integración que dan salida a JUnit XML, informes de cobertura de código y similares.

Jenkins puede marcar los trabajos como exitosos / fallidos según el estado de salida . En PHP, el script sale con 1 si ha detectado que las pruebas fallaron durante la ejecución. Los otros scripts de shell ejecutan comandos y usan los códigos de salida de estos para marcar una compilación como fallida.

// :: End of PHP script:
// If any tests have failed, fail the build
if ($build_error) exit(1);

En la terminología de Jenkins , una compilación inestable se define como:

Una compilación es inestable si se creó correctamente y uno o más editores informan que es inestable. Por ejemplo, si el editor JUnit está configurado y una prueba falla, la compilación se marcará como inestable.

¿Cómo puedo hacer que Jenkins marque una compilación como inestable en lugar de solo exitosa / fallida al ejecutar scripts de shell?

HNygard
fuente
Lo logré ejecutando diferentes pasos de trabajo y usando los complementos de jenkins stackoverflow.com/questions/25442343/…
fantastory

Respuestas:

58

Utilice el complemento Text-finder .

En lugar de salir con el estado 1 (que fallaría la compilación), haga:

if ($build_error) print("TESTS FAILED!");

Luego, en las acciones posteriores a la compilación, habilite el Buscador de texto, configure la expresión regular para que coincida con el mensaje que imprimió ( TESTS FAILED!) y marque la casilla de verificación "Inestable si se encuentra" debajo de esa entrada.

Jan Hudec
fuente
2
Consulte la respuesta a continuación para ver una opción sin instalar un complemento, desde jenkins versión 2.26: stackoverflow.com/a/49676269/1347649
JSoet
63

Las versiones modernas de Jenkins (desde 2.26, octubre de 2016) resolvieron esto: ¡es solo una opción avanzada para el paso de construcción Ejecutar shell!

exit code for build

Puede elegir y establecer un valor de salida arbitrario; si coincide, la construcción será inestable. Simplemente elija un valor que es poco probable que se lance mediante un proceso real en su compilación.

Alan Franzoni
fuente
Me gusta esta opción ya que no requiere que instales ningún complemento adicional
mattherman
2
Dado que esto se implementa en la última
versión de
3
"Versiones modernas de Jenkins" significa Jenkins 2.26 o más reciente. Consulte issues.jenkins-ci.org/browse/JENKINS-23786 .
Azul
5
¿Es posible especificar esto a través del código cuando se usa el shcomando de paso en a Jenkinsfile? ¿Dónde se encuentra la configuración en la GUI? No puedo encontrarlo.
bluenote10
1
Tuve que hacer clic para abrir el botón "Avanzado ..." debajo del paso de compilación para exponer esto. No es muy útil ocultar una sola opción (y no particularmente avanzada) detrás de un colapsador "haga clic aquí para hacer las cosas", pero así es.
tripleee
57

Se puede hacer sin imprimir cadenas mágicas y usando TextFinder. Aquí hay algo de información al respecto.

Básicamente, necesita un archivo .jar de http: // yourserver.com / cli disponible en scripts de shell, luego puede usar el siguiente comando para marcar una compilación como inestable:

java -jar jenkins-cli.jar set-build-result unstable

Para marcar la construcción como inestable en caso de error, puede usar:

failing_cmd cmd_args || java -jar jenkins-cli.jar set-build-result unstable

El problema es que jenkins-cli.jar debe estar disponible desde el script de shell. Puede ponerlo en una ruta de fácil acceso o descargarlo a través del script de shell del trabajo:

wget ${JENKINS_URL}jnlpJars/jenkins-cli.jar
binaryLV
fuente
2
Realmente me gusta esta solución, implementé una clase ruby ​​para esto para poder reutilizarla fácilmente en mis rakefiles. :)
Shire
3
+1: esta es una solución mejor que la respuesta aceptada porque el Buscador de texto solo puede buscar una cadena por trabajo, por lo que solo puede establecer el estado de compilación en uno de dos valores.
gareth_bowles
4
Interesante solución. Pero si su Jenkins requiere autenticación, deberá configurar la autenticación de clave pública en su configuración o cualquier comando jenkins-cli fallará con una AccessDeniedException.
Tom De Leu
2
Esto no funcionará si está utilizando un esclavo que no tiene acceso web al maestro. Por ejemplo, si el esclavo Jenkins no puede crear una conexión HTTP o HTTPS con el servidor.
Steve HHH
3
Quería utilizar esta solución, pero set-build-resultha quedado obsoleta en jenkins-cli.
DrLime2k10
28

Debe usar Jenkinsfile para envolver su script de compilación y simplemente marcar la compilación actual como INESTABLE usando currentBuild.result = "UNSTABLE".

   etapa {
      status = / * tu comando de construcción va aquí * /
      if (status === "MARK-AS-UNSTABLE") {
        currentBuild.result = "INESTABLE"
      }
   }
poussma
fuente
3
¿Por qué esta respuesta no tiene más votos a favor? ¿Tiene algún problema (excepto el uso de la cuerda "mágica" UNSTABLE)? Parece más sencillo que las otras respuestas.
Kevin
2
La pregunta era sobre trabajos de estilo libre, mientras que esta respuesta trata sobre trabajos de Pipeline. La respuesta de Pipeline no se aplica a los trabajos de estilo libre
Mark Waite
¿Cómo funciona esto? Recibo un error: Expected one of "steps", "stages", or "parallel" for stagecuando intento establecer currentBuild.result directamente dentro de un escenario.
dokaspar
11

también deberías poder usar groovy y hacer lo que hizo el buscador de texto

marcar una compilación como inestable con un maravilloso complemento posterior a la compilación

if(manager.logContains("Could not login to FTP server")) {
    manager.addWarningBadge("FTP Login Failure")
    manager.createSummary("warning.gif").appendText("<h1>Failed to login to remote FTP Server!</h1>", false, false, false, "red")
    manager.buildUnstable()
}

Consulte también el complemento Groovy Postbuild

Kalpesh Soni
fuente
6

En el script de mi trabajo, tengo las siguientes declaraciones (este trabajo solo se ejecuta en el maestro de Jenkins):

# This is the condition test I use to set the build status as UNSTABLE
if [ ${PERCENTAGE} -gt 80 -a ${PERCENTAGE} -lt 90 ]; then
  echo WARNING: disc usage percentage above 80%

  # Download the Jenkins CLI JAR:
  curl -o jenkins-cli.jar ${JENKINS_URL}/jnlpJars/jenkins-cli.jar

  # Set build status to unstable
  java -jar jenkins-cli.jar -s ${JENKINS_URL}/ set-build-result unstable

fi

Puede ver esto y mucha más información sobre cómo configurar estados de compilación en la wiki de Jenkins: https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI

Steve HHH
fuente
4
  1. Configurar la compilación de PHP para producir un informe junit xml

    <phpunit bootstrap="tests/bootstrap.php" colors="true" >
       <logging>
           <log type="junit" target="build/junit.xml" 
               logIncompleteSkipped="false" title="Test Results"/>
       </logging>
    
       ....
    
     </phpunit>
    
  2. Finalizar el script de compilación con estado 0

    ...
    exit 0;
    
  3. Agregar acción posterior a la compilación Publicar informe de resultado de prueba JUnit para XML de informe de prueba. Este complemento cambiará la compilación estable a Inestable cuando la prueba esté fallando.

    **/build/junit.xml
    
  4. Agregue el complemento Jenkins Text Finder con escaneo de salida de consola y opciones sin marcar. Este complemento falla en la construcción completa por error fatal.

    PHP Fatal error:
    
MariuszS
fuente
3

Encuentro que la forma más flexible de hacer esto es leyendo un archivo en el maravilloso complemento de compilación posterior. ingrese la descripción de la imagen aquí

import hudson.FilePath
import java.io.InputStream

def build = Thread.currentThread().executable

String unstable = null
if(build.workspace.isRemote()) {
    channel = build.workspace.channel;
    fp = new FilePath(channel, build.workspace.toString() + "/build.properties")
    InputStream is = fp.read()
    unstable = is.text.trim()
} else {
    fp = new FilePath(new File(build.workspace.toString() + "/build.properties"))
    InputStream is = fp.read()
    unstable = is.text.trim()
}

manager.listener.logger.println("Build status file: " + unstable)
if (unstable.equalsIgnoreCase('true')) {
    manager.listener.logger.println('setting build to unstable')
    manager.buildUnstable()
}

Si el contenido del archivo es "verdadero", la compilación se establecerá en inestable. Esto funcionará en el maestro local y en cualquier esclavo en el que ejecute el trabajo, y para cualquier tipo de scripts que puedan escribir en el disco.

jeremyjjbrown
fuente
Supongo que esto realmente dice "si hay un archivo en el espacio de trabajo llamado build.properties", marque como inestable. ¿está bien? Soy nuevo en Groovy, ¿te importaría desglosar un poco más esta explicación?
uchuugaka
@uchuugaka sí, si hay un archivo y tiene ese contenido. El nombre y el contenido del archivo son arbitrarios. Utilice lo que se adapte a su caso.
jeremyjjbrown
¡Gracias! muy útil. Groovy Postbuild es bastante indirecto, y Groovy absorbe una gran cantidad de cosas de Java y agrega más ... es un nuevo truco para mí.
uchuugaka
@uchuugaka No creo que sea un problema con groovy :)
jeremyjjbrown
No es un problema en absoluto. ¡Solo un desafío en el que apoyarse!
uchuugaka
2

TextFinder es bueno solo si el estado del trabajo no ha cambiado de SUCCESS a FAILED o ABORTED. Para tales casos, use un script maravilloso en el paso PostBuild:

errpattern = ~/TEXT-TO-LOOK-FOR-IN-JENKINS-BUILD-OUTPUT.*/;
manager.build.logFile.eachLine{ line ->
    errmatcher=errpattern.matcher(line)
    if (errmatcher.find()) {
        manager.build.@result = hudson.model.Result.NEW-STATUS-TO-SET
    }
 }

Vea más detalles en una publicación que escribí al respecto: http://www.tikalk.com/devops/JenkinsJobStatusChange/

yorammi
fuente
2

Duplicando mi respuesta desde aquí porque pasé un tiempo buscando esto:

Esto ahora es posible en las versiones más recientes de Jenkins, puede hacer algo como esto:

#!/usr/bin/env groovy

properties([
  parameters([string(name: 'foo', defaultValue: 'bar', description: 'Fails job if not bar (unstable if bar)')]),
])


stage('Stage 1') {
  node('parent'){
    def ret = sh(
      returnStatus: true, // This is the key bit!
      script: '''if [ "$foo" = bar ]; then exit 2; else exit 1; fi'''
    )
    // ret can be any number/range, does not have to be 2.
    if (ret == 2) {
      currentBuild.result = 'UNSTABLE'
    } else if (ret != 0) {
      currentBuild.result = 'FAILURE'
      // If you do not manually error the status will be set to "failed", but the
      // pipeline will still run the next stage.
      error("Stage 1 failed with exit code ${ret}")
    }
  }
}

El generador de sintaxis de canalización le muestra esto en la pestaña avanzada:

Ejemplo de sintaxis de canalización

Gibraltar
fuente
2

Pensé en publicar otra respuesta para las personas que podrían estar buscando algo similar.

En nuestro trabajo de compilación, tenemos casos en los que quisiéramos que la compilación continuara, pero que se marcara como inestable. Para el nuestro, está relacionado con los números de versión.

Por lo tanto, quería establecer una condición en la compilación y establecer la compilación en inestable si se cumple esa condición.

Usé el paso condicional (sencillo) opción como paso de compilación.

Luego utilicé Ejecutar sistema Groovy script como el paso de compilación que se ejecutaría cuando se cumpliera esa condición.

Solía maravilloso Comando y establecer la secuencia de comandos de la siguiente

import hudson.model.*

def build = Thread.currentThread().executable
build.@result = hudson.model.Result.UNSTABLE

return

Eso parece funcionar bastante bien.

Me encontré con la solución aquí

http://tech.akom.net/archives/112-Marking-Jenkins-build-UNSTABLE-from-environment-inject-groovy-script.html

adprocas
fuente
1

Como una alternativa más ligera a las respuestas existentes, puede establecer el resultado de la compilación con un HTTP POST simple para acceder a la API REST de la consola de scripts Groovy :

    curl -X POST \
     --silent \
     --user "$YOUR_CREDENTIALS" \
     --data-urlencode "script=Jenkins.instance.getItemByFullName( '$JOB_NAME' ).getBuildByNumber( $BUILD_NUMBER ).setResult( hudson.model.Result.UNSTABLE )" $JENKINS_URL/scriptText

Ventajas:

  • no es necesario descargar y ejecutar un archivo jar enorme
  • sin problemas para configurar y leer algún estado global (texto de la consola, archivos en el espacio de trabajo)
  • no se requieren complementos (además de Groovy)
  • no es necesario configurar un paso de compilación adicional que sea superfluo en los casos PASADOS o FALLOS.

Para esta solución, su entorno debe cumplir estas condiciones:

  • Se puede acceder a la API REST de Jenkins desde el esclavo
  • El esclavo debe tener acceso a las credenciales que le permitan acceder a la API REST del script Jenkins Groovy.
Alex O
fuente
0

Una forma fácil de establecer una compilación como inestable es en su bloque "ejecutar shell", ejecutar exit 13

usuario1415664
fuente
-3

Puede simplemente llamar a "salida 1", y la compilación fallará en ese punto y no continuará. Terminé haciendo una función de paso a través para manejarlo por mí, y llamé a safemake en lugar de hacer para construir:

function safemake {
  make "$@"
  if [ "$?" -ne 0 ]; then
    echo "ERROR: BUILD FAILED"
    exit 1
  else
    echo "BUILD SUCCEEDED"
  fi
}
jessebs
fuente
11
salida 1, hasta donde yo sé, solo hará que la compilación falle. No quiero que falle la compilación, quiero que se marque como inestable.
HNygard
1
Consulte también stackoverflow.com/questions/36313216/… - la solución simple es simplementeif make "$@"; then echo "BUILD SUCCEEDED"; else rc=$?; echo "BUILD FAILED"; exit $rc; fi
tripleee