SVN提交钩子,以避免更改标签子目录
有没有人有清楚的指示如何添加一个预先提交的钩子,避免更改标签子目录?
我已经在网上search了很多。 我发现这个链接: SVN :: Hooks :: DenyChanges ,但我似乎无法编译的东西。
我没有足够的声望来评论上面的Raim的答案,但他的工作很好,除了一个例外,他的grep模式是错误的。
我简单地使用下面的作为我的预先提交钩子(我没有一个现有的,你需要在这种情况下合并):
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK=/opt/local/bin/svnlook # Committing to tags is not allowed $SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W.*\/tags\/" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1 # All checks passed, so allow the commit. exit 0
Raim的grep模式唯一的问题是,如果它是在你的回购“根”,它只匹配“标签”。 由于我在回购中有几个项目,他写的脚本允许在标签分支上进行提交。
此外,一定要chmod + x所示,否则你会认为它的工作B / C提交失败,但它失败了B / C它不能执行预先提交的钩子,不是因为钩子工作。
这真是太好了,谢谢Raim。 比所有其他build议更好,更轻,因为它没有依赖性!
下面是一个简短的shell脚本,用于防止在创build标签后提交:
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK=/usr/bin/svnlook # Committing to tags is not allowed $SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W*tags" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1 # All checks passed, so allow the commit. exit 0
把它保存在你的Subversion版本库的hooks/pre-commit
,并使用chmod +x
来执行它。
这是我的Windowsbatch file预先提交钩子。 如果用户是pipe理员,则其他检查将被跳过。 它检查提交消息是否为空,以及提交是否为标记。 注意:findstr是grep在其他平台上的替代scheme。
它检查提交的方式是标记,它首先检查svnlook是否包含“tags /”。 然后检查svnlook是否改变了匹配“^ A。tags / [^ /] / $”,这意味着它将检查你是否在tags /下添加了一个新的文件夹。
用户可以创build新的项目。 预提交钩子允许用户创build文件夹trunk / tags /和branches /。 用户不允许删除文件夹trunk / tags /和branches /。 这将适用于单个或多个项目存储库。
@echo off rem This pre-commit hook will block commits with no log messages and blocks commits on tags. rem Users may create tags, but not modify them. rem If the user is an Administrator the commit will succeed. rem Specify the username of the repository administrator rem commits by this user are not checked for comments or tags rem Recommended to change the Administrator only when an admin commit is neccessary rem then reset the Administrator after the admin commit is complete rem this way the admin user is only an administrator when neccessary set Administrator=Administrator setlocal rem Subversion sends through the path to the repository and transaction id. set REPOS=%1% set TXN=%2% :Main rem check if the user is an Administrator svnlook author %REPOS% -t %TXN% | findstr /r "^%Administrator%$" >nul if %errorlevel%==0 (exit 0) rem Check if the commit has an empty log message svnlook log %REPOS% -t %TXN% | findstr . > nul if %errorlevel% gtr 0 (goto CommentError) rem Block deletion of branches and trunk svnlook changed %REPOS% -t %TXN% | findstr /r "^D.*trunk/$ ^D.*branches/$" >nul if %errorlevel%==0 (goto DeleteBranchTrunkError) rem Check if the commit is to a tag svnlook changed %REPOS% -t %TXN% | findstr /r "^.*tags/" >nul if %errorlevel%==0 (goto TagCommit) exit 0 :DeleteBranchTrunkError echo. 1>&2 echo Trunk/Branch Delete Error: 1>&2 echo Only an Administrator may delete the branches or the trunk. 1>&2 echo Commit details: 1>&2 svnlook changed %REPOS% -t %TXN% 1>&2 exit 1 :TagCommit rem Check if the commit is creating a subdirectory under tags/ (tags/v1.0.0.1) svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/[^/]*/$" >nul if %errorlevel% gtr 0 (goto CheckCreatingTags) exit 0 :CheckCreatingTags rem Check if the commit is creating a tags/ directory svnlook changed %REPOS% -t %TXN% | findstr /r "^A.*tags/$" >nul if %errorlevel% == 0 (exit 0) goto TagsCommitError :CommentError echo. 1>&2 echo Comment Error: 1>&2 echo Your commit has been blocked because you didn't enter a comment. 1>&2 echo Write a log message describing your changes and try again. 1>&2 exit 1 :TagsCommitError echo. 1>&2 echo %cd% 1>&2 echo Tags Commit Error: 1>&2 echo Your commit to a tag has been blocked. 1>&2 echo You are only allowed to create tags. 1>&2 echo Tags may only be modified by an Administrator. 1>&2 echo Commit details: 1>&2 svnlook changed %REPOS% -t %TXN% 1>&2 exit 1
这个anwser在date之后很多,但是我发现了svnlook changed命令的–copy-info参数。
这个命令的输出在第三列中加了一个“+”,所以你知道它是一个副本。 你可以检查提交到标签目录,只允许提交'+'提交。
我在我的博客文章中添加了一些输出。
很晚,但是我写了一个基于http://subversion.tigris.org/上的log-police.py脚本的python pre-commit hook。
这个脚本应该做你想做的事情,但是它也检查日志消息是否存在,尽pipe这应该很容易从脚本中删除。
一些注意事项:
- 我是Python的新手,所以很可能会写得更好
- 它只在Windows 2003和Python 2.5和Subversion 1.4上testing过。
要求:
- 颠覆
- python
- Python的Subversion绑定
最后,代码:
#!/usr/bin/env python # # pre-commit.py: # # Performs the following: # - Makes sure the author has entered in a log message. # - Make sure author is only creating a tag, or if deleting a tag, author is a specific user # # Script based on http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/log-police.py # # usage: pre-commit.py -t TXN_NAME REPOS # Eg in pre-commit.bat (under Windows) # python.exe {common_hooks_dir}\pre_commit.py -t %2 %1 # import os import sys import getopt try: my_getopt = getopt.gnu_getopt except AttributeError: my_getopt = getopt.getopt import re import svn import svn.fs import svn.repos import svn.core # # Check Tags functionality # def check_for_tags(txn): txn_root = svn.fs.svn_fs_txn_root(txn) changed_paths = svn.fs.paths_changed(txn_root) for path, change in changed_paths.iteritems(): if is_path_within_a_tag(path): # else go to next path if is_path_a_tag(path): if (change.change_kind == svn.fs.path_change_delete): if not is_txn_author_allowed_to_delete(txn): sys.stderr.write("\nOnly an administrator can delete a tag.\n\nContact your Subversion Administrator for details.") return False elif (change.change_kind != svn.fs.path_change_add): sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.") return False # else user is adding a tag, so accept this change else: sys.stderr.write("\nUnable to modify " + path + ".\n\nIt is within a tag and tags are read-only.\n\nContact your Subversion Administrator for details.") return False return True def is_path_within_a_tag(path): return re.search('(?i)\/tags\/', path) def is_path_a_tag(path): return re.search('(?i)\/tags\/[^\/]+\/?$', path) def is_txn_author_allowed_to_delete(txn): author = get_txn_property(txn, 'svn:author') return (author == 'bob.smith') # # Check log message functionality # def check_log_message(txn): log_message = get_txn_property(txn, "svn:log") if log_message is None or log_message.strip() == "": sys.stderr.write("\nCannot enter in empty commit message.\n") return False else: return True def get_txn_property(txn, prop_name): return svn.fs.svn_fs_txn_prop(txn, prop_name) def usage_and_exit(error_msg=None): import os.path stream = error_msg and sys.stderr or sys.stdout if error_msg: stream.write("ERROR: %s\n\n" % error_msg) stream.write("USAGE: %s -t TXN_NAME REPOS\n" % (os.path.basename(sys.argv[0]))) sys.exit(error_msg and 1 or 0) def main(ignored_pool, argv): repos_path = None txn_name = None try: opts, args = my_getopt(argv[1:], 't:h?', ["help"]) except: usage_and_exit("problem processing arguments / options.") for opt, value in opts: if opt == '--help' or opt == '-h' or opt == '-?': usage_and_exit() elif opt == '-t': txn_name = value else: usage_and_exit("unknown option '%s'." % opt) if txn_name is None: usage_and_exit("must provide -t argument") if len(args) != 1: usage_and_exit("only one argument allowed (the repository).") repos_path = svn.core.svn_path_canonicalize(args[0]) fs = svn.repos.svn_repos_fs(svn.repos.svn_repos_open(repos_path)) txn = svn.fs.svn_fs_open_txn(fs, txn_name) if check_log_message(txn) and check_for_tags(txn): sys.exit(0) else: sys.exit(1) if __name__ == '__main__': sys.exit(svn.core.run_app(main, sys.argv))
接受的答案可以防止更新标签中的文件,但不会阻止添加文件到标签。 以下版本处理两者:
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK="/home/staging/thirdparty/subversion-1.6.17/bin/svnlook" # Committing to tags is not allowed $SVNLOOK changed -t "$TXN" "$REPOS" --copy-info| grep -v "^ " | grep -P '^[AU] \w+/tags/' && /bin/echo "Cannot update tags!" 1>&2 && exit 1 # All checks passed, so allow the commit. exit 0
以前编写的大部分脚本都是不完整的,因为有几个案例没有涉及。 这是我的脚本:
contains_tags_dir=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "+\/tags\/.*$" | wc -l | sed "s/ //g"` if [ $contains_tags_dir -gt 0 ] then tags_dir_creation=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "^A .+\/tags\/$" | wc -l | sed "s/ //g"` if [ $tags_dir_creation -ne 1 ] then initial_add=`$SVNLOOK changed --copy-info -t "$TXN" "$REPOS" | head -1 | egrep "^A \+ .+\/tags\/.+\/$" | wc -l | sed "s/ //g"` if [ $initial_add -ne 1 ] then echo "Tags cannot be changed!" 1>&2 exit 1 fi fi fi
它可能看起来很复杂,但你必须确保你在/tags
,如果它不存在,并且所有后续文件夹都允许创build/tags
。 任何其他更改都被阻止。 以前的脚本几乎没有涵盖Subversion书中为svnlook changed ...
所描述的所有情况。
如果您正在使用JIRA,则可以使用名为“ 提交策略”的插件来保护存储库中的path, 而无需编写自定义挂接 。
怎么样? 使用名为“ 更改文件”的条件必须匹配模式 。
它有一个正则expression式types参数,必须匹配提交中的每个文件,否则提交将被拒绝。 所以,在你的情况下,你应该使用一个正则expression式,意思是“不以prefix / tags /开头”。
(您可以使用相同的插件实施许多其他智能检查。)
免责声明:我是一个开发人员在这个付费附加。
我的版本只允许创build和删除标签。 这应该处理所有的特殊情况(如添加文件,更改属性等)。
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK=/usr/local/bin/svnlook output_error_and_exit() { echo "$1" >&2 exit 1 } changed_tags=$( $SVNLOOK changed -t "$TXN" "$REPOS" | grep "[ /]tags/." ) if [ "$changed_tags" ] then echo "$changed_tags" | egrep -v "^[AD] +(.*/)?tags/[^/]+/$" && output_error_and_exit "Modification of tags is not allowed." fi exit 0
列出的答案是伟大的,但没有做到我所需要的。 我想允许创build标签,但一旦创build它们应该是完全只读的。
我也想防止愚蠢的情况,如果你这样做:
svn copy myrepo/trunk myrepo/tags/newrelease
一切都是第一次。 但第二次,如果标签已经存在,您将以myrepo/tags/newrelease/trunk
。
我的预提交钩子将查找任何预先存在的SVN目录(repo)/tags/(tag)/
,如果find则会失败:
$SVNLOOK tree -N --full-paths "$REPOS" "`$SVNLOOK changed -t "$TXN" "$REPOS" \ | sed 's/[AZ][[:space:]]*\([^/]*\)\/tags\/\([^/]*\)\/.*/\1\/tags\/\2\//' \ | head -n 1`" \ && echo "Tag already exists, commit rejected." >&2 \ && exit 1
由于第一个答案没有阻止添加/ suppr文件,并阻止新的标签创build,以及其他许多不完整或错误的,我重做了它
这是我的预先提交钩子:目标是:
- 禁止提交标签(文件添加/抑制/更新)
- 不要阻止创build标签
———文件“预先提交”(放入存储库钩子文件夹)———
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK=/usr/bin/svnlook #Logs #$SVNLOOK changed -t "$TXN" "$REPOS" > /tmp/changes #echo "$TXN" > /tmp/txn #echo "$REPOS" > /tmp/repos # Committing to tags is not allowed # Forbidden changes are Update/Add/Delete. /W = non alphanum char Redirect is necessary to get the error message, since regular output is lost. # BUT, we must allow tag creation / suppression $SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^A\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 101 $SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^U\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 102 $SVNLOOK changed -t "$TXN" "$REPOS" | /bin/grep "^D\W.*tags\/[0-9._-]*\/." && /bin/echo "Commit to tags are NOT allowed ! (Admin custom rule)" 1>&2 && exit 104 # All checks passed, so allow the commit. exit 0;
———文件结尾“pre-commit”———
此外,我做了2个shell脚本来复制我的svn的每个项目中的钩子:一个设置只读回购:
———脚本“setOneRepoTagsReadOnly.sh”———
#!/bin/sh cd /var/svn/repos/svn zeFileName=$1/hooks/pre-commit /bin/cp ./CUSTOM_HOOKS/pre-commit $zeFileName chown www-data:www-data $zeFileName chmod +x $zeFileName
———文件结束“setOneRepoTagsReadOnly.sh”———
还有一个人为了回购所有的回报,把我所有的回购券都只读了:
———文件“makeTagsReadOnly.sh”———
#!/bin/shs/svn #Lists all repos, and adds the pre-commit hook to protect tags on each of them find /var/svn/repos/svn/ -maxdepth 1 -mindepth 1 -type d -execdir '/var/svn/repos/svn/setOneRepoTagsReadOnly.sh' \{\} \;
———文件结束“makeTagsReadOnly.sh”———
我直接从svn“root”(/ var / svn / repos / svn,在我的情况下)执行脚本。 顺便说一句,一个cron任务可以设置为每天执行脚本来自动修改新的回购
希望它有帮助。