3

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

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

2009 年 5 月 1 日凌晨 1:20:00 - AManagr-
推迟到下一个版本,这就是为什么...

2009 年 4 月 24 日凌晨 1:20:00 - ADev -
QA 机器的 XYZ Gizmo 组件已过时。这是发生这种情况的复杂方式......等等等等......这很难解决。

2009 年 4 月 22 日上午 1:20:00 - QAGuy -
我无法将报告保存为 PDF 文件。

我用过的其他工具(也许是 Mantis?)有一个“笔记”功能。所以我不能忘记在评论上写上我的名字,或者知道新笔记是放在字段的顶部还是底部,等等。 ..

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

我不是在寻找关于将这样的长格式“笔记”分解为多个特定单独字段的建议。另外,我知道工作项的历史选项卡,但这还不够。谁写了什么,什么时候写的需要清楚,并且与文本的观点相同。

更新

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

历史日志为每个用户的更改显示一行,甚至显示该字段的更改。但那是在另一个屏幕上,很难在精神上解析它显示的数据。

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

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

4

2 回答 2

3

是的你可以。TFS 工作项是可定制的。在这个版本中没有我想要的那么多,但你可以做你想做的事。

让我们使用以下字段定义来尝试一下。Notes Date 和 Notes Author 是只读的,并从系统中获取它们的默认值。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 字段。Changed BY 和 Changed Date 字段将为您提供此信息。您可以在 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);
           }
       }
    }
 }

这只是从我现有的代码中复制和粘贴的快速和肮脏的,所以仔细检查它以确保我没有引入错字。

于 2009-05-13T21:04:49.050 回答
0

我对“历史记录”选项卡的问题感到好奇?它在灰色条中包含日期/时间和用户名,并在其下方立即发表评论。

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

更新

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

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

另请参阅TFS 工作项跟踪自定义控件

于 2009-05-14T02:47:49.433 回答