SVN post-commit for Windows

Categories: HTML/ColdFusion, Source Code, JavaScript, Java, SQL, Flex/Flash

As I mentioned early I've been working on a SVN post-commit script. We've got a SVN repository that will be modified by several remote developers and I really need to keep an eye on this repository and I need to closely monitor changes to this repository.

There are two major functions that I needed in my post-commit script:

  1. I needed to update the working copy on my server
  2. I needed to e-mail the changes to myself, so I know when developers are making changes

There are an abundant of examples showing off how to do this in various *nix flavors, but I couldn't find any good Windows-based solutions that didn't require Perl to be installed on the server. That led me to create the following post-commit.bat script.

@ECHO OFF
REM *************************************************************
REM * this sets the arguments supplied by Subversion            *
REM *************************************************************
SET REPOS=%1
SET REV=%2

REM *************************************************************
REM * define directory paths                                    *
REM * you *must* add any paths for command line tools you plan  *
REM * since SVN does not include the Windows %PATH% environment *
REM * variable for security reasons.                            *
REM *                                                           *
REM * DIR  - the current hooks directory                        *
REM * PATH - a user set path of where executables are located   *
REM *                                                           *
REM *************************************************************
SET DIR=%REPOS%/hooks
REM *************************************************************
REM * make sure to add the path to the SendEmail executable     *
REM *************************************************************
SET PATH=%PATH%;%DIR%;C:\Utils 

REM *************************************************************
REM * define the path to the working copy of your code          *
REM *                                                           *
REM * the default working_copy folder would be:                 *
REM * file:///%REPOS%                                           *
REM *************************************************************
SET WORKING_COPY=c:\path\to\working\copy

REM *************************************************************
REM * define e-mail parameters                                  *
REM *************************************************************
SET SITENAME=My Code Base
SET SMTP_SERVER=smtp.yourdomain.com
SET EMAIL_TO=svnupdates@yourdomain.com
SET EMAIL_FROM=svnupdates@yourdomain.com
SET SUBJECT=SVN Update - %SITENAME% - rev %REV% - %REPOS%

REM *************************************************************
REM * update the local working copy                             *
REM * this will sync the new changes to your servers copy       *
REM *************************************************************
svn update %WORKING_COPY%

REM *************************************************************
REM * generate the header to use for the e-mail message         *
REM *************************************************************
ECHO The following changes were made to the code: > %DIR%/email.txt
ECHO. >> %DIR%/email.txt

REM *************************************************************
REM * dump the log of changes to the e-mail message             *
REM *************************************************************
svn log %WORKING_COPY% -v -r "%REV%" >> %DIR%/email.txt

REM *************************************************************
REM * dump the diff changes to the e-mail message               *
REM *                                                           *
REM * WARNING: Generates tons of output                         *
REM *                                                           *
REM * NOTE: this is optional, you can remove this information   *
REM *       if you do not want a verbose message of changes     *
REM *************************************************************
svn diff %WORKING_COPY% -c "%REV%" --no-diff-deleted >> %DIR%/email.txt

REM *************************************************************
REM * send the e-mail message to the user                       *
REM *                                                           *
REM * NOTE: to create a SendEmail.log file, append:             *
REM *                                                           *
REM *        -l %DIR%/SendEmail.log                             *
REM *                                                           *
REM *       at the end of the line below.                       *
REM *************************************************************
sendEmail -s %SMTP_SERVER% -t %EMAIL_TO% -f %EMAIL_FROM% -u "%SUBJECT%" -o message-file=%DIR%/email.txt

A couple of notes on the script above:

  • You'll need to download SendEmail in order to send the e-mail messages. In the environmental variable %PATH% you'll want to make sure to include the path where you copied the SendEmail.exe. In the example above, the SendEmail.exe is located in the C:\Utils directory.
  • Make sure to go through the script and replace any variables declared with the SET command with the values that coorelated to your environment.
  • In my case I required a working copy to be placed on my server, as it's used as a global development environment. If you do not require a local working copy, you can comment out the svn update %WORKING_COPY% line (by placing the command REM in front of the line.) You would then change your WORKING_COPY variable to the URL of your SVN repository—which would be file:///%REPOS%.
  • The svn diff command can generate a ton of information. In most use cases, you probably do not want to add this information to the e-mail output.

