65.9K
CodeProject 正在变化。 阅读更多。
Home

连接 Visual SourceSafe 2005 和 Bugzilla

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2010年1月4日

CPOL

5分钟阅读

viewsIcon

26924

downloadIcon

355

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 服务接口。

使用代码

该插件由以下部分组成:

  • IVSSEventHandlerIVSSEvents 派生的主类
  • 用于输入错误条目的小型窗体
  • 一个非常简单的 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 库建立连接。根据是提交新文件还是检查现有文件的更改,从 localSpecvssItem 对象中检索项目路径,并将注释提交到给定的错误 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 进行了测试。

安装

  1. CookComputing.XmlRpcV2.dllbugzproxy.dllVSSBugzillaPlugin.dllVSSBugzillaPlugin.ini 复制到 VSS 2005 安装目录,例如 "C:\\Program Files\Microsoft Visual Sourcesafe"
  2. 通过执行以下命令注册 VSSBugzillaPlugin.dll"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe" "C:\Program Files\Microsoft Visual SourceSafe\VSSBugzillaPlugin.dll"(如果 RegAsm.exe 和插件位于不同位置,请相应调整路径)。
  3. 创建或编辑文件 ssaddin.ini 并添加行 Microsoft.SourceSafe.VSSBugzillaPlugin = 1
  4. 编辑 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 日:第一个版本。
© . All rights reserved.