Tuesday, February 21, 2012

Perforce and diff emails

After working with Subversion, and getting used to the colorful post-commit diff email, I wanted to set up a similar setting in Perforce.
Unfortunately I couldn't find post-commit hooks in Perforce.
So I came up with the following steps to generate the diff on the client side:
  1. Create a "Review" trigger in Perforce for the branches you want to monitor.
    In the visual Perforce client click "Connection" > "Edit current user" > "Reviews" tab, now right click and "Include" every branch you want to be notified about.
    This sends an email about every changelist submitted to Perforce, without specifying the changelist content
  2. Get the jar, or source code, that creates the HTML diff.

    I am aware that there are tools to convert diff 2 HTML, but since my team is using Java (thus they have a JRE), mostly on Windows (so no Python), I wanted a Java convertor.
  3. Use a VBA script in Outlook to convert the triggered email to a diff of the changelist content.
    The script fires up the local Perforce client and uses the command "p4 describe " to create the diff, uses the Java class to convert the diff to HTML and replaces the email body with the HTML diff.
    Open the script below in a text editor:

    Sub P4Diff(MyMail As MailItem)
        Dim strSplit As Variant
        Dim changelist As String
        Dim sOutput As String
        Dim sOutputErr As String
        Dim sP4Cmd As String
        Dim sJavaCmd As String
        Dim sJarPath As String
        Dim sP4Port As String
        Dim sP4User As String
        Dim sP4Password As String
        ' error handling directive
        On Error GoTo errMyErrorHandler
        ' Variables that need to be set per environment
        sP4Cmd = "C:\Progra~1\Perforce\p4.exe"
        sJavaCmd = "C:\Java\jre6\bin\java.exe"
     sJarPath = "C:\SomePath\p4diff.jar"
     sP4Port = "yourperforce:1667"
        sP4User = "youruser"
        sP4Password = "yourpassword"
        ' parse the changelist from the email subject
        strSplit = Split(MyMail.Subject, " ")
        changelist = strSplit(2)
        ' create a shell
        Set wshShell = VBA.CreateObject("WScript.Shell")
        ' set the p4 environment variables
        Set processEnvVars = wshShell.Environment("PROCESS")
        processEnvVars("P4PORT") = sP4Port
        processEnvVars("P4USER") = sP4User
        processEnvVars("P4PASSWD") = sP4Password
        ' execute the diff and wait for it to finish
        Set oExec = wshShell.Exec("%COMSPEC% /c " & sP4Cmd & " describe " & changelist & " | " & sJavaCmd & " -jar " & sJarPath)
        Do While oExec.Status = WshRunning
            If oExec.StdOut.AtEndOfStream = 0 Then
                sOutput = sOutput & oExec.StdOut.ReadLine()
            End If
        If oExec.StdOut.AtEndOfStream = 0 Then
            sOutput = sOutput & oExec.StdOut.ReadLine()
        End If
        ' Read the diff result and set in the email body
        sOutputErr = oExec.StdErr.ReadAll()
        MyMail.HTMLBody = sOutput & sOutputErr
        Exit Sub
      MsgBox Err.Description, _
        vbExclamation + vbOKCancel, _
        "Error: " & CStr(Err.Number)
    End Sub

    Change the script variables to match your environment.

    Install the VBA script:
    1.  In Outlook click "Tools" > "Macro" > "Visual Basic Editor"
    2. Open "ThisOutlookSession"
    3. Paste the edited script from your text editor into the VB editor and save
    4. Close the VBA editor and text editor

    Change the Outlook Macro security so it will be able to run the script

  4. Create a rule in Outlook to run the script when the email subject contains "PERFORCE change".
    For some reason this doesn't work well if you run the script AND move the email to a different folder