January 3, 2008

E-mail File for Review

Surround SCM

Works with Surround SCM 5 and later

Some time ago I wrote an article on how to e-mail a file from Surround SCM after it is checked in. The file that is e-mailed is the latest version from the Surround SCM server. While the ability to e-mail a file automatically from Surround SCM can be very useful, a better suited solution for your process may be to e-mail the file that exists in a user's working directory before it is checked in. This gives someone other than the user doing the changes the opportunity to review it. Some testing could also take place. Once the file has gone through a review/approve process, then it can be checked in. This process can increase the chances that you will only have quality check ins in your source code management system. [toc]

Obstacles & Solutions

Getting the correct file

The main obstacle to achieve this in Surround SCM is with the way triggers run. In Surround SCM, triggers run on the server machine by the server process. How can the server access the file on the local machine (working directory)? A thought could be to hard code working directories, share those folders and make them accessible to the server process. However this is tedious and not practical. This would require for every user to have the exact same working directory structure and also some maintenance would be required. While anybody could open their favorite e-mail client, select to attach a file and browse to the working directory, this seems like it would get annoying after a while. One would have to continually browse through the working directories and make sure the correct file is attached. Besides, when working on multiple branches, one could have several sets of directories that have the same structure. This could get confusing and make it more difficult to browse the correct working directory. Surround SCM has an environment variable, SSCM_LOCALFILE, available during some operations that scripts can take advantage of. This environment variable contains the full path to the temporary file Surround SCM creates on the server machine before committing a file change (check in, promotes, rebases, etc…). This temporary file is a file that Surround SCM takes from a working directory and copies it to the server machine, where it does some further processing before actually checking in the file (see what changes have been made, merging, etc…). This is the file we want to attach to the an e-mail for review because it contains the changes the user made (and have not been checked in yet) and is available to the server process.

Figuring out when to trigger

The main issue is that this environment variable is only available when a change committing action is invoked. Since we do not want to commit the change (we want to e-mail the changed file to someone for review before the change is committed), this presents another obstacle. One approach could be to create a trigger that occurs before a check in. It would send the e-mail and then prevent the check in action. This is not practical, since it is not intuitive to know that in order to e-mail a file you have to try to check it in. Also, you would have to use a custom field to know whether this was a check in to send the file or an actual check in. Also, if the trigger prevents the check in, you would get an error that the check in was canceled by a pre event trigger. It seems a pretty ugly solution. A better solution is to have another script do the check in. Then the error should be returned to the script and the user would not see it. Since you can trigger based on a state change, the best way to trigger this would be using a state called “Send E-mail for review”. The user could right click on any file, select State > Send E-mail for Review.

Basic Flow

The basic flow I came up for this is as follows:
  • User checks out file.
  • User modifies file.
  • User changes state of file to “Send File for Review”.
  • This fires trigger (set to fire only when resulting state is “Send File for Review”).
    • Trigger launches script.
      • Script changes a custom field value for the file (to be used as a flag).
      • Script then attempts to check in file.
  • The check in action fires another trigger (set to fire before a check in and if the custom field is set to the flag set by the first script.)
    • Second trigger fires another script.
      • Script sends e-mail.
      • Script resets the custom field
      • Script changes file state to “In review”.
    • Trigger prevents check-in (user who changed the file state never sees the prevent check in message).
The above could be enhanced with other triggers that would not allow a check in of a file unless a file has been approved.

Setting it up

Based on the flow described above, in order to set this up we require the following:
  • Custom field to be used as a flag by the triggers and scripts.
  • Workflow state used to trigger the whole process.
  • Trigger to fire off when this file enters this state and runs a script.
  • Script that flags the file and tries to check it in.
  • Trigger that checks for this flag before a check in, runs a script and then prevents the check in.
  • Script that sends e-mail, unsets the flag and changes the state of the file to denote that it is under review.
I will not go into detail on how to create the custom field, the workflow state or the triggers. Please refer to the Surround SCM User Guide for this. For this example, the new state is named "E-mail File for Review" and the custom field will be a check box called "E-mail?".

Trigger #1

The first trigger is setup to fire when a file changes state and the resulting state is "E-mail File for Review". The action is to run a batch file called setflag.bat. The trigger summary looks as follows:
Trigger applies to files in branch [<all branches>] and in repository [<all repositories>] -- after an event when resulting file state [is in list] [E-mail File for Review] -- Run script located at "d:batchsetflag.bat"

Script details

The "setflag.bat" file contains two commands from the Surround SCM CLI. One sets the custom field "E-mail?" to "checked" and the other one attempts to check in the file. This is how the commands look in my batch file:
sscm setcustomfield %SSCM_FILE% 1008 checked -b%SSCM_BRANCH% -p%SSCM_REPOSITORY% -yAdministrator: -z127.0.0.1:490

