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.
Most of the previously written scripts are incomplete because several cases are not covered. This is my script:
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
It might seem complicated but you have to make sure that you are in /tags
and you are allowed create /tags
if it does not exist and all subsequent folders. Any other change is blocked. Almost none of the previous scripts cover all cases described in the Subversion book for svnlook changed ...
.
If you are using JIRA, you can use the add-on named Commit Policy to protect paths in your repository without writing custom hooks.
How? Use the condition named Changed files must match a pattern.
It has an regular expression type argument that must match for every file in a commit, otherwise the commit is rejected. So, in your case you should use a regex that means "does not start with the prefix /tags/".
(You can implement many other smart checks with the same plugin.)
Disclaimer: I'm a developer working on this paid add-on.
This anwser is a lot after date, but I discovered the --copy-info parameter for the svnlook changed command.
The output of this command adds a '+' in the third column, so you know it is a copy. You can check for commits to the tags directory, and only allow commits with a '+' present.
I've added some output in my blog post.
My version only allows creating and deleting tags. This should handle all the special cases (like adding files, changing properties, etc.).
#!/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
Here is my windows batch file pre-commit hook. If the user is an administrator the other checks will be skipped. It checks if the commit message is empty, and if the commit is to a tag. Note: findstr is a nerfed alternative to grep on other platforms.
The way it checks if the commit is to a tag, it first checks if svnlook changed contains "tags/". It then checks if svnlook changed matches "^A.tags/[^/]/$", which means that it will check if you are adding a new folder under tags/.
Users are allowed to create new projects. The pre-commit hook allows a user to create the folders trunk/ tags/ and branches/. Users are not allowed to delete the folders trunk/ tags/ and branches/. This will work for a single or multi-project repository.
@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