Introducing CaptainHook - A Subversion Hook Framework For .NET
UPDATE: CaptainHook is now an Open Source project on SourceForge.
One potent tool for team communications on a project, especially one with distributed developers, is the simple commit email. Setting up Subversion to send out an email when a developer commits changes to the repository is fairly easy. The Subversion distribution comes with a PERL script (commit-email.pl) that works quite well for this purpose.
At least it did for me until we changed mail servers to one that did not allow SMTP relay. Try as I might, I could not get the script to authenticate with our SMTP credentials. I downloaded various other PERL modules that were supposed to be able to authenticate with no luck. I read the RFC 2554 (seat of your pants reading) and authenticated manually via telnet and compared that to the SMTP logs for the components and realized that for some reasons, these scripts were doing the wrong thing.
That’s when it occurred to me that I could probably write a simple .NET app in a minute that could send out the commit email. As I got started though, I realized that it might be nice to write something that would allow others to easily handle other Subversion hooks. Hence CaptainHook was born.
Hooks in Subversion are scripts (or executables) that are triggered by an event in the subversion version control life cycle. The following are the five hooks supported by Subversion. For a short discussion on how to install the hooks, read this post by Pete Freitag.
Note that (except for post-commit
and post-revprop-change
) the
return value of the script controls whether or not the commit should
continue. If the script returns 0, the commit continues. If it returns
anything other than 0, the commit is stopped.
Script Name | Triggered By | Arguments | Notes |
---|---|---|---|
start-commit |
Before the commit transaction starts | Repository Path and username | Can be used for repository access control. |
pre-commit |
After the commit transaction starts but before the transaction is commited | Repository Path and transaction name | Often used to validate a commit such as checking for a non-empty log message. |
post-commit |
After the commit transaction completes | Repository Path and the revision number of the commit | Can be used to send emails or backup repository. |
pre-revprop-change |
Before a revision property is changed | Repository Path, Revision, Username, name of the property | Revision Property’s new value is passed into standard input. Can be used to check permission. |
post-revprop-change |
After a revision property is changed | Repository Path, Revision, Username, name of the property | Can be used to email or backup these changes. |
My goal was to provide a nice strongly typed interface and a few useful service methods for accessing Subversion. Thus handling a Subversion hook is as easy as implementing an abstract base class and calling methods on a Subversion wrapper interface.
Setup
To setup CaptainHook, simply unzip the exe file and its related
assemblies into the hooks
folder on your Subversion server. The
distribution includes a plugins
directory with a single plugin already
there. The plugins directory is where CaptainHook looks for other hook
handlers. Be sure to update the config file with settings that match
your environment.
The next step is to rename the .tmpl file for the hook events you wish
CaptainHook to handle. CaptainHook comes with some sample batch files
you can use instead, one for each hook. Just copy the ones you want to
use from the SampleBatchFiles
directory into the hooks
directory.
Flow
Now when a commit occurs, Subversion will call the post-commit.bat
file which in turn calls CaptainHook with the post-commit
flag. This
flag indicates to CaptainHook which plugins to load. CaptainHook then
looks in the plugins
directory for any assemblies with types that
implement the PostCommitHook
abstract class. It then instantiates
instances of these types and calls the Initialize
method and then the
HandleHook
method.
Note that for the time being, CaptainHook is an executable so it has to incur the cost of searching the plugin assemblies every time which may seem like overkill (and it is). However my focus was on the model for CaptainHook. At some point it will evolve to use remoting as a Server Activated Singleton or it may become a Windows Service which fit the model better. Either way, there are ways in which we can incur this cost only once. But for now, this will do and performs well enough.
Assemblies and Classes
Captain hook contains serveral assemblies.
Assembly | Purpose |
---|---|
CaptainHook | This is the main console exe and is the starting point for the application. |
CaptainHook.Interfaces | Contains the interface definitions. This is the only assembly you need to reference when writing a plugin. |
CaptainHook.SubversionWrapper | This is potentially useful as a stand-alone library. It includes the SubversionRepository class which allows running commands against Subversion and receiving the output as a string. This is useful for running straight commands against Subversion. This assembly also includes the SubversionTranslator class. This class wraps the SubversionRepository class and provides an object oriented means to calling the Subversion commands. |
Velocit.Hook.Plugins | Contains the PostCommitEmailHook plugin that started this whole ordeal as well as the RequireLogMessageHook which is a pre-commit hook that demonstrates how to reject a commit if no log message is specified. |
Let me know if you find this useful. It is definitely a work in progress
as not every command is implemented in the SubversionTranslator
class.
If it turns out that several people find this useful and want to
contribute to the code, I am willing to put the code on
SourceForge.
Download CaptainHook from my company’s tools site.
The zip archive contains both the source code and the binaries. I also compiled an x64 version of the exe for you 64bit kids.
Comments
33 responses