运维咖啡吧

享受技术带来的乐趣,体验生活给予的感动

SVN Hooks的介绍及使用

阅读此篇文章你可以: - 对SVN Hooks有一定的了解 - 获取两个最常用的SVN Hooks案例

SVN hooks介绍

Hooks 钩子,主要实现的功能就是在特定事件发生之前或者之后自动执行事先定义好的脚本代码来实现某些功能,类似于JS中的监听事件、MySQL中的触发器、Django中的signals信号等

大多数开发语言都可以用来编写hooks脚本,常用的如windows下的bat、vb,linux下的shell、python等

SVN中的hooks按照所在位置可以分为两类,客户端hooks和服务端hooks,日常使用中服务端hooks使用更广,我们也以服务端hooks介绍为主

SVN服务端hooks主要有以下9种:

pre-lock:文件加锁前执行,不常用

post-lock:文件加锁后执行,通常用来发送锁定事件通知,需要传递两个参数给hooks脚本,按照顺序依次为:1.版本库路径,2.锁定路径的认证用户名

per-unlock:文件解锁前执行,不常用

post-unlock:文件解锁后执行,通常用来发送解锁事件通知,需要传递两个参数给hooks脚本,按照顺序依次为:1.版本库路径,2.解锁路径的认证用户名

start-commit:开始提交时执行,在pre-commit之前,通常用来确定用户是否有提交权限

pre-commit:提交之前执行,在start-commit之后,通常用来对提交内容的检查,例如我们后边要介绍的利用pre-commit做提交log的合规性检查,需要传递两个参数给hooks脚本,按照顺序依次为:1.版本库路径,2.提交事务的名称

post-commit:提交完成后执行,这应该是使用最广的hooks之一,通常用来在提交之后发送提交通知,甚至是利用它来做自动化的CI/CD等操作,需要传递两个参数给hooks脚本,按照顺序依次为:1.版本库路径,2.提交创建的修订版本号

pre-revprop-change:在修改revision属性之前执行,不常用

post-revprop-change:在修改revision属性之后执行,不常用

SVN hooks应用

svn hooks位于svn版本库的hooks文件夹下,例如svn目录为/home/svn/repos,仓库名称为ops-coffee,那么hooks就位于/home/svn/repos/ops-coffee/hooks/目录下,文件夹下的.tmpl的文件为hooks的模板文件,以shell脚本的方式展示了hooks该如何使用

注意这些hooks文件都要有可执行权限

如果我们要使用svn的hooks,那么就在hooks文件夹下新建文件名为hooks类型的文件(例如pre-commit,没有后缀,名字也不能随意改)并为文件赋予可执行权限,或者直接复制模板文件去掉.tmpl后缀然后进行修改

接下来我们看两个常用的例子来加深对hooks的理解

限制log提交规则

良好的svn log规范,有利于我们对项目的管理,尤其在多人协作开发的过程中,清晰、规范的log能大大降低沟通成本,提升开发效率。因此我们会制定相应的规则要求所有开发按照一定的规范提交log,这些规则通常依赖所有参与者的自觉,效果可能并不是很好,有么有办法强制参与者按照既定的规则提交log呢?

pre-commit这个hook就能很好的帮助我们实现这个需求,每一次代码提交前都会触发pre-commit脚本,那么我们就可以在脚本中判断log规则是否跟我们预先定义的一样,不一样则不允许提交

假如我们有如下log提交规范


代码提交记录以简洁、表意清晰为基本原则,建议每完成一个功能模块都单独提交一次代码,每个提交记录应包含以下信息:[功能模块][任务类别]描述,例如:

[功能模块]

当前提交的功能模块名字,不固定,例如:新闻、评论、ops-coffee活动等

[任务类别]

任务类别只包括dev、bug、misc几种,不能自定义

描述


接下来我们利用pre-commit每次提交前检查是否符合上边定义的规范,具体配置如下

1.我们先创建pre-commit的hook脚本,内容如下

#!/bin/bash
REPOS="$1"
TXN="$2"

SVNLOOK=/usr/bin/svnlook  
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS")
LOGFORMAT="\[(.+)\]\[(dev|bug|misc)\](.+)$"

# 判断提交log与预设的规则是否匹配
[[ ${LOGMSG} =~ ${LOGFORMAT} ]] || exit 1

exit 0

LOGFORMAT为我们根据规范写的正则表达式,符合[xxx][(dev|bug|misc)]xxx这样的规则即可

通过svnlook命令拿到本次提交的log记录,然后与预设的正则进行匹配,通过则继续往下走,不通过则直接退出状态1

最终exit退出状态为0时则表示全部规则验证通过,进行后续的代码提交操作,非0时表示验证失败

可以在hook脚本中写多条不同的验证规则,每条规则不通过时返回不同的状态码,这样后续不通过就知道哪里验证失败了,例如检测提交的文件名不能包含有空格,不然就exit 2等

2.别忘了给hook脚本加上可执行权限

# chmod +x /home/svn/repos/ops-coffee/hooks/pre-commit

这样就ok了,很简单,再提交log时就会按照定义的规则来判断,如果判断不通过则直接报错'Commit blocked by pre-commit hook'让你重新写log

提交成功发送邮件通知

看了上边强制log提交规则的示例,想必对SVN hooks有了一定的了解,那么我们趁热打铁再来看一个提交成功发送邮件的例子

假如我们有一个账号叫merge,专门用来合并上线代码,经过这个账号合并的代码自动触发发布API更新代码到生产环境,其他账号合并的代码发送邮件通知给[email protected]的邮箱,那么该如何实现呢?

1.首先是代码提交(合并)之后触发,那么就需要用到post-commit这个hook,具体内容如下

# cat /home/svn/repos/ops-coffee/hooks/post-commit
#!/bin/bash
REPOS="$1"
REV="$2"

export LANG=zh_CN

# svn info
AUTHOR=$(svnlook author -r $REV $REPOS)
MESSAGE=$(svnlook log -r $REV $REPOS)
CHANGED=$(svnlook changed -r $REV $REPOS)
REPERTORY=$(echo $REPOS | awk -F'/' '{print $NF}')

LOGFILE="/tmp/.svn_hooks_post_commit.log"
echo "$AUTHOR

版本库:
$REPERTORY - $REV

更新LOG:
$MESSAGE

更新内容:
$CHANGED
" > $LOGFILE


if [ $AUTHOR == merge ];then
    curl -H "Authorization:Token 3w2290j02baa1xb8cemec35k8b" "https://ops-coffee.cn/api/deploy?p=${REPERTORY}&v=${REV}"
else
    mail -s "SVN 更新通知:系统版本号【$REV】" [email protected] < $LOGFILE
fi

通过svnlook命令获取到提交者、LOG、更新内容的数据,然后将数据拼装成邮件的正文,以便下边发送邮件

然后if判断提交者是不是merge,如果是则通过curl命令调用deploy的API,API会根据所传的两个参数v:仓库名和p:版本号将代码发布到对应项目的生产环境上,如果不是则发送邮件通知

以上为演示代码,生产环境的发布各位根据自己实际情况调整

2.同样不要忘了给脚本添加可执行权限

# chmod +x /home/svn/repos/ops-coffee/hooks/post-commit

这样就ok了,每次代码提交(合并)之后就会判断是哪个账号的提交,确定是发送邮件通知还是直接部署上线