svn的hook机制,跟其他很多类似的工具一样,hook机制的本身就是在某个具体的时机所触发的内容,类似于事件驱动的回调。
场景说明
举个简单的例子,我们使用svn commit的时候如果希望对日志的信息进行判断,如果日志中没有包含指定格式的Ticket号时,提示相关的错误信息,不允许提交。这样的场景,就是hook机制起作用的最为常见的情形之一。这篇文章中会用最简单的方式来演示这个机制的设定和使用方式。
svn的hook
svn的hook模版
在创建的svn的仓库中,目前默认包含了如下9种hook的版本
- start-commit
- pre-commit
- post-commit
- pre-revprop-change
- post-revprop-change
- pre-lock
- post-lock
- pre-unlock
- post-unlock
hook说明
这9种相关的hook所触发的时机相关的信息如下
类型 | 触发时机 | 常见用途 | 备注 |
---|---|---|---|
start-commit | 提交事务生成之前 | 一般可根据用户名对提交进行权限控制,一般多用于对svn版本功能check的检查 | 参数个数为2,svn 1.5为3个 |
pre-commit | 事务已生成,但是尚未提交 | 可可根据提交的内容或者comment进行控制,比如提交日志不能为空 | - |
post-commit | 提交之后 | 数据进行备份,以及修改提示的mail操作,或者驱动自动构建 | - |
pre-revprop-change | 属性变更前,尚未变化 | 可以进行属性变更权限的控制 | - |
post-revprop-change | 属性变更前 | 进行版本属性的备份以及mail通知操作等 | - |
pre-lock | 加锁之前 | 可进行是否能加锁的控制 | - |
post-lock | 加锁之后 | 可进行mail通知,使开发成员了解此文件已经加锁 | 往往有时结合特定流程,比如有提交冻结期的结束,可结合这个属性进行使用 |
pre-unlock | 解锁前 | 可进行是否能解锁的控制 | - |
post-unlock | 解锁之后 | 可进行mail通知,使开发成员了解此文件已经解锁 | 往往有时结合特定流程,比如有提交冻结期的结束,可结合这个属性进行使用 |
hook参数
当前版本的hook的相关参数信息如下所示:
类型 | 参数1 | 参数2 | 参数3 | 参数4 | 参数5 |
---|---|---|---|---|---|
start-commit | 代码库路径 | 用户名 | - | - | - |
pre-commit | 代码库路径 | 事务名 | - | - | - |
post-commit | 代码库路径 | 版本号 | 事务名 | - | - |
pre-revprop-change | 代码库路径 | 版本号 | 用户名 | 属性名 | ACTION |
post-revprop-change | 代码库路径 | 版本号 | 用户名 | 属性名 | ACTION |
pre-lock | 代码库路径 | 路径 | 用户名 | Comment | STEAL(1 |
post-lock | 代码库路径 | 用户名 | - | - | - |
pre-unlock | 代码库路径 | 路径 | 用户名 | TOKEN | BREAK-UNLOCK(1 |
post-unlock | 代码库路径 | 用户名 | - | - | - |
起效方式
缺省创建的库中的9个文件均以tmpl结尾,而这样是不起作用的,在Unix/Linux下,删除tmpl的后缀才能起作用,而windows则需要将.tmpl改成.bat。
修改之后立即起效,无需重新启动svn服务。
注意事项
因为安全的考量,在钩子函数中是无法使用环境变量的。Unix/Linux下基础的PATH也是环境变量,因为这个的缘故,导致可执行文件必须使用全路径进行引用,这就是你在代码里面没有看到svnlook而是/usr/bin/svnlook的根本原因。
实例
场景说明:
在版本管理中,我们建议在提交的日志中结合Ticket番号,如果在svn commit的时候提交日志的信息为空或者不包含Ticket号的信息,则无法提交到代码库。日志格式一般为:# xxxx: 日志信息
事前准备
事前准备
准备镜像
可以使用前面文章中Dockerfile生成的alpine的svn的lts版本的镜像,也可以直接使用使用easypack打好的镜像。
[root@liumiaocn svn]# docker pull liumiaocn/svn:1.10.0
1.10.0: Pulling from liumiaocn/svn
8e3ba11ec2a2: Already exists
4de3c6aa9a6d: Pull complete
f64b6f3c550b: Pull complete
Digest: sha256:c55a104e8f1cc10545b9e51aac4a40271540d0b13ab78c5c0e6ca40c0203f4f7
Status: Downloaded newer image for liumiaocn/svn:1.10.0
[root@liumiaocn svn]# docker images |grep liumiaocn/svn
liumiaocn/svn 1.10.0 15e2c7c993e6 Less than a second ago 12.4 MB
[root@liumiaocn svn]#
启动svn服务
[root@liumiaocn ~]# mkdir -p /usr/local/svn/hooktest
[root@liumiaocn ~]# cd /usr/local/svn/hooktest
[root@liumiaocn hooktest]# docker run -p 3690:3690 -v `pwd`/data:/data/svn --name svn -d liumiaocn/svn:1.10.0
cf3b9343e7245b5c0592b28f7386051cc5e403e962b97040078bd3e27e6f052b
[root@liumiaocn hooktest]#
确认服务
[root@liumiaocn hooktest]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf3b9343e724 liumiaocn/svn:1.10.0 "/usr/bin/svnserve..." 23 seconds ago Up 23 seconds 0.0.0.0:3690->3690/tcp svn
[root@liumiaocn hooktest]#
仓库准备
进入svn容器中,创建演示用仓库:hook-repo
[root@liumiaocn hooktest]# docker exec -it svn sh
/data/svn # svnadmin create hook-repo
/data/svn # ls
hook-repo
/data/svn #
设定
svn服务的配置设定文件
对仓库的svn服务的配置设定文件,都做如下设定
设定项 | 说明 | 缺省值 | 备考 |
---|---|---|---|
anon-access | 匿名用户访问权限 | read | 有read/write/none三种取值 |
auth-access | 认证用户访问权限 | write | 有read/write/none三种取值 |
password-db | 用户名与密码信息 | passwd | 多仓库可使用相对路径 |
authz-db | 用户与组权限设定 | authz | 多仓库可使用相对路径 |
/data/svn/hook-repo/conf # vi svn*
/data/svn/hook-repo/conf # egrep 'anon-access|auth-access|password-db|authz-db' svnserve.conf |grep -v '#'
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
/data/svn/hook-repo/conf #
用户信息:passwd
设定svn的用户信息passwd如下
[users]
devuser1 = devuser1pw
devuser2 = devuser2pw
testuser1 = testuser1pw
权限设定:authz
设定svn的权限信息authz如下
[groups]
group_dev = devuser1,devuser2
[hook-repo:/]
@group_dev = rw
testuser1 = r
重启svn镜像
[root@liumiaocn hooktest]# docker restart svn
svn
[root@liumiaocn hooktest]#
hook设定前确认
checkout出来hook-repo仓库
[root@platform ~]# svn co svn://192.168.163.129:3690/hook-repo --username devuser1 --password devuser1pw
-----------------------------------------------------------------------
ATTENTION! Your password for authentication realm:
<svn://192.168.163.129:3690> fd46fd0b-476c-4183-8596-4638ae6aff62
can only be stored to disk unencrypted! You are advised to configure
your system so that Subversion can store passwords encrypted, if
possible. See the documentation for details.
You can avoid future appearances of this warning by setting the value
of the 'store-plaintext-passwords' option to either 'yes' or 'no' in
'/root/.subversion/servers'.
-----------------------------------------------------------------------
Store password unencrypted (yes/no)? yes
Checked out revision 0.
[root@platform ~]# cd hook-repo/
[root@platform hook-repo]#
确认comment信息为空,是可以提交成功的。
[root@platform hook-repo]# touch C1; svn add C1;
A C1
[root@platform hook-repo]# svn commit -m ""
Adding C1
Transmitting file data .
Committed revision 1.
[root@platform hook-repo]# svn log
------------------------------------------------------------------------
[root@platform hook-repo]# svn update
Updating '.':
At revision 1.
[root@platform hook-repo]# svn log
------------------------------------------------------------------------
r1 | devuser1 | 2018-08-26 18:32:55 -0400 (Sun, 26 Aug 2018) | 1 line
------------------------------------------------------------------------
[root@platform hook-repo]#
comment的信息也没有过多其他的限制
[root@platform hook-repo]# ls
C1
[root@platform hook-repo]# touch C2; svn add C2; svn commit -m "add C2"
A C2
Adding C2
Transmitting file data .
Committed revision 2.
[root@platform hook-repo]# svn log
------------------------------------------------------------------------
r1 | devuser1 | 2018-08-26 18:32:55 -0400 (Sun, 26 Aug 2018) | 1 line
------------------------------------------------------------------------
[root@platform hook-repo]# svn update
Updating '.':
At revision 2.
[root@platform hook-repo]# svn log
------------------------------------------------------------------------
r2 | devuser1 | 2018-08-26 18:35:05 -0400 (Sun, 26 Aug 2018) | 1 line
add C2
------------------------------------------------------------------------
r1 | devuser1 | 2018-08-26 18:32:55 -0400 (Sun, 26 Aug 2018) | 1 line
------------------------------------------------------------------------
[root@platform hook-repo]#
hook设定
在服务器侧的hooks目录下创建pre-commit文件,也可以由现有的文件进行修改。具体内容如下:
[root@liumiaocn hooks]# docker exec -it svn sh
/data/svn # cd hook-repo/hooks
/data/svn/hook-repo/hooks # vi pre-commit
/data/svn/hook-repo/hooks # cat pre-commit
#!/bin/sh
REPOS="$1"
TXN="$2"
LOG_INFO=`svnlook log -t "$TXN" "$REPOS"`
# check empty comment
if [ _"$LOG_INFO" = _"" ]; then
echo "" 1>&2
echo " ## LOG CHECK : NG: [$LOG_INFO] does not match the rules." 1>&2
exit 1
fi
# check log format with # :
TICKET_NO=`echo "$LOG_INFO" |sed s/#//g |awk -F : '{print $1}'`
COMMENT_MSG=`echo "$LOG_INFO" |sed s/#//g |awk -F : '{print $2}'`
if [ _"$TICKET_NO" = _"" -o _"$COMMENT_MSG" = _"" ]; then
echo "" 1>&2
echo " ## LOG CHECK : NG: [$LOG_INFO] does not match the rules." 1>&2
echo " Sample : # BUG1002: feature F1001 bug fixed" 1>&2
exit 1
fi
# pre-commit check passed.
exit 0
/data/svn/hook-repo/hooks # chmod 755 pre-commit
/data/svn/hook-repo/hooks #
执行确认
空COMMENT提交
[root@platform hook-repo]# touch C3; svn add C3;
A C3
[root@platform hook-repo]#
提交确认: 可以看到pre-commit的空comment的判断逻辑起作用了
[root@platform hook-repo]# svn commit -m ""
Adding C3
Transmitting file data .svn: E165001: Commit failed (details follow):
svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output:
## LOG CHECK : NG: [] does not match the rules.
[root@platform hook-repo]#
格式不符合的情况
[root@platform hook-repo]# svn commit -m "add file"
Adding C3
Transmitting file data .svn: E165001: Commit failed (details follow):
svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output:
## LOG CHECK : NG: [add file] does not match the rules.
Sample : # BUG1002: feature F1001 bug fixed
[root@platform hook-repo]#
常见问题
hook文件缺少执行权限
hook文件会被调用,比如pre-commit文件,都需要具有x的执行权限,不然你很有可能在svn commit的时候得到如下的错误提示
Transmitting file data .svn: E165001: Commit failed (details follow):
svn: E165001: Commit blocked by pre-commit hook (exit code 255) with no output.
无法打印输出信息
echo输出的信息是标准输出,需要将其转化为标准错误,才能看到提示信息,这就是1>&2出现的原因(B-SHELL的输出转换方式)。