gitlab触发jenkins的job是通过webhook完成的,也就是一次http请求,请求体在jenkins的job的ConsoleOutput中可以看到。长这样子(网页上的json是一坨,这里format了一下):
GenericWebhookEnvironmentContributor
Received:
{
"object_kind": "push",
"before": "0000000000000000000000000000000000000000",
"after": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
"ref": "refs/heads/xxx-dev",
"checkout_sha": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
"message": null,
"user_id": 142,
"user_name": "xxx",
"user_email": "xxx@x.com",
"project_id": 531,
"repository": {
"name": "test",
"url": "ssh://git@172.16.*.*:*/test.git",
"description": "test",
"homepage": "http://172.16.*.*:*/test",
"git_http_url": "http://172.16.*.*:*/test.git",
"git_ssh_url": "ssh://git@172.16.*.*:*/test.git",
"visibility_level": 10
},
"commits": [
{
"id": "1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
"message": "test\n",
"timestamp": "2020-03-17T21:34:10+08:00",
"url": "http://172.16.*.*:*/test/commit/1d09c45658d42cd6c8c41d3370d4a2d5b46690b4",
"author": {
"name": "xxx",
"email": "xxx@x.com"
}
}
],
"total_commits_count": 1
}
找对分支名了吗
在单元测试之类的触发中,通常需要跑pipeline的分支是不可预知的,这就需要在jenkins脚本中进行动态获取。我们可以注意到上面有一个字段ref
的值为refs/heads/xxx-dev
,看上就是他了,但实际上这是不能用的,我们先试一下。
在jenkins脚本中,可以直接获取到ref的值:
node(label) {
println ref
}
这里println
是groovy的语法,jenkins的PiplineScript基本上就是groovy。
然后我们来试一下直接用ref当分支:
node(label) {
stage('test') {
dir('/home/jenkins/agent/workspace/test') {
git branch: ref, credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
}
}
}
然后会看到这样的报错:
using GIT_ASKPASS to set credentials
> git fetch --tags --force --progress -- http://172.16.*.*:*/test.git +refs/heads/*:refs/remotes/origin/* # timeout=10
> git rev-parse refs/remotes/origin/refs/heads/xxx-dev^{commit} # timeout=10
> git rev-parse refs/remotes/origin/origin/refs/heads/xxx-dev^{commit} # timeout=10
> git rev-parse origin/refs/heads/xxx-dev^{commit} # timeout=10
...
ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.
第一种方法调整分支
我们有两个办法让jenkins拿到准确分支,先说第一种,checkout的方式:
node(label) {
stage('test') {
dir('/home/jenkins/agent/workspace/test') {
git branch: 'develop', credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
sh '''
git checkout ${ref##*/}
'''
}
}
}
在script里调用sh来实现checkout,这里${ref##*/}
就是xxx-dev
,如果写${ref#*/}
就是heads/xxx-dev
,如果写${ref}
就是refs/heads/xxx-dev
但是有些情况下,checkout会报错:
+ git checkout xxx-dev
error: The following untracked working tree files would be overwritten by checkout:
vendor/github.com/PuerkitoBio/purell/.gitignore
vendor/github.com/PuerkitoBio/purell/.travis.yml
...
这时我们就该考虑能不能让jenkins上来就在指定分支上工作呢,其实是可以的,我们来看第二种方法。
第二种方法调整分支第二种方法就是借助groovy代码对ref
变量做手脚,简单思路就是用split
函数将字符串分割,然后取后面的部分。
ref.split("refs/heads/")
这里有点奇怪的是,他的返回值首先是个引用类型,如果直接println ref.split("refs/heads/")
会看到[Ljava.lang.String;@618657aa
,所以不能直接ref.split("refs/heads/")[0]
:
def arr = ref.split("refs/heads/") as List
第二点比较奇怪的是,在其他语言比如C#、Java、go中,这种情况返回的数组只包含一个元素,而这里返回的却是两个元素:
def arr = ref.split("refs/heads/") as List
println arr
// [, xxx-dev]
所以我们需要取arr[1]
来拿到分支名,这样一来我们就可以将上面的脚本改写:
node(label) {
stage('test') {
dir('/home/jenkins/agent/workspace/test') {
def arr = ref.split("refs/heads/") as List
def currentBranch = arr[1]
git branch: currentBranch, credentialsId: 'xxxx', url: 'http://172.16.*.*:*/test.git'
}
}
}
感谢
参考文章:我在这里看到了split
;在这里看到了as LinkedList
。感谢以上作者的文章!如果你有更巧妙的方法,欢迎留言告诉我!