Sunday, October 2, 2011

Subversion: Post-Commit Email Notification

A Subversion repository has a post-commit "hook" which is invoked on every SVN commit. This can be used to send email notifications to all team members involved.

The following is my two-script method inspired by Andrew Farley's SVN Post-Commit Automatic Email.
With this method, we can set different emails for each repositories, and we only have to keep the main script in one place for easy maintenance.

This script is easy to configure and highly customizable. As a batch script, it can be used by Subversion on Windows.
Blat is required for sending email. You only need to change the values in the "Begin/End Settings" section. Please refer the script header remarks for more information and other options.

How to use:

1. Create a batch file named as "weizh-post-commit-email.bat" with the following contents:

ECHO OFF

REM =====================================================================================
REM Copyright 2011 Weizh Chang
REM 
REM This program is free software: you can redistribute it and/or modify
REM it under the terms of the GNU General Public License as published by
REM the Free Software Foundation, either version 3 of the License, or
REM (at your option) any later version.
REM
REM This program is distributed in the hope that it will be useful,
REM but WITHOUT ANY WARRANTY; without even the implied warranty of
REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
REM GNU General Public License for more details.
REM
REM You should have received a copy of the GNU General Public License
REM along with this program.  If not, see <http://www.gnu.org/licenses/>.
REM
REM
REM This script is inspired by 'SVN Post-Commit Automatic Email' by Andrew Farley
REM (andrewfarley.com/sysadmin/svn-commit-automatic-email).
REM =====================================================================================

REM =====================================================================================
REM Program    : Weizh SVN Post-Commit Email Batch Script
REM File       : weizh-post-commit-email.bat
REM Version    : 1.0.0.0
REM URL        : simpcode.blogspot.com
REM Description:
REM
REM Please change the settings in the Begin/End Settings section below.
REM
REM This script requires:
REM - post-commit.bat (the caller).
REM - blat emailer tool (www.blat.net).
REM - usermap (optional - see below).
REM
REM Features:
REM - Sends SVN post commit email notification.
REM - Allows multiple common email recipients for all repositories.
REM - Allows multiple custom email recipients for each repository.
REM - Option to include the SVN Diff in the email.
REM - Option to skip sending email using the 'no email' tag in the log.
REM - Option to use usermap (see below).
REM
REM
REM usermap:
REM This script is able to read the authorized svn users from conf\authz, and map to
REM the users' emails in a 'usermap' file. These emails will be used as part of 
REM the receiver emails. This feature can be disabled by changing the 
REM Settings' usermap to empty.
REM
REM The following example shows how a 'usermap' file content may look like:
REM
REM harry=name=Harry Smith
REM harry=email=harry@example.com
REM
REM sally=name=Sally Anderson
REM sally=email=sally@example.com,sally@example2.com
REM =====================================================================================

ECHO ON

SET repos=%1
SET rev=%2
SET reposName=%3
SET sendTo=%4
SET sendToCc=%5


REM ================ Begin Settings ====================

REM ==== Set email settings
SET emailServer=mail.example.com
SET emailPort=25
SET emailUid=admin@example.com
SET emailPwd=adminPassw0rd
SET sendFrom=admin@example.com
SET sendTry=5

REM ==== Set common receiver/cc email (comma separated, without quotes and spaces)
SET sendToCommon=
SET sendToCcCommon=michelle@example.com,alex@example.com

REM ==== Set the blat exe directory
SET emailDir=C:\blat\

REM ==== Set the SVN bin directory
SET svnDir=C:\svnserve\bin\

REM ==== Set the SVN Diff line limit (-1 to not show any)
SET limitDiff=-1

REM ==== Set the usermap file location (leave empty if not using usermap)
SET usermap=D:\svn_repos\scripts\usermap

REM ==== Set no email tag. If this tag exists at the beginning of a line in the log,
REM ==== no email will be sent (leave empty if not using this feature)
SET noEmailTag=[noemail]

REM ================ End Settings ======================


REM ==== Remove surrounding quotes
SET repos=%repos:"=%
SET rev=%rev:"=%
SET reposName=%reposName:"=%
SET sendTo=%sendTo:"=%
SET sendToCc=%sendToCc:"=%

REM ==== Set reposName to repos if empty
IF "%reposName%"=="" SET reposName=%repos%

REM ==== Get svn author
FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" author -r %rev% %repos%') DO SET author=%%R
SET authorName=

