Leveraging Subversion Hooks for Fun and Profit

Last week, I showed you how to setup a secure subversion server. Today, I’d like to show you how to technically accomplish a couple of development themes that are near and dear to my heart. The first is creating a quality gate with a release branch and creating a team of committers who are the only developers allowed to write there. The second is increasing communications between offshore development and inshore business which we’ll tackle with enforcing svn commit messages and svn diff email notifications. To accomplish this, I’ll introduce you to the basic subversion commit hooks: pre-commit and post-commit.

Fine Grained Subversion Permissions Using pre-commit

We want to ensure that not everyone has free roam across the entire repository. For instance, say we only want committers to have write access to the trunk and developers should be able to create branches whenever they want. Let’s use subversion’s pre-commit template to enforce some basic read-write permissions.


sudo su - svn
cd /var/svn/repos/hooks
cp pre-commit.tmpl pre-commit
chmod g+x pre-commit

You’ll have to modify the pre-commit template a bit by adding the fully qualified path to the access control configuration file. I also enhanced the comment checking a bit by adding an appropriate error message for the client to display.

vi pre-commit:
...
# Make sure that the log message contains some text.
SVNLOOK=/usr/bin/svnlook
LOGMSG=`$SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" | wc -c`
if [ "$LOGMSG" -lt 3 ];then
# Check that a comment has been made
echo -e "nPlease enter a COMMENT (or at least a ticket #)." 1>&2
exit 1
elsif
# Check that the author of this commit has the rights to perform
# the commit on the files and directories being modified.
/usr/share/subversion/hook-scripts/commit-access-control.pl
"$REPOS" "$TXN" /var/svn/repos/commit-access-control.cfg || exit 1
fi

# All checks passed, so allow the commit.
exit 0

Here’s how to enforce permissions for various sections of the repository. Say, for instance, you only want senior developers committing to your release branch (the trunk in this case), and juniors access only to branches.

vi ../commit-access-control.cfg :
[read only default]
match = .*
access = read-only

[developers have access to branch]
match = ^branches
users = dan mark susie
access = read-write

[committers have access to trunk]
match = ^trunk
users = mark
access = read-write

In testing out the permissions hook, I ran into the following problem: Can’t locate Config/IniFiles.pm in @INC. Googling gave me the following solution:

It’s likely that you don’t have required Perl modules installed. In this case it’s Config::IniFiles that is missing. The easiest way to install Perl modules is to use CPAN extension, eg. perl -MCPAN -e ‘install Config::IniFiles’.

Importing an Existing Repository

As our source code repository has been running for the past year offshore, I asked them to note the current revision ID (r3015) and dump the repo database using svnadmin.

svnadmin dump /usr/etc/svn/share/repos/ > repo_r3015.dump
bzip2 repo_r3015.dump

I’d already prepared the holding repository at /var/svn/repos.

sudo chmod g+w /var/svn/repos/
ls -lrt /var/svn
drwxrwxr-x 6 svn svn 4096 2008-12-08 12:50 repos

bunzip2 repo_r3015.dump.bz2
svnadmin load /var/svn/repos/ < ~/repo_r3015.dump

Ensure proper permissions for writing by setting the sticky bit for the subversion group:

sudo chmod -R 2770 /var/svn/repos/db/
ls -lrt /var/svn/repos/
-rwxr-xr-x 1 svn svn 229 2008-12-09 16:18 README.txt
drwxr-xr-x 2 svn svn 4096 2008-12-09 16:18 locks
-rwxr-xr-x 1 svn svn 2 2008-12-09 16:18 format
drwxr-xr-x 2 svn svn 4096 2008-12-09 16:18 conf
drwxrwsr-x 6 svn svn 4096 2008-12-09 16:33 db

Email Notifications


cd /var/svn/repos/hooks$
sudo cp post-commit.tmpl post-commit
sudo chown svn:svn post-commit
sudo chmod g+x post-commit
sudo vi post-commit:
...
/usr/share/subversion/hook-scripts/commit-email.pl
"$REPOS" "$REV" --from svn@admin-kis.hosteurope.de -s "svn commit:"
dan@no-spam.de admin@just-ham.com

The mail server install/setup isn’t part of this HOWTO, but you can use the following articles as reference for exim4 and postfix under Debian.

Run your first local test which should send out an email containing an svn diff:

sudo ./post-commit /var/svn/repos 1

To get nicely formatted, easier to read html mails, grab the svnnotify package and update your post-commit script to the following:

sudo apt-get install libsvn-notify-perl
sudo vi post-commit:
...
AUTHOR=`/usr/bin/svnlook author -r "$REV" "$REPOS"`
REPLY_TO=`cat "/var/svn/repos/$AUTHOR"`

/usr/bin/svnnotify -r $REV -C -d -H HTML::ColorDiff -p $REPOS
-t dan@no-spam.de,admin@just-ham.com
-f svn@admin-kis.hosteurope.de -R $REPLY_TO

And that’s all there is to it! You should now be able to administer your own subversion repository including fine grained permissions and easily understandable email notifications per commit. Let me know if you have any troubles with the install and configuration, and please, if you have some better ideas/solutions/suggestions share them with us!

5 thoughts on “Leveraging Subversion Hooks for Fun and Profit

  1. Dan, nice article. One thing I was wondering about was the email notifications – I find I need these less and less as CI comes of age. Assuming that your outsourcing means that you want some very detailed records of svn activity? 🙂

    Like

  2. Exactly. I’m also trying to learn more about the codebase as well (therefore, I’m enforcing commits with a valid ticket id if applicable too). The CI will be phase two for us, and once we get some test driven development going, I will probably be able to turn off those emails.

    Like

  3. We have a requirement to use subversion 1.5+ clients, because of a merge tracking feature. To ensure that only 1.5+ clients are in use I have created a start-commit hook that checks for the capabilities parameter – capabilities are also a new feature that came with 1.5, and a “mergeinfo” capability is always there for these clients, so I allow only commits from clients that have this.

    The start-commit hook looks like this:


    #!/bin/sh
    REPOS="$1"
    USER="$2"
    CAPABILITIES="$3"

    # allow only subversion 1.5 and higher to commit - this way we make sure that the whole team installs version 1.5 of subversion that supports merge tracking
    if echo $CAPABILITIES | grep 'mergeinfo' > /dev/null; then
    exit 0
    else
    echo "" 1>&2
    echo "Commit failed ! Please use at least subversion 1.5." 1>&2
    exit 1
    fi

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.