Is there anybody who has clear instructions on how to add a pre-commit hook that avoids changes to tags subdirectories?
I already searched the internet quite a bit.
Pretty late to the party, however I wrote a python pre-commit hook for work which is based off the log-police.py script on http://subversion.tigris.org/.
This script should do what you want, however it also checks that a log message exists, though that should be easy to remove from the script.
Some caveats:
Requirements:
Finally, the code:
#!/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))