REM ==== Set email temp file
SET tmpFile=%~dp0svn-email-%rev%-%RANDOM%.tmp


REM ================ Begin Read Usermap ================

REM ==== Skip if usermap not exist
IF "%usermap%"=="" GOTO SendEmail
IF NOT EXIST %usermap% GOTO SendEmail

SETLOCAL ENABLEDELAYEDEXPANSION

REM ==== Set authz file
SET reposAuthz=%repos:/=\%\conf\authz

SET sendToMap=
SET authorName=

FOR /F "tokens=1,2,3 delims==" %%A IN (%usermap%) DO (
    IF NOT "%%%A:~0,1%"=="#" (
        IF "%%B"=="email" (
            IF NOT "%%C"=="" (
                SET count=0
                REM ==== If user exists in authz, append the emails to sendToMap
                FOR /F "tokens=1 delims==" %%U IN ('FINDSTR /I /B "%%A.*\=.*r" %reposAuthz%') DO (
                    REM ==== Remove any spaces
                    FOR /F "tokens=1 delims= " %%Y IN ("%%U") DO (
                        IF "%%Y"=="%%A" (
                            IF !count!==0 (
                                IF NOT "!sendToMap!"=="" SET sendToMap=!sendToMap!,
                                SET sendToMap=!sendToMap!%%C
                                SET count=1
                            )
                        )
                    )
                )
            )
        ) ELSE (
            IF "%%B"=="name" (
                IF "%%A"=="%author%" SET authorName=%%C
            )
        )
    )
)

SET mapReturns=^
  SET sendToMap=%sendToMap%^&^
  SET authorName=%authorName%

ENDLOCAL & %mapReturns%

REM ==== Append to the existing sendTo
IF NOT "%sendToMap%"=="" (
    IF NOT "%sendTo%"=="" SET sendTo=%sendTo%,
)
SET sendTo=%sendTo%%sendToMap%

REM ================ End Read Usermap ==================


:SendEmail

REM ==== Append any common emails
IF NOT "%sendToCommon%"=="" (
    IF NOT "%sendTo%"=="" SET sendTo=%sendTo%,
)
SET sendTo=%sendTo%%sendToCommon%

IF NOT "%sendToCcCommon%"=="" (
    IF NOT "%sendToCc%"=="" SET sendToCc=%sendToCc%,
)
SET sendToCc=%sendToCc%%sendToCcCommon%

REM ==== Exit if sendTo is empty
IF "%sendTo%"=="" GOTO Finish

REM ==== Set sendTo with surrounding quotes
SET sendTo="%sendTo%"

REM ==== Set sendToCc with argument switch and surrounding quotes
IF NOT "%sendToCc%"=="" SET sendToCc=-cc "%sendToCc%"

REM ==== Get svn date and time
FOR /F "tokens=1,2" %%R IN ('"%svnDir%svnlook.exe" date -r %rev% %repos%') DO (
    SET svnDate=%%R
    SET svnTime=%%S
)


REM ==== Set email subject
SET subject=[%reposName%] SVNCommit (%author%) Rev: %rev%

REM ==== Set email body

(
ECHO Dear Developers,
ECHO.

IF NOT "%authorName%"=="" (
    ECHO There is an SVN Commit on  [ %reposName% ]  by %authorName% ^(%author%^).
) ELSE (
    ECHO There is an SVN Commit on  [ %reposName% ]  by %author%.
)

ECHO Please SVN Update your working copy.
ECHO.
ECHO.
ECHO -------------------- SVN Commit Notification --------------------
ECHO Repository:    %reposName%
ECHO Revision:      %rev%
ECHO Author:        %author%
ECHO Date:          %svnDate%      Time: %svnTime%
ECHO.
ECHO -----------------------------------------------------------------
ECHO Log Message:
ECHO -----------------------------------------------------------------
) >%tmpFile%

REM ==== Get svn log
FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" log -r %rev% %repos%') DO ECHO %%R >>%tmpFile%

REM ==== If the 'no email tag' exists in the log, exit without sending email
IF NOT "%noEmailTag%"=="" (
    FOR /F "tokens=*" %%E IN ('FINDSTR /I /B /C:"%noEmailTag%" %tmpFile%') DO GOTO Finish
)

(
ECHO.
ECHO -----------------------------------------------------------------
ECHO Changes:
ECHO -----------------------------------------------------------------
) >>%tmpFile%