sscm ci %SSCM_FILE% -b%SSCM_BRANCH% -p%SSCM_REPOSITORY% -cc"%SSCM_COMMENT%" -yAdministrator: -z127.0.0.1:4900
The number "1008" used in the first command is the custom field ID. You can retrieve your custom field ID by running the lscustomfield(lcf) command. Also, notice that I am passing the comments made in the change state event to the check in event. This is because when a user changes the state, they will need to pass the e-mail address of who to send the file to. This is then passed to the check in command, which then will pass it to the script that will send the e-mail.

Trigger #2

The second trigger is setup to prevent any check in event for a file that has the "E-mail?" field checked. The trigger has two actions:
  • Run a script called "SendFileForReview.exe"
  • Prevent the action.
The trigger summary is as follows:
Trigger applies to files in branch [<all branches>] and in repository [<all repositories>] and E-mail? [is checked] -- before an event on a [Check in] -- Run script located at "D:DEV_ProjectsSendFileForReviewSendFileForReview.exe" Prevent the event with message "check in aborted"
Remember that since a script invoked the check in, the "Check in aborted" message will be returned to that script, not the user. The user will never know that a check in was attempted nor that it was aborted.

Script details

The script in this example was written in C# using Visual Studio 2005. Any other language can be used as long as it supports the sending of e-mails with attachments and can pass commands to the command line. If you would like to download the project I used with this example, you can download it from here. The basic flow of the script is as follows:
  • Checks the event comments for a specific token that contains an e-mail address. The token should be in the format of <e-mail:emailaddress@isp.com;{next e-mail address}>.
  • If it finds the token, it continues, if does not, it stops and logs a message to a text file.
  • It parses the token out of the comments.
  • It starts to process the file.
    • Gets the name of the file using the SSCM_FILE environment variable.
    • Gets the full path of the temporary file using the SSCM_LOCALFILE environment variable.
    • Copies the temporary file to another directory.
    • Renames the temporary file to the file name retrieved from the SSCM_FILE variable.
NOTE: The temporary file does not have the same name as the file it represents in Surround SCM. The file will have a .tmp extension.
  • The e-mail is built.
  • The renamed file is attached to the e-mail.
  • The e-mail is sent. If it fails, it logs the error.
  • It resets the "E-mail?" custom field to not checked.
  • It changes the state of the file to "In Review".

How it looks

This is how the process would look like: 1. First, the user would check out the file and make some changes. In this example, I check out a file called "Program.cs" from a mainline branch called "WysiCorp" and a repository called "WysiCorp/WysiCM/WysiCM". 2. After saving my changes, I right click on the file in Surround SCM and select "State" > "E-mail File for Review".

Figure 1: File state change

3. In the state change comments dialog, I enter the e-mail address in the format that the script is expecting.

Figure 2: File state change dialog

3. After a few seconds, the file state is set to "In Review". The file still has a status of "modified", which means it has not been checked in.

Figure 3: File state in review

4. I check my inbox and I have the e-mail. Figure below shows what the e-mail looks like.

Figure 4: Sample e-mail

I then download the attachment and open it. The change I made that I have not checked in yet is in this file.

Possible Enhancements

Since this is something I wrote on the side, I did not get very sophisticated. There are some enhancements that could be done but would require more time. Smarter parsing logic The way the script is currently written, it expects the token to be at the beginning of the comments for parsing out the e-mail addresses. If you include the token at the end of the comments, and there are any "<" or ">" characters before the token, the script will not properly parse the e-mail addresses to send the e-mail to. Hard code the addresses Since the e-mails are passed as comments, you could instead have a file on the server with the e-mail address. When you run a command via the CLI, you can pass a file for the comments. Single E-mail with Multiple Files Another idea would be that the script run by the trigger would simply add to a table the file name and the e-mail address to send the file to. Then, another script that would run in the background would check this table every so often. It would then build a single e-mail for each recipient and include all of the files associated with this recipient. Dynamic E-mail Subject and Body The token could be expanded to also include a subject and body of the e-mail. This would be included in the comments.

Disclaimer

This script is provided as is with no guarantees. This is a script that I wrote in my own time as a side project. This is meant to show how triggers can be used to attach a local file to an e-mail from Surround SCM. The ability to attach a local file to an e-mail and send it from Surround SCM in is not a native feature of the application. Seapine Software Technical support can not provide any support or assistance in the deployment of this script. Seapine's Services department would be happy to provide you with a quote to deploy something similar in your environment.