GitLab CE 服务器端钩子

以前的项目中,我们使用过GitLab+Jenkins实现自动化构建,在GitLab的项目上设置WebHook钩子,当开发者Push代码上来时,会触发Jenkins对应Job的执行,Job的任务就是从GitLab拉取代码,进行编译等操作。不过以前是一个项目对应一个钩子,目前我们项目使用了Spring Cloud微服务,一个项目包含多个Module,物理上每个Module其实就是对应项目中的一个目录,我们想在某个Module有代码更新时触发该Module的构建,而不会去构建整个项目,同时公用的Module触发构建时,依赖于它的其它Module也要被触发构建,不过这是Jenkins提供的功能,和GitLab无关。

对于这种需求,目前没有看到GitLab UI界面有提供配置,于是钻研了GitLab服务器端钩子的编写方法。服务器端钩子存放目录如下:

/var/opt/gitlab/git-data/repositories/GitLab用户名/项目名称.git/custom_hooks

其中GitLab用户名和项目名称根据具体项目而定。刚开始没有custom_hooks目录,先创建这个目录,然后在该目录下创建一个可执行文件,名称为:post-receive,这个可执行文件内容可使用多种语言编写,只需要在头部写好相应的解析器,比如bash脚本就写:#!/bin/bash。post-receive内容示例如下:

#!/bin/bash

while read oldrev newrev  //这两个参数是脚本被调用时从标准输入读取的
do
echo $oldrev  // 这样写,客户端push代码时,会在客户端回显该值,不必要的话可以去掉
echo $newrev
done

//得到所有修改的文件路径,并且去重

dirsPUSH=`git diff HEAD^ HEAD –name-only | xargs dirname | cut -d ‘/’ -f1| sort -u`

for DIR in $dirsPUSH  // 遍历路径,就是查找哪个Module有代码更新
do

// 触发Jenkins任务运行
curl -X GET http://user:password@www.jenkinssite.com/job/$DIR/build?token=myToken
done

其中一行代码:dirsPUSH=`git diff HEAD^ HEAD –name-only | xargs dirname | sort -u`,让我抓狂了一个下午,这句代码的意思是获取到所有变更文件的路径,比如myProject目录下Module1子目录的文件demo.java更新了,dirsPUSH就包含这么一个值:Module1/demo.java,我们通过dirname和sort处理后,就得到Module1这个值,然后将这个值和Jenkins用户名密码网址token(自己在Jenkins中设置)拼接成curl操作的地址,Jenkins中对应Job就立即执行构建了。针对项目中的每个Module,我们都在Jenkins中建立一个Job,因此只要这个Module有代码更新,Jenkins中对应的Job就开始构建。在我们的项目中,每个Job的任务就是编译源代码,打包成Docker镜像,然后自动上传到阿里云的容器镜像服务中等待部署。

StackOverflow上很多帖子都说这样写来获取更新的文件路径:

dirsPUSH=`git diff  –name-only  $oldrev $newrev | xargs dirname | cut -d ‘/’ -f1| sort -u`,这样写会出现“fatal: this operation must be run in a work tree”错误,如果加上“–work-tree=repo目录”,却又出现“Not a git repository”错误。手动把这些命令拿到对应目录下执行又不出错,直接执行post-receive代码也正常,只是在post-receive代码被钩子系统调用时才出现这样的错误,反反复复测试各种情况,依然是上面两个错误,让人百思不得姐啊。还好后面找到了能完成这个任务的写法,即“git diff HEAD^ HEAD”,参考了这里,再想想花了那么多时间在这一个命令上,心碎了一地。

发表评论

电子邮件地址不会被公开。