So you recently started running Subversion on Windows? You’re keen to unlock the power of hook scripts but don’t know where to start? Well dear reader, you can start right here…
Subversion hook script?
In a nutshell, it’s a program that performs an action which is triggered by a specified repository event. You can think of hook scripts as Subversion’s tool chest for setting up tighter control of a repository or integration with third-party applications, such as auto-closing tickets in a defect tracker when someone commits a change with “Fixes #123″ in the log, or triggering builds in a continuous integration system. The most common and powerful hook scripts are server side, although it’s also possible to run client side hook scripts.
Server side hook scripts usually have the permissions of the web server, which gives them power and flexibility, being able to affect other repositories on the server – of course the flip side to this power is the risk that a badly designed hook could slow the server to a crawl or in extreme cases, corrupt the repository.
What can hook scripts do?
- Report on events, such as emailing alerts when a commit occurs, sending a report on the commit to a third-party.
- Test for a pre-condition before allowing a commit to occur. For example, checking that a commit has been commented, or follows coding guidelines.
- Block certain actions. Maybe prevent a commit that contains multi-gigabyte files that could block other SVN traffic for hours, or prevent locks from being stolen.
What hook scripts can’t (shouldn’t) do
- Hook scripts shouldn’t modify files being committed. Right now, if a hook script actually changed a commit transaction, there’s no way of communicating the change back to the client. So while it might be tempting to write a script that automatically corrects errors or applies positive changes to a committed file, it will result in two different versions of the file in the same revision one version written to the repository and another in the user’s cache. The result of this loss of consistency can be as horrible as it is unpredictable.
Where are the hook scripts located?
When a new repository is created, a hooks subdirectory is included, e.g. if you create a repository called chancode, hooks will live in the /repositories/chancode/hooks/ directory. By default a non executable template (.tmpl) for each type of hook script is automatically created with the directory.
- Start-commit Invoked before a transaction is created, pre-pre-commit, if you will. Commonly used to check if a user has sufficient privileges to perform a commit.
- pre-commit / post-commit Invoked before or after a commit is completed.
- pre-revprop-change / post-revprop-change Invoked before or after a revision propertly is added, modified or deleted.
- pre-lock / post-lock Invoked when a user attempts to lock a path or after a lock has been created.
- pre-unlock / post-unlock Invoked when a user attempts to destroy an exclusive lock, or immediately after the lock’s destruction.
There’s a good source of pre-written scripts available online, although the vast majority have been written for Unix/Linux, so aren’t immediately usable on Windows. Hooks can be written in anything, although cross-platform languages like Perl, Python and Ruby are quite popular. For simple scripts, it’s possible to use Windows’ plain old batch scripting.
Testing the water
We’ll do a simple test to show a hook script in action. We’ll introduce a pre-commit hook that checks for a log message that is n characters long – in this case, at least 6 characters.
- On your Windows Subversion/uberSVN server navigate your way to the hooks directory in your repository.
i.e. C:\Program Files (x86)\WANdisco\uberSVN\repositories\chancode\hooks
- Open the pre-commit.tmpl file – you’ll recall that this is the script that gets triggered before a commit is completed.
- The template file contains lots of useful information, as well as an example script that does exactly what we’re going to do, unfortunately it’s aimed at the Unix/Linux /bin/sh interpreter, so we can’t use it for Windows without a rewrite.
- Delete all the contents of the file and copy in the following Windows batch scripting:
@echo off :: Stops commits that don't include a log message of at least 6 characters. @echo off setlocal rem Subversion sends through the repository path and transaction id set REPOS=%1 set TXN=%2 svnlook log %REPOS% -t %TXN% | findstr ...... > nul if %errorlevel% gtr 0 (goto err) else exit 0 :err echo --------------------------------------------------------------------------- 1>&2 echo Your commit has been blocked because it didn't include a log message. 1>&2 echo Do the commit again, this time with a log message that describes your changes. 1>&2 echo --------------------------------------------------------------------------- 1>&2 exit 1
The script uses Svnlook, the incredibly useful command line tool to examine the commit transaction’s log message, then calls upon the findstr command to look for a string of at least 6 characters – the length of the minimum message length is set by the number of “.” characters after the findstr command.
- Save the file so that it can be executable. Windows supports .exe or .bat files.
- Testing time. Make an arbitrary change in a file, commit the change with a log message that is either blank or contains fewer than 6 characters. You’ll get the following error message:
- Repeat the commit with the necessary number of characters, the commit will then succeed.
- Of course, this is a super-simple example. Lazy developers soon learn to leave comments along the lines of ‘update update update’ or ‘blah blah blah.’ You can use more complex scripts for better checking.
Debugging and troubleshooting hook problems is notoriously difficult as there’s no formal error logging. These points are worth keeping in mind when setting up hook scripts.
- If you’re completely stuck when trying to convert a hook script for use with Windows, remember there’s always Cygwin, a set of tools for running Linux tools on Windows, which will let you run many Linux scripts on Windows without the need to rewrite them.
- Empty environment problem – Subversion executes hook programs with no environment variables. That’s a good security precaution but often leaves administrators pulling their hair out with frustration when a manually tested hook script absolutely refuses to work with Subversion. So ensure that any necessary environment variables are set in your hook script and/or use absolute paths.