Comment marquer une construction instable dans Jenkins lors de l'exécution de scripts shell

93

Dans un projet sur lequel je travaille, nous utilisons des scripts shell pour exécuter différentes tâches. Certains sont des scripts sh / bash qui exécutent rsync, et d'autres sont des scripts PHP. L'un des scripts PHP exécute des tests d'intégration qui sortent vers JUnit XML, des rapports de couverture de code, etc.

Jenkins est capable de marquer les travaux comme réussis / échoués en fonction de l' état de sortie . En PHP, le script se termine par 1 s'il a détecté que les tests ont échoué lors de l'exécution. Les autres scripts shell exécutent des commandes et utilisent les codes de sortie de celles-ci pour marquer une construction comme ayant échoué.

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

Dans la terminologie Jenkins , une construction instable est définie comme suit:

Une compilation est instable si elle a été créée avec succès et qu'un ou plusieurs éditeurs la signalent comme instable. Par exemple, si l'éditeur JUnit est configuré et qu'un test échoue, la génération sera marquée comme instable.

Comment puis-je faire en sorte que Jenkins marque une construction comme instable au lieu de réussir / échouer uniquement lors de l'exécution de scripts shell?

HNygard
la source
Je l'ai réalisé en exécutant différentes étapes de travail et en utilisant les plugins jenkins stackoverflow.com/questions/25442343
...

Réponses:

58

Utilisez le plugin Text-finder .

Au lieu de quitter avec le statut 1 (ce qui échouerait la construction), faites:

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

Ensuite, dans les actions de post-construction, activez la recherche de texte, définissez l'expression régulière pour qu'elle corresponde au message que vous avez imprimé ( TESTS FAILED!) et cochez la case "Instable si trouvé" sous cette entrée.

Jan Hudec
la source
2
Voir la réponse ci-dessous pour une option sans installer de plugin, depuis la version 2.26 de Jenkins: stackoverflow.com/a/49676269/1347649
JSoet
61

Les versions modernes de Jenkins (depuis la 2.26, octobre 2016) ont résolu ce problème: c'est juste une option avancée pour l'étape de construction du shell Execute!

code de sortie pour la construction

Vous pouvez simplement choisir et définir une valeur de sortie arbitraire; s'il correspond, la construction sera instable. Choisissez simplement une valeur qui est peu susceptible d'être lancée par un processus réel dans votre build.

Alan Franzoni
la source
J'aime cette option car elle ne vous oblige pas à installer de plugins supplémentaires
mattherman
2
Comme cela est implémenté dans le dernier Jenkins - cela devrait être une réponse acceptée
smoke_lp
3
«Versions modernes de Jenkins» signifie Jenkins 2.26 ou plus récent. Voir issues.jenkins-ci.org/browse/JENKINS-23786 .
Bleu
5
Est-il possible de le spécifier via le code lors de l'utilisation de la shcommande step dans un Jenkinsfile? Où se trouve le paramètre dans l'interface graphique? Je ne le trouve pas.
bluenote10
1
J'ai dû cliquer sur le bouton "Avancé ..." ouvert sous l'étape de construction pour exposer cela. Il n'est pas très utile de cacher une seule option (et pas particulièrement avancée) derrière un collapser "cliquez ici pour faire les choses", mais c'est comme ça.
tripleee
57

Cela peut être fait sans imprimer de chaînes magiques et en utilisant TextFinder. Voici quelques informations à ce sujet.

Fondamentalement, vous avez besoin d'un fichier .jar de http: // yourserver.com / cli disponible dans les scripts shell, vous pouvez alors utiliser la commande suivante pour marquer une construction instable:

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

Pour marquer la construction instable en cas d'erreur, vous pouvez utiliser:

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

Le problème est que jenkins-cli.jar doit être disponible à partir du script shell. Vous pouvez soit le mettre dans un chemin d'accès facile, soit le télécharger via le script shell du travail:

wget ${JENKINS_URL}jnlpJars/jenkins-cli.jar
binaryLV
la source
2
J'aime vraiment cette solution, j'ai implémenté une classe ruby ​​pour cela pour une réutilisation facile dans mes rakefiles. :)
Shire
3
+1 - c'est une meilleure solution que la réponse acceptée car le Text Finder ne peut rechercher qu'une seule chaîne par travail, vous ne pouvez donc définir l'état de construction que sur l'une des deux valeurs.
gareth_bowles
4
Solution intéressante. Mais si votre Jenkins nécessite une authentification, vous devrez configurer l'authentification par clé publique dans sa configuration ou toute commande jenkins-cli échouera avec une AccessDeniedException.
Tom De Leu
2
Cela ne fonctionnera pas si vous utilisez un esclave qui n'a pas d'accès Web au maître. Par exemple, si l'esclave Jenkins ne peut pas créer une connexion HTTP ou HTTPS avec le serveur.
Steve HHH
3
Je voulais utiliser cette solution, mais set-build-resultelle est obsolète dans le jenkins-cli.
DrLime2k10
27

Vous devez utiliser Jenkinsfile pour encapsuler votre script de construction et simplement marquer la construction actuelle comme INSTABLE en utilisant currentBuild.result = "UNSTABLE" .

   étape {
      status = / * votre commande de construction va ici * /
      if (status === "MARK-AS-UNSTABLE") {
        currentBuild.result = "INSTABLE"
      }
   }
poussma
la source
3
Pourquoi cette réponse n'a-t-elle pas plus de votes positifs? Y a-t-il quelque chose qui ne va pas (sauf l'utilisation de la chaîne "magique" UNSTABLE)? Cela semble plus simple que les autres réponses.
Kevin le
2
La question portait sur les emplois de style libre, tandis que cette réponse concerne les emplois de Pipeline. La réponse Pipeline ne s'applique pas aux emplois de style libre
Mark Waite
Comment ça marche? Expected one of "steps", "stages", or "parallel" for stageJ'obtiens une erreur: lorsque j'essaye de définir currentBuild.result directement dans une scène.
dokaspar le
6

