An Introduction to Subversion Hook Scripts on Windows

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.

Hooks

Hook types

  • 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.

  1. 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
  2. Open the pre-commit.tmpl file – you’ll recall that this is the script that gets triggered before a commit is completed.
  3. 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.
  4. 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.

  5. Save the file so that it can be executable. Windows supports .exe or .bat files.
  6. 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:

    Tortoise 01

  7. Repeat the commit with the necessary number of characters, the commit will then succeed.
  8. 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.

Parting Tips

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.

8 Responses to “An Introduction to Subversion Hook Scripts on Windows”


  • Hi, nice example. I have just tried to use a hook, on a windows machine… but nothing happens. Are there something you have to do before this functionality starts working?

    Kind regards
    Claes

  • Hi Claes,

    Thanks for your comment! Unfortunately, hook scripts problems are difficult to diagnose – is Subversion throwing any error messages?

    There are a few common problems that would be worth looking at first. On Windows, hook scripts must be saved as either a batch file (.bat) or an executable (.exe). If your pre-commit file is saved in any other format, then this will be causing the hook script to fail.

    Another problem might be the admin permissions. The server program performing the commit is the same program that will be running the hook script – so the working copy must be owned by the same user that svnserve or Apache runs as, or the working copy must at least have appropriate permissions set. You can check which permissions are set, by looking at the repository configuration files.

    It might also be worth re-checking the ‘Parting Tips’ section of the blog post, which has some useful pointers for solving hook script problems.

    Hope this helps!

  • Works great with Tortoise SVN.

    However, my Netbeans 7.1.2 will not commit with the pre-commit file named as .bat.

    I get the following output in Netbeans:

    ==[IDE]== 11-May-2012 12:55:09 Preparing Commit…
    ==[IDE]== 11-May-2012 12:55:09 Preparing Commit… finished.
    ==[IDE]== 11-May-2012 12:55:11 Committing…
    commit –force-log -F C:\Users\PANDER~1\AppData\Local\Temp\svn_6408020217266247030 –targets C:\Users\PANDER~1\AppData\Local\Temp\svn_3755696915136096726 –config-dir C:\Users\panderson\.netbeans\7.1.2\config\svn\config –non-interactive –username Paul.Anderson –password ******
    Sending D:\SubVersion\src\Alarm\AlarmApplication.java

    Any thoughts?

    Thanks

  • Disregard my last comment. It did not work in Netbeans as I had changed the error echo statements which included:

    echo If blah blah blah 1>&2

    If the If is included in the echo, then the commit to netbeans will fail.

  • Sorry, there must be a maximum length string that can be retured. The If is ok. I am having one of those days.

  • Hi,

    I want to make a pre-hook commit for SVN vs Redmin, I have examples in ruby under linux how do I convert it to windows environment.

    Thanks

  • Hi,

    Thanks for the script, it worked perfectly for me!!

    Thanks!

  • avatar Nithya Sudarsana Kumar

    hi..

    thanks for this script :-)

    it works perfectly on windows svn repository. Let me know how to execute this same pre-commit hook in linux (python script).

    thanks in advance.

Leave a Reply