Once you've been using Subversion when you and and your colleagues are working on a project, you're bound to find useful ways to exploit Subversion's hook system. We use the sample commit-email.pl script to send all commits to an email list for ad-hoc peer-review. I found and enabled Ian Christian's pre-commit script to check PHP syntax when checking in code.
The latest piece of the puzzle was to restrict commits to a project's branch to a few users, which has been harder to figure out than I expected. The most common script for access control is svnperms, which has a rich syntax for configuring access. Unfortunately, svnperms seems to work best with a repository with the following repository layout:
Our repository is laid out as:
I was trying to restrict access to Project1's stable branch (project1/branches/stable), and this didn't seem to be possible under svnperms, no matter how many regular expressions I tried. Subversion provides another access control script, commit-access-control.pl script, but having been burned by svnperms, I was reluctant to spend too much time trying to configure it and get it to work.
Since hooks are just shell scripts, its easy to write your own, which is what I did in this case. The place to check commit access is before the transaciton is created, in the start-commit hook. Being more comfortable in PHP, I whipped up the following command line script and saved it as check_commit_privs.php
#!/usr/bin/php
<?php
/*
CHECKS IF A USER CAN COMMIT TO THE REPOSITORY
Oscar Merida <omerida@forumone.com>
*/
// SVN passes two arguments, the repository path and user for the commit
$repo_path = $_SERVER['argv'][1];
$commit_user = $_SERVER['argv'][2];
// You can use array to define user groups
$qa_group = array('bob', 'roger', 'amanda'');
$contractors = array('marco', 'dawn', 'bill');
// CONFIGURATION
//
// array key is a path in SVN repository or a regular expression that will match a path.
// value is an array of usernames that can commit to that path
// first path match that limits access will prevent commits.
// This script assumes you only need to lock down certain
// parts of your repository.
$allowed = array(
// only contractors can commit to widgets project
'/widgets/' => $contractors,
// only qa_group can commit to any project's testing branch
'/.*\/branch\/testing/' => $qa_group,
// only bill can commit to his project
'/bills_project/' => array('bill')
);
foreach ($allowed as $regexp => $group)
{
if (preg_match($regexp, $repo_path)
&& !in_array($commit_user, $group))
{
exit(1);
}
}
To enable this script, create or add a file named 'start-commit' to your repository's hooks/ folder with the following. If there is a file named start-commit.tmpl, copy that as a starting point. You'll also have to make sure that both start-commit and check_commit_privs.php are executable by your SVN users.
REPOS="$1"
USER="$2"
# basic permissions check
/path/to/check_commit_privs.php "$REPOS" "$USER" || exit 1