利用 Jenkins Pipeline 编写通用脚本捕获 Job 执行信息
问题产生背景
最近企业微信更新了 bot,老板作为腾讯前员工,坚持要在内部办公用起来。当然了,这个支持 markdown 友好通知的机器人,对于能够在即时聊天工具里面告诉其他人一些工作情报,还是蛮方便的。
需要通知的信息
因为只是想试用一下看看效果,所以一开始我们只会拿 Jenkins 执行后的简单信息来告诉相关人员:
- 谁执行的
- 执行了什么项目
- 对应的是什么分支
- 执行结果是成功还是失败
- 执行任务的日志详情地址
解决思路
- 首先是要确保怎么拿到这些最基础的信息。有些信息是 Freestyle Project 即使加上插件还是很难获取得到,但 Pipeline 的 script 却可以通过一些技巧拿到。
- 紧接着要考虑的是,怎么样不在每个项目都重复写一次解析信息任务。所以可以写成一个独立通用的 Pipeline 通知任务,作为目标 Job 无论失败或成功都会执行的 downstream 任务。
- 最后,怎么将信息从主任务告诉给我们通用通知任务。这其实作为子任务的 Pipeline 可以一直朔源 upstream 的任务去获取信息。
开始处理
在企业微信里面创建一个 bot,然后该 bot 会提供一个 webhook 的 url。
再者,针对思路的 1, 3 点,我们可以建立一个 Pipeline 任务,去掉勾选的“使用 Groovy 沙盒”,填充最基本的格式:
pipeline { agent any stages { stage ('Notify') { steps { notify() } post { always { echo "OK" } } } } }
language-groovy
其中的 notify
函数就是我们要处理的东西。接下来就是使用 Groovy 语言来自由处理我们的东西,只要能使用编程语言,一切都将是简单而美好的。需要注意的是,获取构建信息的时候要使用 NonCPS 注解来避免因为 CPS 优化导致的异常,这里定义一些获取基本信息的函数:
// get the first build for fetching the information of project and job @NonCPS def getFirstUpstreamBuild() { return currentBuild.upstreamBuilds[0] } // get the last build for fetching the information of project and job @NonCPS def getLastUpstreamBuild() { return currentBuild.upstreamBuilds[currentBuild.upstreamBuilds.length - 1] } // get job id def getJobId() { return getFirstUpstreamBuild().id } // get job status def getJobStatus() { return getLastUpstreamBuild().currentResult } // get project name def getProjectName() { return getFirstUpstreamBuild().projectName } // get the build variable for fetching the information of user def getEnv() { return getFirstUpstreamBuild().buildVariables } // get user name def getUserName() { def build = getFirstUpstreamBuild().rawBuild def cause = build.getCause(hudson.model.Cause.UserIdCause.class) return cause.getUserName() } // get the branch of git def getGitBranch() { return getEnv()['GIT_BRANCH'] } // get the url of job def getJobUrl() { return getEnv()['BUILD_URL'] }
language-groovy
补个 notify
函数来作为处理函数,这里是做的就是告诉机器人要说什么:
def notice() { def targetUrl = "$webhook_url" def logUrl = "${getJobUrl()}console" def logLevel = getJobStatus() == "SUCCESS" ? "info" : "warning" def data = "\ {\ \"msgtype\": \"markdown\",\ \"markdown\": {\ \"content\": \"<font color=\\\"${logLevel}\\\">${getUserName()}</font> 执行 <font color=\\\"${logLevel}\\\">${getProjectName()}</font> 发布 **<font color=\\\"${logLevel}\\\">${getJobStatus()}</font>**\ \n> 日志地址:[点击查看](${logUrl})\ \n> 发布分支:${getGitBranch()}\"\ }\ }\ " sh "curl -X POST '${targetUrl}' -H 'Content-Type: application/json' -d '${data}'" }
language-groovy
最后,在所要通知的构建项目的“Post-build Actions”里面添加个“Build other projects”,内容为前面的 Pipeline 任务,勾选“Trigger even if the build fails”来确保 Pipeline 能处理 upstream 的成功和失败。