Introduction
Connecting a source code repository with other systems is not uncommon today; e.g., when committing changes, comments can be attached to bug entries, listing the files changed or added with the revision and the comment attached by the developer. The Open Source bug tracking tool Bugzilla supports integration of a variety of SCM systems, and there are many issue tracking systems around that provide VSS integration. With the use of the VSS automation interface, the common interfaces of Bugzilla, and the tool Bugzilla itself, this article describes how and in what manner it is possible to integrate VSS 2005 with Bugzilla.
Background
Bugzilla and SCM integration
By using the integration daemon scmbug, Bugzilla can be integrated with CVS or Subversion (scmbug supports a variety of bug tracking and source code management systems). But, what does integration mean? It means that, when committing a change in Subversion (or CVS), a bug ID can be provided and a comment is added to the bug, containing the list of files changed, added, removed, and the comment attached to the commit. The comment in Subversion gets added with the link to the corresponding bug in Bugzilla. When setting up scmbug on a Subversion repository, some scripts are added to the Subversion hooks that do the actual comment entering to Bugzilla. The bug ID in Subversion can either be provided via Subversion's bugtraq fields (when using Tortoise SVN client) or via a hint in the comment. But there is no such integration with Bugzilla and VSS 2005 yet.
Bugzilla and Visual SourceSafe 2005
VSS 2005 provides the SourceSafe automation layer, a collection of COM based interfaces which provides a mechanism to write add-ins that react on specific VSS 2005 events like before check-in or before add. That means, when reacting on events via the plug-in, some comment entry to Bugzilla can be written. For the plug-in, connection to Bugzilla and modification of Bugzilla entries is done through the bugzproxy library (also requires xml-rpc.net), a library written in C# that uses Bugzilla's Web Service interface:
Using the code
The plug-in consists of the following parts:
- The main class derived from
IVSSEventHandler
and IVSSEvents
- A small form to enter bug entries
- A very simple ini file handler
- A very simple log file handler
The main class reacts on the events that are fired before checking in a file and before adding a file. What happens is, depending on the configuration, either a small dialog is shown to enter the bug ID, or the bug ID is to be extracted from a comment. Certain options are evaluated, whether a bug ID is always required or optional, or whether a bug ID may/need also be entered when adding a file. If the bug ID has to be extracted out of a comment, this will be done using Regular Expressions.
public bool BeforeAdd(VSSItem vssItem, string localSpec, string comment)
{
if (iniFile.Sections["Plugin"]["RequestBugIDWhenAddingFile"] == "1")
{
return ProcessBugInformation(vssItem, localSpec, comment, true);
}
else
return true;
}
public bool BeforeCheckin(VSSItem vssItem, string localSpec, string comment)
{
return ProcessBugInformation(vssItem, localSpec, comment, false);
}
private bool ProcessBugInformation(VSSItem vssItem,
string localSpec, string comment, bool isFileAdd)
{
if (iniFile.Sections["Plugin"]["UseBugIDDialog"] == "1")
{
FormEnterBugID form =
new FormEnterBugID(vssItem, localSpec, comment, isFileAdd);
if (form.ShowDialog() == DialogResult.OK)
{
form = null;
return true;
}
else
{
form = null;
return false;
}
}
else
{
Regex BugIDRegExp = new Regex(
iniFile.Sections["Plugin"]["BugIDRegExp"]);
Match bugID = BugIDRegExp.Match(comment);
if (bugID.Value.Length > 0)
{
BOEnterComment bo = new BOEnterComment();
Regex BugNumber = new Regex("[0-9]*");
Match bugNum = BugNumber.Match(bugID.Value);
if (bo.AppendComment(vssItem, localSpec, comment,
bugNum.Value, isFileAdd))
{
bo = null;
return true;
}
else
{
bo = null;
return false;
}
}
else
{
if (iniFile.Sections["Plugin"]["AlwaysRequireValidBugID"] == "1")
{
LogFileHandler.writeToLogFile(LogSeverity.ERROR,
"No valid Bug ID was provided in the comment");
MessageBox.Show("No valid Bug ID was provided in the comment",
"VSSBugzilla Plugin: Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
else
return true;
}
}
}
The actual comment submission is done within the class BOAppendComment
. First, the connection information for Bugzilla is read from the configuration file, and the connection via the bugzproxy library established. Depending on whether a new file is submitted or a change to an existing file is checked in, the project path is retrieved from either localSpec
or the vssItem
object and the comment submitted to the given bug ID.
public bool AppendComment(VSSItem vssItem, string localSpec,
string comment, string BugID, bool isFileAdd)
{
IniFileHandler iniFile = IniFileHandler.Instance;
string host = String.Empty;
string path = String.Empty;
try
{
host = iniFile.Sections["Bugzilla"]["Host"];
}
catch(Exception e)
{
LogFileHandler.writeToLogFile(LogSeverity.ERROR,
"No host value defined in ini file\n" + e.Message);
MessageBox.Show("No host value defined in ini file",
"VSSBugzilla Plugin: Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
uint port = Convert.ToUInt32(iniFile.Sections["Bugzilla"]["Port"]);
try
{
path = iniFile.Sections["Bugzilla"]["Path"];
}
catch (Exception e)
{
path = String.Empty;
}
string user = iniFile.Sections["Bugzilla"]["User"];
string pass = iniFile.Sections["Bugzilla"]["Pass"];
int bugID;
try
{
bugID = System.Convert.ToInt32(BugID);
}
catch (Exception e)
{
LogFileHandler.writeToLogFile(LogSeverity.ERROR, e.Message);
MessageBox.Show(e.Message, "VSSBugzilla Plugin: Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
Server server = new Server(host, port, path);
try
{
int res = server.Login(user, pass, true);
if (res <= 0)
{
LogFileHandler.writeToLogFile(LogSeverity.ERROR,
"Could not login to " + host + path);
MessageBox.Show("Could not login to " + host + path,
"VSSBugzilla Plugin: Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
LogFileHandler.writeToLogFile(LogSeverity.INFO, "Login to " +
host + path + " with user " + user + " successful");
if (isFileAdd)
server.GetBug(bugID).AppendComment("The following file(s) " +
"has/have been added by a visual source safe commit:\n\n" +
vssItem.Spec + "/" + ExtractFileName(localSpec) +
"\n\nReason:\n" + comment, null, null);
else
server.GetBug(bugID).AppendComment("The following file(s) " +
"has/have been changed by a visual source safe commit:\n\n" +
vssItem.Spec + "\tat Version " +
(vssItem.VersionNumber + 1).ToString() +
"\n\nReason:\n" + comment, null, null);
if (isFileAdd)
LogFileHandler.writeToLogFile(LogSeverity.INFO,
"Comment appended to Bug " + bugID +
" when commiting file " + vssItem.Spec +
"/" + ExtractFileName(localSpec));
else
LogFileHandler.writeToLogFile(LogSeverity.INFO,
"Comment appended to Bug " + bugID +
" when commiting file " + vssItem.Spec +
" at Version " + (vssItem.VersionNumber + 1).ToString());
}
catch (Exception e)
{
LogFileHandler.writeToLogFile(LogSeverity.ERROR, e.Message);
MessageBox.Show(e.Message, "VSSBugzilla Plugin: Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
return true;
}
Using the plug-in
The plug-in has been tested against Bugzilla 3.2.4.
Installation
- Copy CookComputing.XmlRpcV2.dll, bugzproxy.dll, VSSBugzillaPlugin.dll, and VSSBugzillaPlugin.ini into the VSS 2005 installation directory, e.g., "C:\\Program Files\Microsoft Visual Sourcesafe".
- Register VSSBugzillaPlugin.dll issuing the following command: "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe" "C:\Program Files\Microsoft Visual SourceSafe\VSSBugzillaPlugin.dll" (adapt path of RegAsm.exe and plug-in if located in different locations).
- Create or edit the file ssaddin.ini and add the line
Microsoft.SourceSafe.VSSBugzillaPlugin = 1
.
- Edit the settings in the VSSBugzillaPlugin.ini configuration file (the settings are explained below).
Configuration
This section describes the settings that must be provided via VSSBugzillaPlugin.ini.
Host
- The server where Bugzilla is installed, without the leading http://.
Port
- The server port.
Path
- The path to Bugzilla on the server; e.g., Bugzilla may be installed under http://someserver/bugzilla, so the path must be set to bugzilla.
User
- The Bugzilla username.
Pass
- Password.
Logging
- Setting this to 1 turns logging on; 0 turns logging of.
LogFilePath
- The full path to the log file, e.g., C:\temp\VSSBugzillaPlugin.log.
UseBugIDDialog
- Setting this variable to 1 will show the dialog to enter the bug ID, 0 will require the bug ID to be entered at the beginning of a comment.
AlwaysRequireValidBugID
- Setting this variable to 1 will require a bug ID to be given on every check-in.
RequestBugIDWhenAddingFile
- Setting this variable to 1 will turn on bug ID processing when adding files to the repository.
BugIDRegExp
- The Regular Expression that is to be used when bug IDs are to be recognized via comment information.
Limitations
There are two main limitations to using the Visual SourceSafe 2005 Automation layer plug-in mechanism together with Bugzilla.
- Although Visual SourceSafe 2005 actually knows that it is checking in multiple files (by showing a dialog named "Checkin multiple"), it does not provide this information to the
vssItem
when the checkin
event is fired. It is clear that the checkin
event is fired for every item checked in, but there is no proper way to find out which files belong to the same check-in.
- Although the "before..." events are caught, there is no way to change either comment or VSS item information. Therefore, it is not possible to add the bug ID information to the actual Visual SourceSafe 2005 commit.
References
History
- 4th January, 2010: First version.