简要
jenkins集成gitlab有两种方式:
- 通过 jenkins 自带的通用 webhook 触发器。
- 通过 gitlab 或者 gitlab-branch-source 之类的插件。
本文档介绍通用 webhook 触发器,更加灵活。
- 可以自定义 webhook 地址的请求参数,用于限定 webhook 的 get 参数。即仅当 webhook 包含这个参数的时候,才会触发构建。
- 可以接收 gitlab 通过 webhook 地址传递过来的 body(json数据),并且可以从 json 数据中任意的获取数据,例如分支名等
- 可以自定义 webhook 的 token
安装通用 webhook 插件
代码 demo
将demo放在 http://git.xxx.com/devops/simple-java-maven-app.git
git clone https://github.com/Spinestars/simple-java-maven-app
cd simple-java-maven-app
git remote add origin http://git.xxx.com/devops/simple-java-maven-app.git
git add .
git commit -m "Initial commit"
git push -u origin master
maven工具
参见文章:jenkins-构建工具集成
共享库 jenkinslib
http://git.xxx.com/devops/jenkinslib.git
jenkinslib在jenkins的配置,参见文章:jenkins☞003共享库
src/org/devops/build.groovy
👙此代码的执行一定需要先配置 jenkins maven 全局工具
package org.devops
def Build(buildType, buildShell){
def buildTools = ["mvn":"M2", "npm":"NPM"]
println("当前选择构建类型:${buildType}")
buildHome = tool buildTools[buildType]
if ("${buildType}" == "npm"){
sh """
export NODE_HOME=${buildHome}
export PATH=\$NODE_HOME/bin:\$PATH
${buildHome}/bin/${buildType} ${buildShell}"""
}else{
sh "${buildHome}/bin/${buildType} ${buildShell}"
}
}
src/org/devops/gitlab.groovy
👙jenkins-gitlab-secretText-token 是标题:创建jenkins访问gitlab的凭据 的内容。
package org.devops
// 封装HTTP,用于jenkins向gitlab发起请求
def HttpReq(reqType, reqUrl,reqBody ){
def gitServer = "http://git.xxx.com/api/v4"
withCredentials([string(credentialsId: 'jenkins-gitlab-secretText-token', variable: 'GITLABTOKEN')]) {
response = httpRequest acceptType: 'APPLICATION_JSON_UTF8',
consoleLogResponseBody: true,
contentType: 'APPLICATION_JSON_UTF8',
customHeaders: [[maskValue: false, name: 'PRIVATE-TOKEN', value: "${GITLABTOKEN}"]],
httpMode: "${reqType}",
url: "${gitServer}/${reqUrl}",
wrapAsMultipart: false,
requestBody: "${reqBody}"
}
return response
}
// 变更 gitlab 提交状态
def ChangeCommitStatus(projectId,commitSha,status){
commitApi = "projects/${projectId}/statuses/${commitSha}?state=${status}"
response = HttpReq('POST', commitApi, '')
println(response)
return response
}
src/org/devops/tools.groovy
package org.devops
def toEmail(userEmail,status){
emailext body: """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<img src="http://<jenkins>/static/0eef74bf/images/headshot.png">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
</td>
</tr>
<tr>
<td>
<ul>
<li>项目名称:${JOB_NAME}</li>
<li>构建编号:${BUILD_ID}</li>
<li>Git用户:${userFullName}(${userName})</li>
<li>Git分支:${branch}</li>
<li>CommitShortID:${commitShort}</li>
<li>CommitID:${commitSha}</li>
<li>构建状态: ${status}</li>
<li>项目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
</ul>
</td>
</tr>
<tr>
</table>
</body>
</html> """,
subject: "Jenkins-${JOB_NAME}项目构建信息 ",
to: userEmail
}
Pipeline文件 jenkinsfile
定义一个 jenkinsfile 库,存 jenkinsfile 文件。
http://git.xxx.com/devops/jenkinsfiles.git
#!groovy
@Library('jenkinslib@master') _
def build = new org.devops.build()
def gitlab = new org.devops.gitlab()
def tools = new org.devops.tools()
//def deploy = new org.devops.deploy()
String buildType = "${env.buildType}"
String buildShell = "${env.buildShell}"
//String deployHosts = "${env.deployHosts}"
String gitUrl = "${env.gitUrl}"
String branchName = "${env.branchName}"
// 当存在 runOpts 变量并且值等于 GitlabPush 的时候,则分支名从 webhook 数据中获取。
if ("${runOpts}" == "GitlabPush") {
branchName = branch - 'refs/heads/'
env.commitShort = commitSha.take(8)
currentBuild.description = """Git用户: ${userFullName}(${userName})\nGit分支:${branchName}\nCommit: ${commitShort}"""
gitlab.ChangeCommitStatus(projectId, commitSha, "running")
}
pipeline{
agent { node { label "agent01" } }
stages {
stage("checkout") {
steps {
script {
checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], userRemoteConfigs: [[credentialsId: 'gitlab-jenkins-pull-token', url: "${giturl}"]]])
}
}
}
stage("build") {
steps {
script {
build.Build(buildType, buildShell)
}
}
}
}
post {
always {
script {
println('always')
}
}
success {
script {
println('success')
gitlab.ChangeCommitStatus(projectId, commitSha, "success")
tools.toEmail(userEmail, "success")
}
}
failure {
script {
println('failure')
gitlab.ChangeCommitStatus(projectId, commitSha, "failed")
tools.toEmail(userEmail, "failed")
}
}
aborted {
script {
println('aborted')
gitlab.ChangeCommitStatus(projectId, commitSha, "canceld")
tools.toEmail(userEmail, "aborted")
}
}
}
}
jenkins web 配置
如果一切配置好,则 jenkins 构建的时候会输出 gitlab 通过 webhook 传递过来的信息,如下示例:
{"object_kind":"push","event_name":"push","before":"332e5cfeff94b9dec3d766955c533d2ab7e62bf4","after":"39cf0cd49ff6f156e76a171b6b8ab85ce512a8e5","ref":"refs/heads/master","checkout_sha":"39cf0cd49ff6f156e76a171b6b8ab85ce512a8e5","message":null,"user_id":1,"user_name":"zyh","user_username":"root","user_email":"","user_avatar":"http://git.xxx.com/uploads/-/system/user/avatar/1/avatar.png","project_id":68,"project":{"id":68,"name":"simple-java-maven-app","description":"","web_url":"http://git.xxx.com/devops/simple-java-maven-app","avatar_url":null,"git_ssh_url":"ssh://[email protected]:2222/devops/simple-java-maven-app.git","git_http_url":"http://git.xxx.com/devops/simple-java-maven-app.git","namespace":"devops","visibility_level":0,"path_with_namespace":"devops/simple-java-maven-app","default_branch":"master","ci_config_path":"","homepage":"http://git.xxx.com/devops/simple-java-maven-app","url":"ssh://[email protected]:2222/devops/simple-java-maven-app.git","ssh_url":"ssh://[email protected]:2222/devops/simple-java-maven-app.git","http_url":"http://git.xxx.com/devops/simple-java-maven-app.git"},"commits":[{"id":"39cf0cd49ff6f156e76a171b6b8ab85ce512a8e5","message":"Update pom.xml","title":"Update pom.xml","timestamp":"2022-05-08T01:37:58+00:00","url":"http://git.xxx.com/devops/simple-java-maven-app/-/commit/39cf0cd49ff6f156e76a171b6b8ab85ce512a8e5","author":{"name":"zyh","email":"[email protected]"},"added":[],"modified":["pom.xml"],"removed":[]},{"id":"2bf69c80b1713021be07700c4598db4884de8e1a","message":"Update pom.xml","title":"Update pom.xml","timestamp":"2022-05-08T01:36:22+00:00","url":"http://git.xxx.com/devops/simple-java-maven-app/-/commit/2bf69c80b1713021be07700c4598db4884de8e1a","author":{"name":"zyh","email":"[email protected]"},"added":[],"modified":["pom.xml"],"removed":[]},{"id":"332e5cfeff94b9dec3d766955c533d2ab7e62bf4","message":"Update README.md","title":"Update README.md","timestamp":"2020-09-06T18:16:16+08:00","url":"http://git.xxx.com/devops/simple-java-maven-app/-/commit/332e5cfeff94b9dec3d766955c533d2ab7e62bf4","author":{"name":"lizeyang","email":"[email protected]"},"added":[],"modified":["README.md"],"removed":[]}],"total_commits_count":3,"push_options":{},"repository":{"name":"simple-java-maven-app","url":"ssh://[email protected]:2222/devops/simple-java-maven-app.git","description":"","homepage":"http://git.xxx.com/devops/simple-java-maven-app","git_http_url":"http://git.xxx.com/devops/simple-java-maven-app.git","git_ssh_url":"ssh://[email protected]:2222/devops/simple-java-maven-app.git","visibility_level":0}}
👙通过 json.cn 格式化。
通过示例,我们可以在 jenkins webhook 通用触发器里配置变量来获取所需的数据,例如本次 git 提交人、本次 git commit等
同时还会输出 jenkins webhook 触发器用户配置的一些参数或者变量,示例:
Contributing variables:
branch = refs/heads/dev
runOpts = GitlabPush
runOpts_0 = GitlabPush
branch 变量就是用户自定义的获取 gitlab 通过 webhook 传递过来的 json 数据的变量。
runOpts 变量就是用户自定义的 webhook get 参数。
webhook 通用触发器配置
通过pipeline方式设置 webhook 通用触发器配置。
通过 jenkins webui 设置通用触发器配置。
设置webhook传递过来的post内容的映射变量
具体的设置可以通过上述的 post content 示例来对照配置。
需要设置的变量有:
- branch=$.ref
- userFullName=$.user_name
- userName=$.user_username
- userEmail=$.user_email # 这个user_email 取得是gitlab用户的公共邮箱(默认gitlab不会将账户注册邮箱传递到这个公共邮箱,需要用户自己在web用户配置里设置)
- projectId=$.project.id
- commitSha=$.checkout_sha
- before=$.before
- after=$.after
- object_kind=$.object_kind
设置webhook get参数和token
token可以随便写
开启各种控制台日志输出
经过上述配置,最终生成的 webhook 地址是:
http://
checkout 方式获取Jenkinsfile
👙需要先配置 jenkins 拉取 gitlab 代码的凭证
凭证类型:username with password
凭证id:jenkins-gitlab-pull-code
gitlab web 配置
将webhook地址填入网址
增加构建描述信息
Jenkins构建工程中对应的一些变量:
http://jkspj.pengwin.com:18080/job/test.simple-java-maven-app/pipeline-syntax/globals#currentBuild
我们可以给这些变量赋值,从而在jenkins pipeline或者jenkins web上展示一些自定义信息。
例如:
- currentBuild.description 变量,这个变量里的值会显示在构建列表里,如图所示
👙在上面的jenkinsfile已经包含了上面截图的效果.
if ("${runOpts}" == "GitlabPush") {
branchName = branch - 'refs/heads/'
commitShort = commitSha.take(8)
currentBuild.description = """Git用户: ${userFullName}(${userName})\nGit分支:${branchName}\nCommit: ${commitShort}"""
}
将构建状态反馈给gitlab
如果你用 gitlab 插件,则这个实现不难,但如果用通用 webhook 触发器,则这个实现是需要调用 gitlab api 接口。
相关的 gitlab api 接口文档:
https://docs.gitlab.com/ee/api/commits.html#post-the-build-status-to-a-commit
官方示例:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/17/statuses/18f3e63d05582537db6d183d9d557be09e1f90c8?state=success"
gitlab build 状态:pending
, running
, success
, failed
, canceled
👙可以看到 gitlab 的状态单词和 jenkins 的状态单词是不一样的,因此jenkins pipeline里调用 gitlab api 传递的状态要用 gitlab 的状态单词。
创建jenkins访问gitlab的凭据
- 创建 gitlab 专属用户:jenkins
- 将所有需要自动化的仓库授予 jenkins,权限为 Maintainer
- 用 jenkins 用户登录 gitlab 网站,并创建个人令牌,令牌权限是 api
- 登录 jenkins 网站,创建凭据:
- 凭据类型:secret text
- 凭据ID:jenkins-gitlab-secretText-token
过滤 gitlab push 请求
默认新建分支都会触发jenkins构建。
通用webhook触发器,可以进行如下设定:
- 当给定的正则可以匹配给定的字符串时,则此次构建不执行。
👙给定的字符串,从 post json 中获取,这样,正则就可以过滤推送的事件。
Given the following generic variables are configured:
| variable | expression | expressionType | defaultValue | regexpFilter |
| object_kind | $.object_kind | JSONPath | | |
| before | $.before | JSONPath | | |
| after | $.after | JSONPath | | |
| ref | $.ref | JSONPath | | |
| git_ssh_url | $.repository.git_ssh_url | JSONPath | | |
Given filter is configured with text: $object_kind $before $after
Given filter is configured with expression: ^push\s(?!0{40}).{40}\s(?!0{40}).{40}$
第一组是根据 post json 设置的变量
第二组是根据变量定义的字符串
第三组是匹配字符串的正则
对应的 jenkins web 配置截图:
配置邮件发送
jenkins web 配置 smtp 服务器,见截图:
邮件模板和发邮件的代码,参见标题:jenkinslib.src/org/devops/tools.groovy
pipeline调用,参见标题: jenkinsfile.post()部分
合并分支触发流水线
👙依赖标题:将构建状态反馈给gitlab。
只有当源分支最后一次流水线成功的时候,才允许合并到目标分支。
实现上述需求,只需要开启gitlab的功能即可:
效果如下: