背景

Gerrit 作为一个使用广泛的代码评审平台,我们使用它的时候,往往会希望它能够一次性多完成几件事情,而不是简单的提交代码,合并代码。这个时候就需要用到串联事件的 hook 方法。Hook 作为钩子,能够搭建起事件之间的桥梁,实现在一个事件结束时自动触发我们想要触发的其他事件,从而完成我们对于代码评审相关的其他需求比如通知或者自动触发流水线程序等等。本文就来探讨一下 gerrit 相关的不同 hook 配置方式以及它们的优缺点。

1.Gerrit 不同 hook 方式介绍:

Gerrit 的 hook 方式按照 hook 事件配置地方的不同主要分为三种方式,客户端 hook,webhook 以及服务端 hook。客户端 hook 顾名思义是在本地客户端仓库配置的 hook 事件,它能够拦截本地仓库的一些事件,并作出相应的反应。然而,客户端 hook 配置无法影响远程仓库的操作流程,而一般我们更加关注的是远程仓库的代码变化以及 hook 操作,所以客户端 hook 不在本文的讨论重点。Webhook 以及服务端 hook 都能够拦截远程仓库的相关事件,接下来一一介绍 webhook 和服务端 hook 的配置方式以及优劣。

2.Webhook 配置方法:
环境配置:
gerrit 版本:3.4.0
webhook 配置方法:
gerrit 的项目的 webhook 设置主要分两个部分,一个部分在服务端代码的 gerrit/review_site/etc/gerrit.config 中,配置格式如下:

[plugin "webhooks"]
connectionTimeout = 3000
socketTimeout = 2500
maxTries = 300
retryInterval = 2000
threadPoolSize = 3

(connectionTimeout 为连接超时时间,socketTimeout 为 socket 连接超时时间,maxTries 为最大尝试次数,retryInterval 为尝试间隔时间,threadPoolSize 为进程池个数)
另一部分仓库内的 webhook 配置是由 All-Projects 仓库下的配置文件统一配置的,其他仓库完全继承的,具体操作方法如下:

①. 首先将 All-Projects 仓库 clone 下来:

git clone "http://admin@<gerrit-address>-:<gerrit-port>/a/All-Projects"

②. 然后进入到仓库内并切换到 config 分支

cd All-Projects/
git fetch origin refs/meta/config:refs/remotes/origin/meta/config
git checkout meta/config

③. 在 All-Projects 主目录下创建 webhooks.config 文件,并添加以下内容(示例仅作参考):

[remote "events"]
url = http://11.11.11.111:9000/system_hook/v1/events
maxTries = 3
sslVerify = false
event = patchset-created
event = ref-updated
event = project-created
event = change-merged
event = hashtags-changed

(其中 url 为 webhook 对应的 url,maxTries 为最大尝试次数,sslVerify 为是否启用 ssl 验证,event 表示哪些事件会触发 webhook 操作)

④. 提交配置修改并重启 gerrit 服务:

git commit -am "Add webhooks config file"
git push origin meta/config:meta/config

从以上配置方式可以看出,webhook 所配置的 hook 事件都是 gerrit 事先定义好的,包括事件类型以及消息体格式,我们只能使用而不能更改。这就容易导致一个问题,比如我们想要得到代码提交的详细信息来触发 hook 事件,就有可能无法做到,因为 gerrit 定义的消息体并未传递我们想要的信息。这时,就有机会用到第三种 hook 方式,服务端 hook。

3.服务端 hook 配置:

服务端 hook 主要分为两步:
①.在服务端目录/gerrit/review_site/下创建文件夹 hook

cd /gerrit/review_site/ & mkdir hooks

②.根据事件类型不同创建以事件类型名命名的脚本,并自定义脚本内容。当系统检测到有相关动作发生时,会自动触发所定义的脚本。
服务端的 hook 事件主要分为两类,一个是 Synchronous Hooks(同步 hook),一个是 Asynchronous Hooks(异步 hook),同步 hook 一般是事件发生时触发的事件类型,例如 ref-update、submit 等等,异步 hook 一般是事件发生后触发的事件类型,例如 patchset-created、change-merged、ref-updated 等。

服务端 hook 的优势在于可以自定义事件的后续动作,以及发送的消息体内容,这样在很多应用场景中都会更加灵活多变,更容易符合业务的需求。

4.Gerrit hook 的应用场景示例
Webhook 和服务端 hook 由于其特性的不同,有着不同的应用场景。例如,我们可以使用 webhook 接入通讯工具,当仓库有变更时发送消息通知相关人员;或者通过服务端 hook 接入流水线触发脚本,在仓库变更时自动触发代码审查相关的流水线。

例如,以下代码片段是 ref-update 动作对应的脚本代码,ref-update 动作发生在用户正在同步代码,这时我们可以通过相关 git 命令获取到提交的相关信息,如提交信息 commitmsg、提交日期 commitdate,或者从动作的传参中获取信息如上传人 uploader、提交 id commitid 等,最后我们可以通过 http 请求将各种消息发送到远端,做进一步的处理。

下图是整个流程的示意图。在远端服务器,我们接入了 kafka 消息队列用于消息的处理和转发。kafka 消息队列最终把处理好的消息接入到通讯工具,通知相关的责任人代码变更的详细信息。

总结

Gerrit 根据其业务需求主要有三种 hook 的配置方式,用的相对较多的是 webhook 和服务端 hook 方式,区别在于 webhook 的动作以及消息体格式是 gerrit 定义好的,而服务端 hook 可以自定义 hook 后续动作以及消息格式,如果有对动作以及消息格式有要求的应用场景,建议选择服务端 hook。


↙↙↙阅读原文可查看相关链接,并与作者交流