Dans mon script de travail, j'ai les déclarations suivantes (ce travail ne s'exécute que sur le maître 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

Vous pouvez voir ceci et beaucoup plus d'informations sur la définition des statuts de construction sur le wiki Jenkins: https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI

Steve HHH
la source
4
  1. Configurer la construction PHP pour produire un rapport 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. Terminer le script de construction avec le statut 0

    ...
    exit 0;
  3. Ajouter une action post-build Publier le rapport de résultat de test JUnit pour les fichiers XML de rapport de test. Ce plugin changera la construction stable en instable lorsque le test échouera.

    **/build/junit.xml
  4. Ajouter plugin Jenkins Text Finder avec l'analyse de la sortie de la console et des options non cochées. Ce plugin échoue entièrement sur une erreur fatale.

    PHP Fatal error:
MariuszS
la source
3

Je trouve que le moyen le plus flexible de le faire est de lire un fichier dans le plugin groovy post build. entrez la description de l'image ici

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 le contenu du fichier est «vrai», la construction sera définie sur instable. Cela fonctionnera sur le maître local et sur tous les esclaves sur lesquels vous exécutez le travail, et pour tout type de script pouvant écrire sur le disque.

jeremyjjbrown
la source
Je suppose que cela indique vraiment "s'il y a un fichier dans l'espace de travail nommé build.properties" marque comme instable. Est-ce correct? Je suis nouveau sur Groovy, cela vous dérangerait-il de résumer un peu plus cette explication?
uchuugaka
@uchuugaka ouais, s'il y a un fichier et qu'il a ce contenu. Le nom et le contenu du fichier sont arbitraires. Utilisez ce qui convient à votre cas.
jeremyjjbrown
Merci! très utile. Groovy Postbuild est assez indirect, et Groovy aspire une si grande quantité de choses de Java et en ajoute plus ... c'est une nouvelle astuce pour moi.
uchuugaka
@uchuugaka Je ne pense pas que ce soit un problème avec groovy :)
jeremyjjbrown
Pas un problème du tout. Juste un défi auquel se pencher!
uchuugaka
2

Le TextFinder n'est bon que si le statut du travail n'a pas été changé de SUCCESS à FAILED ou ABORTED. Dans de tels cas, utilisez un script groovy dans l'étape 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
    }
 }

Voir plus de détails dans un article que j'ai écrit à ce sujet: http://www.tikalk.com/devops/JenkinsJobStatusChange/

yorammi
la source
2

Dupliquer ma réponse d' ici parce que j'ai passé du temps à chercher ceci:

C'est maintenant possible dans les nouvelles versions de Jenkins, vous pouvez faire quelque chose comme ceci:

#!/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}")
    }
  }
}

Le générateur de syntaxe de pipeline vous montre ceci dans l'onglet avancé:

Exemple de syntaxe de pipeline

gib
la source
2

J'ai pensé que je publierais une autre réponse pour les personnes qui pourraient rechercher quelque chose de similaire.

Dans notre travail de construction, nous avons des cas où nous voudrions que la construction continue, mais qu'elle soit marquée comme instable. Pour le nôtre, cela concerne les numéros de version.

Donc, je voulais définir une condition sur la construction et définir la construction sur instable si cette condition est remplie.

J'ai utilisé l' option Étape conditionnelle (unique) comme étape de construction.

Ensuite, j'ai utilisé le script Groovy du système d'exécution comme étape de construction qui s'exécuterait lorsque cette condition serait remplie.

J'ai utilisé Groovy Command et défini le script comme suit

import hudson.model.*

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

return

Cela semble très bien fonctionner.

Je suis tombé sur la solution ici

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

adprocas
la source
1

Comme alternative plus légère aux réponses existantes, vous pouvez définir le résultat de la génération avec un simple HTTP POST pour accéder à l'API REST de la console de script 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

Avantages:

  • pas besoin de télécharger et d'exécuter un énorme fichier jar
  • pas de kludges pour définir et lire un état global (texte de la console, fichiers dans l'espace de travail)
  • aucun plug-in requis (à part Groovy)
  • pas besoin de configurer une étape de construction supplémentaire qui est superflue dans les cas PASSÉ ou ÉCHEC.

Pour cette solution, votre environnement doit remplir ces conditions:

  • L'API REST Jenkins est accessible depuis l'esclave
  • L'esclave doit avoir accès aux informations d'identification qui permettent d'accéder à l'API REST du script Jenkins Groovy.
Alex O
la source
0

Un moyen simple de définir une construction comme instable est dans votre bloc "Exécuter le shell", exécutez exit 13

user1415664
la source
-3

Vous pouvez simplement appeler "exit 1", et la construction échouera à ce stade et ne continuera pas. J'ai fini par faire un passthrough make fonction pour le gérer pour moi, et appeler safemake au lieu de make for building:

function safemake {
  make "$@"
  if [ "$?" -ne 0 ]; then
    echo "ERROR: BUILD FAILED"
    exit 1
  else
    echo "BUILD SUCCEEDED"
  fi
}
jessebs
la source
11
exit 1, pour autant que je sache, ne fera échouer la construction. Je ne veux pas que la construction échoue, je veux qu'elle soit marquée comme instable.
HNygard
1
Voir aussi stackoverflow.com/questions/36313216/… - la solution simple est justeif make "$@"; then echo "BUILD SUCCEEDED"; else rc=$?; echo "BUILD FAILED"; exit $rc; fi
tripleee le