web-dev-qa-db-fra.com

Utiliser Jenkins 'Mailer' dans le flux de travaux du pipeline

J'aimerais exploiter le plugin Mailer existant de Jenkins dans un Jenkinsfile qui définit un travail de construction de pipeline. Compte tenu du simple script d'échec suivant, j'attendrais un courrier électronique pour chaque build.

#!groovy

stage 'Test'
node {
    try {
        sh 'exit 1'
    } finally {
        step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: '[email protected]', sendToIndividuals: true])
    }
}

Le résultat de la construction est:

Started by user xxxxx
[Pipeline] stage (Test)
Entering stage Test
Proceeding
[Pipeline] node
Running on master in /var/lib/jenkins/jobs/rpk-test/workspace
[Pipeline] {
[Pipeline] sh
[workspace] Running Shell script
+ exit 1
[Pipeline] step
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE

Comme vous pouvez le constater, il enregistre qu'il exécute le pipeline step immédiatement après la défaillance, mais aucun courrier électronique n'est généré.

Les e-mails dans d'autres tâches de style libre qui exploitent le mailer fonctionnent bien, il suffit d'appeler via des tâches de pipeline.

Cela fonctionne avec Jenkins 2.2 et mailer 1.17.

Existe-t-il un mécanisme différent selon lequel je devrais invoquer des e-mails ayant échoué à la construction? Je n'ai pas besoin de tout le surcoût de l'étape mail , juste besoin de notifications sur les échecs et les récupérations.

37
rkeilty

Dans le pipeline a échoué sh ne définit pas immédiatement le currentBuild.result à FAILURE alors que sa valeur initiale est null. Par conséquent, les étapes de construction qui reposent sur le statut de construction, comme Mailer, pourraient fonctionner apparemment de manière incorrecte.

Vous pouvez le vérifier en ajoutant une impression de débogage:

stage 'Test'
node {
    try {
        sh 'exit 1'
    } finally {
        println currentBuild.result  // this prints null
        step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: '[email protected]', sendToIndividuals: true])
    }
}

Tout ce pipeline est encapsulé avec le gestionnaire d'exceptions fourni par Jenkins, c'est pourquoi Jenkins marque la construction comme ayant échoué à la fin.

Donc, si vous voulez utiliser Mailer, vous devez maintenir le statut de construction correctement. Par exemple:

stage 'Test'
node {
    try {
        sh 'exit 1'
        currentBuild.result = 'SUCCESS'
    } catch (any) {
        currentBuild.result = 'FAILURE'
        throw any //rethrow exception to prevent the build from proceeding
    } finally {
        step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: '[email protected]', sendToIndividuals: true])
    }
}

Si vous n'avez pas besoin de relancer l'exception, vous pouvez utiliser catchError. Il s'agit d'un pipeline intégré qui capture toute exception dans son étendue, l'imprime dans la console et définit le statut de construction. Exemple:

stage 'Test'
node {
    catchError {
        sh 'exit 1'
    } 
    step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: '[email protected]', sendToIndividuals: true])
}
61
izzekil

En plus de l'excellente réponse d'izzekil, vous souhaiterez peut-être choisir les destinataires des e-mails en fonction des auteurs. Vous pouvez utiliser email-ext pour le faire (en fonction de leurs exemples de pipeline ):

step([$class: 'Mailer',
      notifyEveryUnstableBuild: true,
      recipients: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
                                      [$class: 'RequesterRecipientProvider']])])

Si vous utilisez un email récent (plus de 2.50), vous pouvez l'utiliser dans votre pipeline:

emailext(body: '${DEFAULT_CONTENT}', mimeType: 'text/html',
         replyTo: '$DEFAULT_REPLYTO', subject: '${DEFAULT_SUBJECT}',
         to: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
                                 [$class: 'RequesterRecipientProvider']]))

Si vous n'utilisez pas de fichier Jenkins déclaratif, vous devrez mettre checkout scm afin que Jenkins puisse trouver les committers. Voir JENKINS-46431 .

Si vous utilisez toujours une version plus ancienne de email-ext, vous frappez JENKINS-25267 . Vous pouvez lancer votre propre email HTML:

def emailNotification() {
    def to = emailextrecipients([[$class: 'CulpritsRecipientProvider'],
                                 [$class: 'DevelopersRecipientProvider'],
                                 [$class: 'RequesterRecipientProvider']])
    String currentResult = currentBuild.result
    String previousResult = currentBuild.getPreviousBuild().result

    def causes = currentBuild.rawBuild.getCauses()
    // E.g. 'started by user', 'triggered by scm change'
    def cause = null
    if (!causes.isEmpty()) {
        cause = causes[0].getShortDescription()
    }

    // Ensure we don't keep a list of causes, or we get
    // "Java.io.NotSerializableException: hudson.model.Cause$UserIdCause"
    // see http://stackoverflow.com/a/37897833/509706
    causes = null

    String subject = "$env.JOB_NAME $env.BUILD_NUMBER: $currentResult"

    String body = """
<p>Build $env.BUILD_NUMBER ran on $env.NODE_NAME and terminated with $currentResult.
</p>

<p>Build trigger: $cause</p>

<p>See: <a href="$env.BUILD_URL">$env.BUILD_URL</a></p>

"""

    String log = currentBuild.rawBuild.getLog(40).join('\n')
    if (currentBuild != 'SUCCESS') {
        body = body + """
<h2>Last lines of output</h2>
<pre>$log</pre>
"""
    }

    if (to != null && !to.isEmpty()) {
        // Email on any failures, and on first success.
        if (currentResult != 'SUCCESS' || currentResult != previousResult) {
            mail to: to, subject: subject, body: body, mimeType: "text/html"
        }
        echo 'Sent email notification'
    }
}
28
Wilfred Hughes

Je pense qu'une meilleure façon d'envoyer des notifications par courrier électronique dans les pipelines Jenkins est d'utiliser la section de publication d'un pipeline, comme décrit dans jenkins docs au lieu d'utiliser try catch:

pipeline {
  agent any
    stages {
      stage('whatever') {
        steps {
          ...
        }
      }
    }
    post {
        always {
          step([$class: 'Mailer',
            notifyEveryUnstableBuild: true,
            recipients: "[email protected]",
            sendToIndividuals: true])
        }
      }
    }
  }
}
14
Andi