REM ==== Get svn changed
FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" changed -r %rev% %repos%') DO ECHO %%R >>%tmpFile%

IF NOT "%limitDiff%"=="-1" (
(
ECHO.
ECHO -----------------------------------------------------------------
ECHO Diff: ^(only first %limitDiff% lines shown^)
ECHO -----------------------------------------------------------------
) >>%tmpFile%

REM ==== Get svn diff
FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" diff -r %rev% %repos% ^| head --lines=%limitDiff%') DO ECHO %%R >>%tmpFile%
)

(
ECHO.
ECHO.
ECHO Regards,
ECHO SVN Server Admin
) >>%tmpFile%


REM ==== Send email
"%emailDir%blat.exe" %tmpFile% -server %emailServer%:%emailPort% -f %emailUid% -u %emailUid% -pw %emailPwd% -from %sendFrom% -to %sendTo% %sendToCc% -subject "%subject%" -try %sendTry%


:Finish
REM ==== Cleanup
IF EXIST %tmpFile% DEL /Q %tmpFile%

2. Set values in the Begin/End Settings section. Put this file inside a folder accessible by all repositories. For instance, If your repository root folder is "D:\svn_repos\", you may put it inside "D:\svn_repos\scripts\".

3. Create another batch file named as "post-commit.bat" with the following contents:

SET repos=%1
SET rev=%2


REM ==== Set repository name for display only, if empty will be same as repos
SET reposName=

REM ==== Set receiver/cc email (comma separated, without quotes and spaces)
SET sendTo=
SET sendToCc=


D:\svn_repos\scripts\weizh-post-commit-email.bat "%repos%" "%rev%" "%reposName%" "%sendTo%" "%sendToCc%"

4. Set the repository's name and receiver/cc emails if any. Change the "D:\svn_repos\scripts" to your path. Put this file inside each repository's "hooks" folder.

Whenever there is a commit, an email will be sent to the relevant recipients with contents such as below:
Dear Developers,

There is an SVN Commit on  [ XXXX ]  by Harry Smith (harry).
Please SVN Update your working copy.


-------------------- SVN Commit Notification --------------------
Repository:    XXXX
Revision:      139
Author:        harry
Date:          2011-10-01      Time: 19:53:53

-----------------------------------------------------------------
Log Message:
-----------------------------------------------------------------
Added and modified on some stuff.

-----------------------------------------------------------------
Changes:
-----------------------------------------------------------------
U  Trunk/Foo/
U  Trunk/Foo/Foo.csproj
A  Trunk/Foo/Helper.cs
U  Trunk/Foo/Customer.cs
U  Trunk/Foo/Properties/AssemblyInfo.cs
D  Trunk/Foo/Test.txt


Regards,
SVN Server Admin

If you find this post helpful, would you buy me a coffee?