If you have any problems getting this script working, I recommend you check out my blog entry on debugging SVN repository hook scripts in Windows.

Comments

Amol's Gravatar Too good! I am searching post hook batch files ... and this is the right choice. :)
Aaron's Gravatar This helped me immensely! Thank you!

For others that come across this, Here's where I got stumped. If you're running subversion with apache, this script will be run as Apache. I needed to run this against a network path like: \\server\share I couldn't, because apache didn't have network access rights.

I had to update the apache service (and perhaps the subversion service) to run using my user account. It worked fine after that.
Danny Armstrong's Gravatar I find passing off to python or ruby allows you to do much more powerful things.

@echo off
set REPOS=%1
set REV=%2

c:\SVN\ServiceRoot\bin\svnlook changed -r %REV% %REPOS% >
c:\SVN\Repo\CodeBoy\hooks\changed.txt
c:\python25\python C:\SVN\Repo\CodeBoy\hooks\updateChanged.py

This way you can only call an update on the modified paths instead of killing your box trying to update the entire checkout.
Seth Aaronson's Gravatar Great script, thanks!
I have users set up with their smtp addresses as their user names. Is there a way to
SET EMAIL_TO= with the value of the user committing the file(s)?
Dan G. Switzer, II's Gravatar @Seth:

The follow SVN command would get you the author of an update:

svnlook author -r "%REV%" "%REPOS%"

See this URL for more usage:
http://svnbook.red-bean.com/en/1.4/svn.ref.svnlook...

You'd need to capture that output and get it into a variable to send it to the author (since the post-commit unfortunately doesn't pass author information to script.)

Just curious as to why you'd only want to notify the commiter via e-mail--since they'll know immediately if their commit passed or failed.
Seth Aaronson's Gravatar I want to use this script to notify the IT team that code has been committed.
The from address in the message ought to be the author of the commit.
The to address is the person that will push the files.
Dan G. Switzer, II's Gravatar @Seth:

Gotcha. Here's a link that should help you capture the author information from the svnlook command:

http://weblogs.asp.net/lorenh/archive/2006/03/24/4...

Pay attention to the comment that mentions:

FOR /F "tokens=*" %%i in ('%~dp0sometool.exe') do SET TOOLOUTPUT=%%i
Seth Aaronson's Gravatar @Dan
Thanks for your response.
Since sometool.exe is svnlook, how would that be set?

When I have this:

FOR /F "tokens=*" %%i in ('%~dp0C:\svnserve\bin\svnlook author -r "%REV%" "%REPOS%"') do SET TOOLOUTPUT=%%i

and

SET EMAIL_FROM=%TOOLOUTPUT%

this is the post-commit log:

The filename, directory name, or volume label syntax is incorrect.
Dec 03 09:34:34 myusername sendEmail[4084]: WARNING => The argument after -f was not an email address!
Dec 03 09:34:34 myusername sendEmail[4084]: ERROR => You must specify a 'from' field! Try --help.
Seth Aaronson's Gravatar @Dan,
I got this to work by copying the svnlook.exe into the hooks folder and using the syntax

FOR /F "tokens=*" %%i in ('%~dp0svnlook.exe author -r "%REV%" "%REPOS%"') do SET TOOLOUTPUT=%%i

Since svnlook.exe is 53 kb, this will do for now until I understand the %~ function.

-Peace
Dan G. Switzer, II's Gravatar @Seth:

You don't need svnlook in the hooks folder, you just need to specify the path to executable. As my other blog entry on troubleshooting post-commit hooks talks about, hooks do not have access to environmental variables.

This means your batch file has a PATH environment that's empty (which is why svnlook might run from a command prompt without the full path.)

