连接 Visual SourceSafe 2005 和 Bugzilla





5.00/5 (1投票)
Visual SourceSafe 2005 的一个插件,允许在提交更改时将注释附加到 Bugzilla 错误条目。
引言
如今,将源代码存储库与其他系统连接起来并非不常见;例如,在提交更改时,可以将注释附加到错误条目,列出更改或添加的文件以及开发人员附加的注释。开源错误跟踪工具 Bugzilla 支持与多种 SCM 系统的集成,并且市面上有许多提供 VSS 集成的缺陷跟踪系统。通过使用 VSS 自动化接口、Bugzilla 的通用接口以及 Bugzilla 工具本身,本文将描述如何以及以何种方式将 VSS 2005 与 Bugzilla 集成。
背景
Bugzilla 和 SCM 集成
通过使用集成守护进程 scmbug,Bugzilla 可以与 CVS 或 Subversion 集成(scmbug 支持多种错误跟踪和源代码管理系统)。但是,集成意味着什么?这意味着,在 Subversion(或 CVS)中提交更改时,可以提供一个错误 ID,并将注释添加到该错误中,其中包括已更改、已添加、已删除的文件列表以及提交时附加的注释。Subversion 中的注释将与 Bugzilla 中相应错误的链接一起添加。在 Subversion 存储库上设置 scmbug 时,会将一些脚本添加到 Subversion 钩子中,这些脚本会实际将注释输入到 Bugzilla 中。Subversion 中的错误 ID 可以通过 Subversion 的 bugtraq 字段(在使用 Tortoise SVN 客户端时)或通过注释中的提示来提供。但目前还没有与 Bugzilla 和 VSS 2005 的此类集成。
Bugzilla 和 Visual SourceSafe 2005
VSS 2005 提供了 SourceSafe 自动化层,这是一组基于 COM 的接口,提供了一种编写 加载项 的机制,这些加载项可以响应特定的 VSS 2005 事件,例如检查前或添加前。这意味着,通过插件响应事件时,可以写入一些到 Bugzilla 的注释条目。对于插件,通过 bugzproxy 库(也需要 xml-rpc.net)连接到 Bugzilla 和修改 Bugzilla 条目,这是一个用 C# 编写的库,它使用 Bugzilla 的 Web 服务接口。
使用代码
该插件由以下部分组成:
- 从
IVSSEventHandler
和IVSSEvents
派生的主类 - 用于输入错误条目的小型窗体
- 一个非常简单的 ini 文件处理程序
- 一个非常简单的日志文件处理程序
主类响应在检查文件之前和添加文件之前触发的事件。根据配置,会显示一个小型对话框来输入错误 ID,或者错误 ID 要从注释中提取。会评估某些选项,例如是否始终需要错误 ID,或者错误 ID 是否可选,或者添加文件时是否也可以/需要输入错误 ID。如果错误 ID 需要从注释中提取,则会使用正则表达式来完成。
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);
}
/// Does all preprocessing: show the bugID dialog or exctract the bugID
/// out of the comment information
private bool ProcessBugInformation(VSSItem vssItem,
string localSpec, string comment, bool isFileAdd)
{
// The dialog is used to enter the BugID
if (iniFile.Sections["Plugin"]["UseBugIDDialog"] == "1")
{
FormEnterBugID form =
new FormEnterBugID(vssItem, localSpec, comment, isFileAdd);
// The dialog to enter the BugID (if shown) is non modal
// so checkin can be aborted, if Bugzilla was not available or
// refused entering a bug id
if (form.ShowDialog() == DialogResult.OK)
{
form = null;
return true;
}
else
{
form = null;
return false;
}
}
else
{
// If not, then, a bug ID might be expected
// at the beginning of a comment
// Try to get the BugID form the comment
Regex BugIDRegExp = new Regex(
iniFile.Sections["Plugin"]["BugIDRegExp"]);
Match bugID = BugIDRegExp.Match(comment);
if (bugID.Value.Length > 0)
{
BOEnterComment bo = new BOEnterComment();
// Exctract the ID only of the previous extracted bugID
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
{
// A Bug ID is required always
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;
}
}
}
实际的注释提交在 BOAppendComment
类中完成。首先,从配置文件中读取 Bugzilla 的连接信息,并通过 bugzproxy 库建立连接。根据是提交新文件还是检查现有文件的更改,从 localSpec
或 vssItem
对象中检索项目路径,并将注释提交到给定的错误 ID。
/// Appends a comment to a given bugzilla bug entry
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"]);
// Path may be undefined - so catch an eventually thrown exception
// and assign the empty string value
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;
//Convert the bugID form text to integer
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
{
// Login
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");
// This statement will throw an exception, if the bug is not valid
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;
}
使用插件
该插件已针对 Bugzilla 3.2.4 进行了测试。
安装
- 将 CookComputing.XmlRpcV2.dll、bugzproxy.dll、VSSBugzillaPlugin.dll 和 VSSBugzillaPlugin.ini 复制到 VSS 2005 安装目录,例如 "C:\\Program Files\Microsoft Visual Sourcesafe"。
- 通过执行以下命令注册 VSSBugzillaPlugin.dll:"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe" "C:\Program Files\Microsoft Visual SourceSafe\VSSBugzillaPlugin.dll"(如果 RegAsm.exe 和插件位于不同位置,请相应调整路径)。
- 创建或编辑文件 ssaddin.ini 并添加行
Microsoft.SourceSafe.VSSBugzillaPlugin = 1
。 - 编辑 VSSBugzillaPlugin.ini 配置文件中的设置(设置将在下面解释)。
配置
本节介绍必须通过 VSSBugzillaPlugin.ini 提供的设置。
Host
- 安装 Bugzilla 的服务器,不包含前面的 http://。Port
- 服务器端口。Path
- 服务器上 Bugzilla 的路径;例如,Bugzilla 可能安装在 http://someserver/bugzilla 下,那么路径必须设置为 bugzilla。User
- Bugzilla 用户名。Pass
- 密码。Logging
- 设置为 1 可打开日志记录;设置 0 可关闭日志记录。LogFilePath
- 日志文件的完整路径,例如 C:\temp\VSSBugzillaPlugin.log。UseBugIDDialog
- 将此变量设置为 1 将显示用于输入错误 ID 的对话框,设置为 0 则要求在注释开头输入错误 ID。AlwaysRequireValidBugID
- 将此变量设置为 1 将要求每次签入都必须提供错误 ID。RequestBugIDWhenAddingFile
- 将此变量设置为 1 将在将文件添加到存储库时启用错误 ID 处理。BugIDRegExp
- 当需要通过注释信息识别错误 ID 时要使用的正则表达式。
限制
使用 Visual SourceSafe 2005 自动化层插件机制与 Bugzilla 结合使用存在两个主要限制。
- 尽管 Visual SourceSafe 2005 实际上知道它正在检查多个文件(通过显示名为“Checkin multiple”的对话框),但在触发
checkin
事件时,它不会将此信息提供给vssItem
。显然,checkin
事件是为每个检查过的项触发的,但没有 proper way 来找出哪些文件属于同一个检查。 - 尽管可以捕获“before...”事件,但无法更改注释或 VSS 项目信息。因此,无法将错误 ID 信息添加到实际的 Visual SourceSafe 2005 提交中。
参考文献
历史
- 2010 年 1 月 4 日:第一个版本。