如何跟踪谁在TFS工作项上发表评论

时间:2009-05-13 20:30:52

标签: tfs tfs-workitem

在处理其他错误跟踪系统中的问题时,可以使用明确标记作者用户名和输入日期的项目添加注释。我正在寻找TFS工作项目中的类似功能。 有这样的功能吗?

我们目前使用的系统允许我们点击热键将当前时间和用户名粘贴到多行文本字段中。所有用户都知道将这些信息粘贴在他们输入的内容之上。虽然这是手动的,但它是可以接受的。例如:

5/1/2009 1:20:00 am - AManagr-
Defered to next version, and here's why...

4/24/2009 1:20:00 am - ADev - 
QA machine had out of date XYZ gizmo component. Here's the convoluted way this can happen... blah blah... This is difficult to fix.

4/22/2009 1:20:00 am - QAGuy - 
I can't save reports to PDF files.

我使用过的其他工具(Mantis可能?)有一个“注释”功能。所以我不能忘记将我的名字写在评论上,或者知道新笔记是否会出现在字段的顶部或底部等等......

手动输入您的姓名和日期/时间不是一个(好)选项。但是,点击一个键或工具栏按钮就可以了。

我不是在寻找将像这样的长形“笔记”分解为多个特定字段的建议。此外,我知道工作项的历史选项卡,但这还不够。谁写了什么以及什么时候需要明确和与文本相同的观点。

更新

想象一下,有几个团队成员正在研究一个问题。它们都向工作项添加信息,每个信息都将更多文本附加到同一个字段。你怎么知道谁添加了什么部分?

“历史记录”日志显示每个用户更改的行,甚至显示字段的更改。但这是在另一个屏幕上,很难在心理上解析它显示的数据。

他们可以“签署”文本的每一部分 - 但如果没有该工具的帮助,这是一种痛苦。

也许Stackoverflows评论功能也是一个很好的例子。

2 个答案:

答案 0 :(得分:3)

是的,你可以。 TFS工作项是可自定义的。没有我想要的版本,但你可以做你想要的。

让我们用以下字段定义来刺破它。 Notes日期和Notes作者是只读的,并从系统中获取其默认值。 Notes字段是HTML,你可以在那里放任何你想要的东西。您可以在TFS Process Editor

中执行此操作
 <FIELD reportable="dimension" type="DateTime" name="Notes Date" refname="System.VSTS.Notes.Date">
    <DEFAULT from="clock" />
    <READONLY not="[Global]\Team Foundation Administrators" />
  </FIELD>
  <FIELD reportable="dimension" type="String" name="Notes Author" refname="System.VSTS.Notes.Author">
    <DEFAULT from="currentuser" />
    <READONLY not="[Global]\Team Foundation Administrators" />
  </FIELD>
  <FIELD type="HTML" name="Notes" refname="System.VSTS.Notes" />
</FIELDS>

当然,您仍需要在表单中添加控件。

您可以尝试的另一件事是只保留Notes字段并注册WorkItemChanged事件并编写Web服务以使用Date和Author更新notes字段。更改BY和更改日期字段将为您提供此信息。您可以通过Brian A. Randell在本文中了解可用事件以及如何订阅它们 - Team Foundation System Event Service

[WebService(Namespace = "http://mynamespace.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class UpdateWorkItem : System.Web.Services.WebService
{
    private static TeamFoundationServer _Tfs;
    private static WorkItemStore _WorkItemStore;

    private static List<WorkItem> _ChangedWorkItems = new List<WorkItem>();

    [SoapDocumentMethod(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", RequestNamespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
    [WebMethod]
    public void Notify(string eventXml, string tfsIdentityXml)
    {

        EventLog.WriteEntry("TFS Services", "Log Started: Notify Webmethod");


        // Load the recieved XML into a XMLDocument
        XmlDocument eventXmlDoc = new XmlDocument();
        eventXmlDoc.LoadXml(eventXml);
        XmlElement eventData = eventXmlDoc.DocumentElement;

        // Validate event data
        if (eventData != null)
        {
            // Get Work Item id from event data
            int id = GetWorkItemId(eventData);

            //EventLog.WriteEntry("TFS Services", String.Format("eventXmlDoc {0}", eventXmlDoc.InnerXml));
            EventLog.WriteEntry("TFS Services", String.Format("Got Id {0}", id));
            string changedby = GetWorkItemChangedBy(eventData);
            EventLog.WriteEntry("TFS Services", String.Format("Got changedby {0}", changedby));
            if (changedby != "TFSSERVICE")
            {
                //Add a 15 second delay in order to make sure all workitems are saved first before starting to update them
                Thread.Sleep(15000);
                EventLog.WriteEntry("TFS Services", "Calling UpdateWorkItemInternal");
                UpdateWorkItemInternal(id);
            }
        }
    }

    private int GetWorkItemId(XmlElement eventData)
    {
        return Convert.ToInt32(eventData.SelectSingleNode("CoreFields/IntegerFields/Field[ReferenceName='System.Id']/NewValue").InnerText);
    }

    private string GetWorkItemChangedBy(XmlElement eventData)
    {
        return Convert.ToString(eventData.SelectSingleNode("CoreFields/StringFields/Field[ReferenceName='System.ChangedBy']/NewValue").InnerText);
    }

    private static void UpdateWorkItemInternal(int id)
    {
        //Connect To TFS Server 
        EventLog.WriteEntry("TFS Services", string.Format("Updating Work Item {0}", id));
        _Tfs = TeamFoundationServerFactory.GetServer("TeamServer");

        _WorkItemStore = (WorkItemStore)_Tfs.GetService(typeof(WorkItemStore));
        WorkItem workItem = _WorkItemStore.GetWorkItem(id);

        switch ((string)workItem.Fields["System.WorkItemType"].Value)
        {
            case "Bug":
                UpdateNotes(workItem);
                break;
            default:
                break;
        }

        foreach (WorkItem item in _ChangedWorkItems)
        {
            if (item.IsDirty)
            {
                foreach (Field field in item.Fields)
                {
                    if (!field.IsValid)
                    {
                        Console.Write("Not valid");
                    }
                }
                EventLog.WriteEntry("TFS Services", string.Format("Saving WorkItem: {0}", item.Id));
                try
                {
                    item.Save();
                }
                catch (Exception ex)
                {
                }
            }
        }

        _ChangedWorkItems.Clear();
    }

    private static void UpdateNotes(WorkItem workItem)
    {
       Field notes = workitem.Fields["System.VSTS.Notes"];
       if (notes != null)
       {
         notes = string.Format("{0} - {1}", workItem.ChangedDate, workItem.ChangedBy);
       } 

       if (workItem.IsDirty)
       {
           if (!_ChangedWorkItems.Contains(workItem))
           {
               _ChangedWorkItems.Add(workItem);
           }
       }
    }
 }

这只是快速而肮脏的,我现有的代码中有一些复制和粘贴,所以请仔细检查以确保我没有引入拼写错误。

答案 1 :(得分:0)

我对“历史记录”标签的问题感到好奇吗?它在灰色栏中包含日期/时间和用户名,并在其下方显示注释。

如果他们没有发表评论,但对工作项进行了其他更改,则会出现一个名为Show Changed Fields的折叠标题。评论总是可见。

<强>更新

您可以创建一个自定义工作项控件,提供您自己的工作项历史视图。

http://msdn.microsoft.com/en-us/library/bb286959.aspx

另见TFS Work Item Tracking Custom Controls