首页 文章

在管道工作流程中使用Jenkins 'Mailer'

提问于
浏览
29

我想在定义管道构建作业的 Jenkinsfile 中利用Jenkins现有的Mailer插件 . 鉴于以下简单的失败脚本,我希望每个版本都有一封电子邮件 .

#!groovy

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

构建的输出是:

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

正如您所看到的,它确实记录了它在失败后立即执行管道 step ,但没有生成电子邮件 .

在其他自由式工作中发送电子邮件,利用 mailer 工作正常,它只是通过管道工作调用 .

这与Jenkins 2.2和邮件程序1.17一起运行 .

Is there a different mechanism by which I should be invoking failed build emails? 我不需要 mail 步骤的所有开销,只需要关于故障和恢复的通知 .

3 回答

  • 57

    在管道中失败 sh 不立即将 currentBuild.result 设置为 FAILURE ,而其初始值为 null . 因此,依赖于像Mailer这样的构建状态的构建步骤可能看似不正确 .

    您可以通过添加调试打印来检查它:

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

    整个管道都包含着Jenkins提供的异常处理程序,这就是为什么Jenkins最终将构建标记为失败的原因 .

    因此,如果您想使用Mailer,则需要正确维护构建状态 . 例如:

    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: 'me@me.com', sendToIndividuals: true])
        }
    }
    

    如果您不需要重新抛出异常,可以使用 catchError . 它是一个内置的Pipeline,可捕获其范围内的任何异常,将其打印到控制台并设置构建状态 . 例:

    stage 'Test'
    node {
        catchError {
            sh 'exit 1'
        } 
        step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'me@me.com', sendToIndividuals: true])
    }
    
  • 23

    除了izzekil的出色答案之外,您可能希望根据提交作者选择电子邮件收件人 . 您可以使用email-ext执行此操作(基于their pipeline examples):

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

    如果您使用的是最近的email-ext(2.50),则可以在管道中使用它:

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

    如果您没有使用声明性Jenkins文件,则需要输入 checkout scm ,以便Jenkins可以找到提交者 . 见JENKINS-46431 .

    如果你're still on an older version of email-ext, you' ll点击JENKINS-25267 . 您可以滚动自己的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'
        }
    }
    
  • 10

    我认为在jenkins管道中发送邮件通知的更好方法是使用jenkins docs中描述的管道的post部分,而不是使用try catch:

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

相关问题