Part of my current role is to establish the policies and procedures around testing and quality in general. One of things I like to do is tie version control commits with items in the bug system (I track features in there as well).

We’re using Subversion as the versioning system and FogBugz as the bug system. Now, the way to do the coupling is to download a script from your instance and save it to hooks/post-commit (unix). This is pretty easy, but in our case limits all the rules in post-commit to be perl. This might not be a problem except that we are a ruby shop, the person currently admin-ing the svn instance does things in shell and my brain’s first language is python. It also means that all the rules are in one file. I don’t really like either of those limitations.

A disclaimer before going any further. This is still theoretical as it hasn’t been deployed yet but it should work. Should being the magic word.

To work around these limitations, here is the post-commit script I’m going to use

#!/bin/sh

REPOSITORY="$1"
REVISION="$2"
SVNLOOK=/usr/bin/svnlook

# All checks passed, so allow the commit.
for f in `find $REPOSITORY/hooks/scripts -name "post-*"`
do
    if [ -x "$f" ]
    then
        # scripts need to notify people who care themselves
        $f $REPOSITORY $REVISION $SVNLOOK
    fi
done

What is does is loop through all the files in a scripts sub-directory and execute any of them that start with ‘post-‘. By adopting this simple naming convention anyone can add their own post-commit scripts in whatever language they are most comfortable with. The only requirement is that they exit with either a 0 or 1 which is how svn decides whether something is okay or not.

What the FogBugz post-commit script does is modify the bug record saying ‘change x’ so you can see what code changed as a result of this bug.

post-commits are only half the story though. pre-commit checks are just as important and are implemented in pretty much the same way only using ‘pre-‘ instead of ‘post-‘. I currently have 2 pre-commit scripts.

  1.  #!/bin/sh
        
     REPOS=$1
     TXN=$2
     SVNLOOK=/absolute/path/to/svnlook
        
     if $SVNLOOK log -t "$TXN" "$REPOS" | egrep -i "^BugzID: [0-9]*$" > /dev/null
     then
         exit 0
     else
         echo "You must associate a check-in with a FogBugzID."
         exit 1
     fi
    
  2.  #!/bin/sh
        
     REPOS=$1
     TXN=$2
     SVNLOOK=/absolute/path/to/svnlook
        
     if $SVNLOOK log -t "$TXN" "$REPOS" | egrep -i "^buddy: [\w]*$" > /dev/null
     then
         exit 0
     else
         echo "You must have a buddy check your commit."
         exit 1
     fi
    

What these two scripts do is check the commit message for a line that says ‘bugzid: id’ (which is necessary for the FogBugz integration) and one that says ‘buddy: name’ (for the buddy system I am trying to implement — more on that in a later post).

One other thing about this system is that if you want to turn off a rule for whatever reason, you just remove the execute bit from it and it is not going to fire rather than having to move or rename the file.

Update: Modified the post-commit script to not care about the return code of the scripts it calls since svn itself ignores (the commit has already happened). If the author of the script that is failing cares to be informed they will have to put the proper notification stuff in themselves.