在管道工作流中使用 Jenkins 'Mailer'
Use Jenkins 'Mailer' inside pipeline workflow
我想在定义管道构建作业的 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 和 mailer 1.17。
我应该调用失败的构建电子邮件的不同机制吗?我不需要 mail
步骤的所有开销,只需要通知关于失败和恢复。
In Pipeline failed 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
。它是一个内置的管道,可以捕获其范围内的任何异常,将其打印到控制台并设置构建状态。示例:
stage 'Test'
node {
catchError {
sh 'exit 1'
}
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'me@me.com', sendToIndividuals: true])
}
除了 izzekil 的出色回答之外,您可能还希望根据提交作者选择电子邮件收件人。您可以使用 email-ext to do this (based on their pipeline examples):
step([$class: 'Mailer',
notifyEveryUnstableBuild: true,
recipients: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']])])
如果您使用的是最近的电子邮件分机 (2.50+),您可以在您的管道中使用它:
emailext(body: '${DEFAULT_CONTENT}', mimeType: 'text/html',
replyTo: '$DEFAULT_REPLYTO', subject: '${DEFAULT_SUBJECT}',
to: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']]))
如果您不使用声明性 Jenkinsfile,则需要放置 checkout scm
以便 Jenkins 可以找到提交者。参见 JENKINS-46431。
如果您仍在使用旧版本的 email-ext,请点击 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
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'
}
}
我认为在 jenkins 管道中发送邮件通知的更好方法是使用管道的 post 部分,如 jenkins docs 中所述,而不是使用 try catch:
pipeline {
agent any
stages {
stage('whatever') {
steps {
...
}
}
}
post {
always {
step([$class: 'Mailer',
notifyEveryUnstableBuild: true,
recipients: "example@example.com",
sendToIndividuals: true])
}
}
}
}
}
我想在定义管道构建作业的 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 和 mailer 1.17。
我应该调用失败的构建电子邮件的不同机制吗?我不需要 mail
步骤的所有开销,只需要通知关于失败和恢复。
In Pipeline failed 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
。它是一个内置的管道,可以捕获其范围内的任何异常,将其打印到控制台并设置构建状态。示例:
stage 'Test'
node {
catchError {
sh 'exit 1'
}
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'me@me.com', sendToIndividuals: true])
}
除了 izzekil 的出色回答之外,您可能还希望根据提交作者选择电子邮件收件人。您可以使用 email-ext to do this (based on their pipeline examples):
step([$class: 'Mailer',
notifyEveryUnstableBuild: true,
recipients: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']])])
如果您使用的是最近的电子邮件分机 (2.50+),您可以在您的管道中使用它:
emailext(body: '${DEFAULT_CONTENT}', mimeType: 'text/html',
replyTo: '$DEFAULT_REPLYTO', subject: '${DEFAULT_SUBJECT}',
to: emailextrecipients([[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']]))
如果您不使用声明性 Jenkinsfile,则需要放置 checkout scm
以便 Jenkins 可以找到提交者。参见 JENKINS-46431。
如果您仍在使用旧版本的 email-ext,请点击 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
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'
}
}
我认为在 jenkins 管道中发送邮件通知的更好方法是使用管道的 post 部分,如 jenkins docs 中所述,而不是使用 try catch:
pipeline {
agent any
stages {
stage('whatever') {
steps {
...
}
}
}
post {
always {
step([$class: 'Mailer',
notifyEveryUnstableBuild: true,
recipients: "example@example.com",
sendToIndividuals: true])
}
}
}
}
}