Sending emails on SVN Commits in VisualSVN

11 November, 2011

In todays world, collaboration is everything. Development tools such as SVN have made collaborating and working with other people a piece of cake. For those who may be unaware SVN is a versioning system allowing you to keep track of every change made to a project (a repository) and who made and submitted the change. As well as tracking you are also able to roll back onto an old version of a certain file if issues arise or you just want to go back to how it used to work.

The way this works is when a change is made, a user will normally "Update" the repository and then "Commit" their changes to the repository. That's in an ideal world, however we are all human and sometimes we may forget to Update or Commit our changes. This is when conflicts can arise with SVN not knowing which one it should look at. People have got round this issue in many ways, one of the more popular ones is to utilise some of SVNs built in features to email the people involved in a project when a commit has happened. Meaning they have no excuse when it comes to updating the repository and making sure conflicts don't occur. In this article I'll show you how to accomplish this!

Later, in another tutorial, I'll show you also how you can link this with your Basecamp account to post messages to your Basecamp projects as well as sending the emails out!

To complete this tutorial, you'll need some knowledge of SVN (and have access to your repositories files on the server), PHP and server commands.

Getting started with hooks

To get started with this, first we'll need to make use of some of SVNs built in functionality in the form of 'hooks'. Hooks allow you to inject small pieces of code into certain points of the system's workflow. SVN has a selection of hook points but the one we'll be dealing with is the "Post Commit" hook. This hook runs straight after a commit has taken place. To set the hook up you'll need to login to your SVN server and navigate to the repository you wish to set email notifications up on. For me, this is running a Windows Server in our office and the repositories can be found at "D:\Repositories\REPOSITORY-NAME", of course this may be different for you.

Once you've found the folder containing your SVN Repositories, locate and open the folder containing the repository you wish to set notifications up on. Inside here should be a few folders and files. The folder we are interested in is "hooks", inside here as default should be a selection of TMPL files. These are the hooks files before they have been made active.

To activate a hook change the filename from .tmpl to .cmd, as mentioned above the hook we are interested in is the "Post Commit" hook, so locate the file "post-commit.tmpl" and change this to "post-commit.cmd" to activate it. Currently, the post commit hook won't doing anything until we place a command in there. Copy the command below and place it into the post-commit.cmd file. Change the path to the php.exe to the location of the php executable file on your server. The second path is the file that will be run once a commit has taken place. This file can be used across all repositories that are setup to email users on commit, so bear this in mind when deciding where to place this file. It will need to be a location which is easily accessible for all repositories, once you've decided replace the file path in the code below:

Post-Commit Hook

"path/to/server/php-installation/php.exe" Path/to/php/notification/notify.php %1 %2

%1 and %2 are variables which the hook will pass into the notify.php file. More on these later.

Creating the PHP

Now we'll take a look at notify.php, as mentioned earlier this will be the file that run on the post-commit hook and will send us the email. Start off by creating the notify.php file in the location you decided on in the post-commit.cmd file. Once created open the file and place the following code into the file:


#! /usr/bin/env php
$repo_path = $argv[1]; // retrieve repository path - this is the %1 passed in the post-commit hook $rev = $argv[2]; // retrieve the revision number of the latest commit - this is the %2 passed in the post-commit hook
$revision = trim($rev);
// retrieve details about the commit $author = trim(`"Path/to/visualsvn/server/svnlook.exe" author {$repo_path} -r {$revision}`); $date = trim(`"Path/to/visualsvn/server/svnlook.exe" date {$repo_path} -r {$revision}`); $message = trim(`"Path/to/visualsvn/server/svnlook.exe" log {$repo_path} -r {$revision}`); $changed = trim(`"Path/to/visualsvn/server/svnlook.exe" changed {$repo_path} -r {$revision}`);
// the date format returned isn't very pretty so we explode out the returned string to get a nice date $date = str_replace('(', '', $date); $date = str_replace(')', '', $date); $date = str_replace(',', '', $date); $bits = explode(" ", $date);
// this will display something like: Tue, 01 Nov 2011 – 12:20:59 $date = "$bits[3], $bits[4] $bits[5] $bits[6] - $bits[1]";
// Put each file that has been changed into an array $temp = array(); $temp = explode("\n", $changed); // Make the codes more readable // A => Item Added // D => Item Deleted // U => Item Contents Updated // _U => Item Properties Updated // UU => Item Contents and Properties Updated
// variable ready to hold formatted list of files to display in the email $files = "";
// loop through the changed files foreach ($temp as $tmp) { $bits = explode(" ", $tmp);
$action = $bits[0]; $file = $bits[sizeof($bits)-1];
// work out what has happened to this file switch ($action) { case 'A': $act = 'Added'; break; case 'D': $act = 'Deleted'; break; case 'U': $act = 'Updated'; break; case '_U': $act = 'Updated'; break; case 'UU': $act = 'Updated'; break; } $act = str_pad($act, 12); $act = str_replace(' ', ' ', $act);
$files .= $act . $file . "\r\n"; // add to the $files variable ready to put into the email }
$email_subject= "SVN: Revision $revision";
// explode the repository path to allow us to get the repository name $repo_ex = explode("\\", $repo_path); $reponame = end($repo_ex);
// build the email body given all the data we have on the commit $email_body = ''; $email_body .= "Repository: ".$reponame."\r\n"; $email_body .= "Author: ".$author."\r\n"; $email_body .= "Date: ".$date."\r\n"; $email_body .= "Message:\r\n"; $email_body .= "-------------\r\n"; $email_body .= $message."\r\n"; $email_body .= "-------------\r\n"; $email_body .= "Changed Files:\r\n"; $email_body .= $files
// email contents have been built // build the headers // then send the email!
$headers = "FROM:";
mail(",", $email_subject, $email_body, $headers);

Once saved, amend the email addresses in the PHP mail function at the bottom of the page. Make some changes to some files within one of your repositories and commit the changes. All being well you should receive an email shortly.

This isn't instant and sometimes depending on the size of your commit (i.e. adding lots of files at the start of a project) it may take a little while longer to compile the commit and send the email out.

Further Development

While this is a great and useful tool to have in your arsenal there are a few other things that can still be done. Are you using Basecamp for your project management? We can easily integrate the above script to post a message to basecamp and to post it to the associated project within Basecamp.

We could also take this one step further and create a web interface for use on your local server to automatically set up the repository for you (even setting up the post-commit hook for you) and even (if you are using it) linking it with a Basecamp account.

Stay tuned for the next part in this line of tutorials where we will look at implementing some of the features mentioned above!


Leave a comment

Replying to: - Cancel