Anyway, just use a path to the svnlook.exe and all should be well.
Seth Aaronson's Gravatar @Dan,
There is a path set:
SET PATH=%PATH%;%DIR%;C:\svnserve;C:\svnserve\utils
I would think [svnlook] would be available like [svn log] and [sendEmail].

Since this is a standalone Subversion instance running as a Windows service, and the root repository folder is located on a different drive, and the FOR command in conjunction with the %~ command is not fully understood by me, perhaps this is why I choose to get it to work by placing svnlook in the hooks folder.
Seth Aaronson's Gravatar @Dan,
I think I have it running now without having to have svnlook in the hooks directory.
I removed the %~dp0, and just have the line as

FOR /F "tokens=*" %%i in ('C:\svnserve\svnlook.exe author -r "%REV%" "%REPOS%"') do SET TOOLOUTPUT=%%i

and then I can place

SET EMAIL_FROM=%TOOLOUTPUT% for use in the sendEmail command.
Evan's Gravatar When I run this script on a commit using tortoise the commit hangs forever. Is there anyway that I can see what the script is doing or does anyone have any idea what would cause it to hang?
Thanks!
Dan G. Switzer, II's Gravatar @Evan:

See my blog entry on debugging post-commit scripts for tips:

http://blog.pengoworks.com/index.cfm/2008/2/5/Debu...
Evan's Gravatar @Dan Thanks! The output helped me to find the issue which I fixed but now I am having an authentication realm issue.

I get the following in my log file:

C:\apache>svn update c:\checkout\procedures
Authentication realm: <http://address:80>; Subversion repository
Password for 'SYSTEM':

I never created an account named system and I am committing from another machine using tortoise. Where does the script get its login info?

Thanks!
Dan G. Switzer, II's Gravatar @Evan:

SYSTEM is a special Windows account. Sounds like the SYSTEM account does not have access to write tot he c:\checkout\procedures folder.
Daniel Fredericks's Gravatar Hey dan,
When I run the script, I get this error in my log file....the email runs, though without any info in it, but I get this error...can you explain this...all we need to do is run the script so we can update our development area.

Certificate information:
- Hostname:
- Valid:
- Issuer:
- Fingerprint:
(R)eject, accept (t)emporarily or accept (p)ermanently? svn: OPTIONS of 'https://server name/TestingRepository/trunk': Server certificate verification failed: issuer is not trusted (https://server name:8443)
Feb 06 14:56:56 server sendEmail[6196]: Email was sent successfully! From: <email address> To: <another email address> Subject: [SVN Update - subversion testing - rev 18 - E:\Repositories\TestingRepository] Server: [mailserver:25]
Dan G. Switzer, II's Gravatar It looks like it doesn't like your SSL cert. My guess is your using a home grown SSL cert and SVN is unable to access the URL because of the invalid cert. Either fix the cert or try to see if there's a way to get SVN to use the cert by adding it to a cert store (I'm not even sure that's possible with the SVN client utils.)
Dan G. Switzer, II's Gravatar @Daniel:

Also, use the physical path to the repository files instead of the URL--which will completely get rid of the need to use SSL altogether.
Steve Myers's Gravatar Good Morning Dan G. Switzer,

Are you referring to the UNC that is used through-out SVN? I don't believe we are using URL's for Repositories and or working files areas. We do have certs developed by Verasign for our system, so I am perplexed as to why it would not like them. Perhaps we are looking at the wrong kind of cert? I work with Daniel Fredericks and we really like SVN, provided we can get past this issue.
Steve Myers's Gravatar My bag, I was thinking about another issue we had, Daniel explained to me that we in fact are using a secure link with SVN. Sorry for the confusion.
Vivek Payala's Gravatar Cool stuff! I got my Windows post commit hook working by simply following the above mentioned steps.
Daniel Fredericks's Gravatar Dan,
Just wanted to thank you for this code. We figured out what our issue was and this code works great.
Jon Hinson's Gravatar @Evan and @Dan:

I received the same output:
Password for 'SYSTEM':

And I solved it by adding the --username ARG and --password ARG options to the end of the svn up command.

Add Comment

Leave this field empty


If you subscribe, any new posts to this thread will be sent to your email address.