Click here to Skip to main content
11,718,016 members (82,536 online)
Click here to Skip to main content

SVN Commenter

, 18 Apr 2013 CPOL 9.5K 182 9
Rate this:
Please Sign up or sign in to vote.
Subversion Comment Editor

Introduction 

This program is a simple subversion comment editor that allows you to browse commits and alter the comment left by the committing developer.

Background 

As most companies, we use a ticket logging system to track bugs, issues etc. Our issue tracking system (Jira) has a separate system (Fisheye) that monitors our subversion repositories and then checks the comments to link SVN commits to tickets.

Since we've had SVN before the issue logging system there are some commit comments without ticket numbers, or sometimes a developer just forgets to add the ticket number in the comment. With this we required a way to alter commit comments when needed.

The two SVN technologies used by my company are TortoiseSVN and the VisualSVN server (community / Free edition). 

Now a-days Tortoise SVN ships with the option of installing a command line client. Using it isn't always practical when wanting to update mass comments. Tortoise has the option to edit a log message, but then lacks the ease of browsing for these comments. 



After searching the web I couldn't find one GUI editor that can handle this feat. Hence... SVNCommenter.  

Using the code  

The code will explain two things...  

  • Sending a svn log retrieval command to console 
  • Sending a svn log update command to console 

1. Sending the SVN commands to retrieve log messages from your SVN server / Repositories. 

private void SVNGetRepoLog(string repoURL,string uName,string pWord)
{
    mode = 0;
    consoleOutput = "";
    string cmd = "log";
    string credentials = "";

    if (uName != string.Empty && pWord != string.Empty)
    {
        credentials = string.Format(" --username {0} --password {1}", uName, pWord);
    }

    waitTimer.Enabled = true;
    rtbComment.Text = "";
    revNumber = -1;

    progressBar1.Visible = true;
    Application.DoEvents();

    //Build the SVN command
    cmd = cmd + " " + repoURL + credentials + " --verbose --xml";

    ConsoleReader.RunCommand("svn.exe",cmd ); 
} 

Let's start by first analyzing the SVN command required to retrieve log messages.

The exe required to submit SVN command is 'svn.exe'. This generally ships with TortoiseSVN if you choose the command-line tool during installation. It can generally be found here: (C:\Program Files\TortoiseSVN\bin\svn.exe).

The parameter passed to the 'svn.exe' to retrieve log messages is 'log' followed by the svn repository URL (e.g., svn.exe log http:\\svn.mydomain.com\testPSVNProject).

To include user credentials one appends --username and --password followed by the actual username and password. (e.g., svn.exe log http:\\svn.mydomain.com\testPSVNProject --username admin --password somepw).

For ease of use one can tell the SVN exe that you want the output in xml format. This is achieved by adding the --xml switch. With the --verbose switch svn will also print all the affected paths with each log message, effectively giving us the files affected by the commit. 

Now that we understand the command we can move on to the code.

To ease sending commands to console and waiting for output I created a ConsoleReader class. It has events that let you know when it gets something back from the console. When these events fire I build up the output to a string variable (consoleOutput). 

The ConsoleReader has a OutputChanged event that we expose to build up the consoleOutput variable. 

void ConsoleReader_OutputChanged(string output)
{
    ticker = 0; //Reset the wait timer
    consoleOutput += output + "\n";
}  

A timer checks to see if there is any further output from the console and when no more output is detected it analyzes the consoleOutput variable.   

private void AnalyzeOutput(string output)
{
    switch (mode)
    {
        case 0: //Log reader
           // DisplayLogEntries(output);
            ReadXMLReply(output);
            break;
        case 1: //Comment changing
            if (output.Contains("pre-revprop-change hook"))
            {
                MessageBox.Show(string.Format("SVN msg:\n{0}", output + hookScript));
            }
            else
            {
                rtbStatus.Text = string.Format("SVN msg: {0}", output);
            }
            break;
        default:
            break;
    }

    progressBar1.Visible = false;
    Application.DoEvents();
} 

Based on the mode we can distinguish if the SVN command was a retrieve or a set. 

In mode 0 we expect an xml formatted list of all the projects log messages as well as its modified files. The ReadXMLReply method then converts the response into a DataSet which we can the display to the user.  

private void ReadXMLReply(string output)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);

    if (output.ToLower().Contains("error validating server certificate"))
    {
        MessageBox.Show("Error logging into the SVN server.\nPlease provide a username " + 
          "and password or log into the svn server.\nIf https is used, accept the security certificate permanently.");
    }
    else if (output.ToLower().Contains("error resolving case of") || 
         output.ToLower().Contains("unable to connect to a repository at"))
    {
        rtbStatus.Text = string.Format("SVN msg: {0}", output);
    }
    else //Received data
    {
        writer.Write(output);
        writer.Flush();
        stream.Position = 0;

        xmlDS = new DataSet();
        xmlDS.ReadXml(stream);

        if (xmlDS.Tables.Count > 0)
        {
            DisplayLogEntries();
        }
    }
}

2. Sending the SVN commands to update a log messages to your SVN server / Repositories. 

While sending the SVN update command we change the mode to 1. 

private void SVNChangeComment(string repoURL, int revision, string newComment)
{
    mode = 1;
    consoleOutput = "";

    //Write the Log Message to file
    string commentPath = Application.StartupPath + @"\comment.txt";
    StreamWriter sw = new StreamWriter(commentPath, false, Encoding.ASCII);
    //Write each line to the file as SVN complains about inconsistent line endings
    foreach (string line in newComment.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None))
    {
        sw.WriteLine(line);
    }
    sw.Close();

    //Build The Command to update the log from a file
    string cmd = string.Format("propset --revprop -r {0} svn:log -F \"{1}\" {2}", revision, commentPath, repoURL);

    waitTimer.Enabled = true;
    progressBar1.Visible = true;
    Application.DoEvents();
    //Run the command
    ConsoleReader.RunCommand("svn.exe", cmd);
}

Sending the updated comment makes use of the SVNChangeComment method. Here the comment is written to file and then passed as a parameter to the svn.exe.  

The command used to update a comment is 'propset'. It requires the revision number that it needs to update. For this we pass --revprop -r and the revision number. The propset command requires a second parameter that specifies what must be updated. In this case it's svn:log. The -F parameter is where we specify the file as the comment. Why not just send the comment? For multiline comments, it is very difficult to wrap the comment. By using a file, the svn.exe it handles nextline characters by itself.    

History

This is the first public version. Who knows.. with some good suggestions / improvements there might just be a second or third revision.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Pieter Alec Myburgh
Software Developer (Senior) Process Computing Technology
South Africa South Africa
Senior Software Engineer & Manager.

I reject your code and substitute my own!

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150901.1 | Last Updated 18 Apr 2013
Article Copyright 2013 by Pieter Alec Myburgh
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid