有没有人有明确的说明,如何添加一个 pre-commit 钩子来避免更改标签子目录?
我已经在互联网上搜索了很多。我找到了这个链接:SVN::Hooks::DenyChanges ,但我似乎无法编译它。
有没有人有明确的说明,如何添加一个 pre-commit 钩子来避免更改标签子目录?
我已经在互联网上搜索了很多。我找到了这个链接: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
#!/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
命令授予执行权限。
@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
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
目录下,并且如果它不存在,你有创建 /tags
和所有后续文件夹的权限。任何其他更改都会被阻止。几乎没有之前的脚本涵盖了 Subversion 书中描述 svnlook changed ...
的所有情况。
#!/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
# E.g. 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
由于第一个答案没有防止添加/删除文件,并且防止新标签的创建,以及许多其他不完整或有缺陷的地方,因此我进行了重新制作。
这是我的预提交钩子:
--------- 文件“pre-commit”(放在存储库的hooks文件夹中) ---------
#!/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" 结束 ---------
此外,我编写了两个 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“根目录”(在我的情况下为/var/svn/repos/svn)执行这些脚本。 顺便说一句,可以设置一个cron任务,每天自动执行这些脚本来修改新的repos。
希望能有所帮助。
我的版本只允许创建和删除标签。这应该处理所有特殊情况(如添加文件、更改属性等)。
#!/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
grep "^U\W.*tags\/"
,因为我的svnlook输出在存储库路径上没有前导斜杠。 - Marcus