23 comments:

  1. can anyone tell me that what changes i should apply while i am executing it in my server

    ReplyDelete
  2. It's great, but I want chosse some folder in Repos to send email. How I can do this ?

    ReplyDelete
  3. Hi Georgekutty,
    Just set your values in the Begin/End Settings section (Step 2).

    ReplyDelete
  4. Hi Anonymous,
    If you know batch command, you may modify it in
    "REM ==== Get svn changed":

    1. Inside the FOR loop, only ECHO to the %tmpFile% if the path you want exist in %%R.
    2. If none exist, GOTO Finish.

    ReplyDelete
  5. Hi Weizh Chang,
    I'm not familiar with CMD, so i can't do it :(

    ReplyDelete
  6. Hi, I totally new to SVN . Can you tell me what are the changes should be done to make this script to work? Thanks in advance .

    ReplyDelete
    Replies
    1. Hi, sorry for late reply.
      You can just follow the steps from 1 to 4. Most importantly, make sure you set the correct values in the "Begin/End Settings" section of "weizh-post-commit-email.bat".

      Delete
  7. it is not executing .can you help me what all changes i need to do in this script and

    when it will be calling weizh-post-commit-email.bat ?

    ReplyDelete
    Replies
    1. Hi,

      Please make sure you've created "post-commit.bat" in the repository' "hooks" folder. And make sure the path to "weizh-post-commit-email.bat" is correct (step 3 and 4).

      If you're using Subversion on Windows, the "post-commit.bat" will be triggered automatically for each post-commit event.

      Also, make sure you've set the correct values in the "Begin/End Settings" section of "weizh-post-commit-email.bat" as well.

      Delete
  8. Hello

    I am getting the email but I am unable to get the details such as Author, Files changed in the email body

    Regards
    Girish

    ReplyDelete
    Replies
    1. Hi,

      Seems like you could not get any data returned from the svnlook.exe command. You may try to run svnlook.exe in a separate command prompt window on the same PC and see whether it can work. You can refer here on how to use the svnlook http://svnbook.red-bean.com/en/1.7/svn.ref.svnlook.html

      You may also try to run the script from a command prompt window (add a PAUSE on the last line), and see if there is any error while calling svnlook.exe.

      Hope this helps.

      Delete
  9. Hi,

    Please help me. I have configured everything and when calling the same command through cmd prompt its working fine bt when post-commit.bat is calling the same file the temp file is being created but email is not being send. Please suggest what is to be done.

    Waiting for the reply

    ReplyDelete
    Replies
    1. Hi,

      Sounds to me you're hitting some problem at the "==== Send email" section, and "==== Cleanup" cannot be reached at all.

      Maybe you could try adding a "pause" command before/after the "==== Send email" section, then run the bat file and see what is the error being returned.

      Hope this helps.

      Delete
    2. Hi,

      I have entered pause and then executed the bat file directly, there were no error and no email was been send.

      Please suggest waiting for your reply.

      Delete
    3. Hi,

      The "==== Send email" section uses "blat.exe" to send the temp file (%tmpFile%). If the temp file is created with the correct content (you can check it using Notepad), then something should be wrong when calling blat.exe.

      Please make sure your email settings (server, port, id, password, etc.) are all correct and workable. You could narrow down the problem by creating a batch file which only calls blat.exe with hard-coded email settings and arguments, and test it from there.

      You may want to check out http://www.blat.net for more information.

      Hope this helps.

      Delete
    4. Hi Weizh,

      I followed the following steps

      Step 1. I commented the file deletion code from the "weizh-post-commit-email.bat"

      Step 2. when i commited in a repo the file was created with the correct content seen in Notepad.

      Step 3. I created a batch file in which for sending an email through blat.exe and executed that and got the same mail in the inbox.

      Please suggest what else can be done. As now blat.exe is working properly.

      Is there any other software which is to be supported for the sending email like pearl etc.

      Will be waiting for your reply.

      Thanks in advance.

      Delete
  10. I'm using VISUALSVN. My output shows blank for everything...

    Beside your script I was using powershell script. It also showing blank email. No repos, no rev, no author, no nothing.. Please help.

    Thank you.

    ReplyDelete
  11. Hi,
    It is a great script and is working fine. Thanks for the script
    Please share how to enable diff in the email.

    ReplyDelete
    Replies
    1. Thanks.
      You may change the -1 to any number of lines to show the Diff:
      SET limitDiff=-1

      Delete
  12. Hello,

    I think the construction:

    ... svnlook.exe" diff -r %rev% %repos% ^| head --lines=%limitDiff% ...

    doesn't work for Windows BAT file. The "head" is command for Linux. Could you please replace on Windows analog?

    ReplyDelete
    Replies
    1. Hi,

      Thanks for the comment.

      I've tested that line and it worked for Windows BAT and the Diff lines could be shown correctly. Would you mind to share the error you've encountered?

      Delete
    2. Hi, no errors appear. But the result of Diff I don't see too. If I try to use the "head" from command prompt window I see "command not found". I use OS Win 2003 server. May be this is the reason?

      I exchange the line:

      REM ==== Get svn diff
      FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" diff -r %rev% %repos% ^| head --lines=%limitDiff%') DO ECHO %%R >>%tmpFile%
      )

      on:

      REM ==== Get svn diff
      SET /A COUNTER=1
      FOR /F "tokens=*" %%R IN ('"%svnDir%svnlook.exe" diff -r %rev% %repos%') DO (
      ECHO %%R >>%tmpFile%
      IF !COUNTER! == %limitDiff% (GOTO end)
      SET /A COUNTER=!COUNTER!+1
      )
      )

      :end

      And the script are working correctly now. Thank you for your script!

      Delete
    3. Hi,

      I was using Windows Server 2008 R2, maybe there's a difference? Glad you've a solution, and thanks for sharing it.

      Delete