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

TFS WorkItems 的基于原因的状态转换

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1投票)

2017 年 8 月 17 日

CPOL

14分钟阅读

viewsIcon

10061

downloadIcon

57

基于原因的状态转换比当前基于状态的转换提供了更好的可用性和灵活性,因为当前的状态转换将原因的收集置于次要且通常是可选的地位。

基于原因的工作流转换的优点

基于原因的工作流转换能够从产品开发团队捕获更准确的信息,因为 TFS 工作项在团队成员之间交接。尽管 TFS 系统允许用户在确定状态后提供转换的原因,但由于默认原因已预填,因此可能会在不经考虑的情况下被接受。除了提交两个字段而实际上只需要一个字段的可用性问题之外,这还会导致原因字段成为工作流转换信息的不可靠来源。

基于原因的工作流转换提供了更大的灵活性以及对工作项字段更精细的控制和协调。

处于“活动”和“已批准”状态的WorkItem通常AssignedTo软件工程团队的成员。如果软件开发人员需要更多信息才能继续(例如,“需要信息”),则WorkItem应分配给质量保证团队或产品管理团队的成员,通常是WorkItem的创建者。一旦提供了所需信息,WorkItem应重新分配给软件开发人员。但是,这种“提供信息”的转换并不一定意味着WorkItem已完全过渡到“活动”状态。如果您正在衡量进度完整性或日历工作与估算工作量之间的关系(按每个软件开发人员),最好在软件开发人员实际上准备好处理时,让他们接受“提供信息”状态的WorkItem并将其重新分配到“活动”状态(例如,使用“信息已接受”的原因)。

WorkItem被置于RemovedDeleted状态时,您可能希望由产品管理团队、质量保证团队或开发负责人之一来审查WorkItem,具体取决于移除原因。一个可能存在疑问的默认“不是 bug”原因无法用于路由,而一个非默认的原因可以可靠地区分,例如:

  • “按设计工作/需要重新设计”可以被置于“功能请求”状态,并分配给产品干系人进行重构。
  • “重复问题”可以被置于Removed状态,但分配给质量保证部门进行验证,以确保没有忽略任何细微之处,或者可能表明需要更好的培训或协调。
  • “工作未经批准或被拒绝”可以被置于“待定分类”状态,并分配给开发团队负责人或经理进行监督。

作为您的产品开发工作流的设计者,一旦您从以状态为中心的分析转向以原因为中心的分析,原本被忽略的意图或细微差别的意图就可以产生更广泛、更一致的结果。

注意事项

  • 请自行承担风险使用(并可能给您带来不便).
  • 除非您能够将WorkItemType .xml 文件导入到您的托管 TFS 环境中,否则此方法仅适用于本地 TFS 服务器。
  • 本文档仅供参考……尽管您可能不采用基于原因的工作流,但您可能会发现此解决方案的某些部分对其他 TFS 工作流应用程序有用。请略读并跳过熟悉或不相关的内容。
  • 坦率地说,基于原因的 TFS 工作流需要大量的工作和定制。如果现有的工作流中的任何一个能让您的团队满意地运行,请考虑其收益是否值得付出的成本。
  • 强烈建议使用一个TFS 沙盒来测试和调试您的工作流,然后再将其推向您的团队。请注意,不良的脚本和自定义容易导致死胡同和无限循环。

TFSAggregator

TFSAggregator: How it Works

TFS Aggregator(参见 https://tfsaggregator.github.io/)是一个成熟的开源实用程序,它提供了一个服务器端 TFS 扩展,可以在 TFS 应用程序层上针对更改的工作项运行自定义脚本。它可用于比基于原因的状态更改更多的事情,例如时间估算和成本估算汇总,或将字段传播到父工作项,这些内容在本文档中未涵盖。

入门

  1. 在您的本地 TFS 服务器上安装扩展(参见 https://tfsaggregator.github.io/admin/install/)。或者,如果您使用托管的 TFS 服务,请将扩展部署和配置为 Web 应用程序(参见 https://tfsaggregator.github.io/admin/install-webhooks/)。
  2. 温习 TFS Aggregator 的策略和规则(参见 https://tfsaggregator.github.io/using/writing-rules/writing-rules/ 以及在线文档的用户指南中的其他页面)。
  3. 如果您有本地 TFS 服务器,请设置一种更方便的方式来收集跟踪和诊断信息(参见 https://tfsaggregator.github.io/using/scripting-tricks-n-tips/scripting-tricks-n-tips/#trace-your-steps)。如果您使用托管 TFS,这可能是设置本地 TFS 服务器作为您解决方案调试和测试沙盒的好理由。

TFS Aggregator 作为插件安装到 TFS 应用程序池。请检查您的 IIS 配置,或搜索 TFSAggregator2.ServerPlugin.policies 文件的位置。在我的 TFS2013 系统上,它位于 C:\Program Files\Microsoft Team Foundation Server 12.0\Application Tier\Web Services\bin\Plugins。要加载对该文件所做的任何更改,您需要“回收”TFS 应用程序池,可以从 IIS 管理器(如上所示)或使用 appcmd recycle apppool /apppool.name: string 命令从命令行进行操作。

--关于 TFSAgregator 策略编辑的更多内容将在下方 --

主要状态

每个主要状态代表一个WorkItem的队列,这些WorkItem要么被暂停,要么需要关注。如果您使用 SCRUM 流程,那么WorkItem会被暂停在“Backlog”中,并在 Sprint 规划会议期间被提取出来并变为“Approved”或“Active”。如果您有一个分类流程(如上所示),那么通常团队领导会定期开会来“批准”并确定WorkItem的优先级或将其暂停。为了团队高效工作,这些主要状态代表了更广泛的团队劳动分工。每个团队成员查看他们自己分配的WorkItem,努力将它们从自己的队列中移出并转到下一个。

TFS 提供了字段和流程约束的丰富交互,以支持这些WorkItem的主要状态转换,其定义如下:https://msdn.microsoft.com/en-us/library/cc339553(v=vs.90).aspx。如果您还不熟悉WorkItemType架构,现在可能值得您花时间将您的WorkItemTypes从 TFS 导出(见下文)以查看您的系统当前正在做什么。

升格到次要状态的原因

将工作流原因升格到次要状态是一种让 TFS 方便地强制用户收集原因的方式。然后,这需要 TFSAggregator(上面)在事后自动将这些次要状态升格为主状态。作为团队工作流的设计者,这种方法存在使工作流状态和工作流转换呈几何级数扩展的缺点。我建议使用设计工具(例如 Visual Studio 的 DGML 图或 Visio 的 UML 状态图)来帮助您理解和分析工作流。DGML 是 Visual Studio 的一个可选模块,因此您可能需要修改已安装的组件才能继续(参见 https://stackoverflow.com/a/43405858/4151626)。这个模块在您的 IDE 中提供了一个图形编辑器,虽然我在 IDE 中以图形方式显示 DGML,但我更喜欢在 XML 中编辑它。这可以通过在 IDE 的 File|Open 对话框中使用“打开方式”->XML 编辑器选项来实现(参见此处的 DGML 架构概述:https://docs.microsoft.com/en-us/visualstudio/modeling/directed-graph-markup-language-dgml-reference)。

第一阶段:捕获和分析现有的 TFS 工作流

引入 witAdmin

背景请参见

如果 witAdmin 工具尚未安装在您的系统上,请安装与您的 TFS 版本相匹配的工具。然后使用 witAdmin 导出项目各种WorkItemTypes的 TFS WorkFlows

#>witadmin.exe exportwitd /?      
Microsoft (R) Work Item Tracking Administration tool.
Copyright (c) Microsoft Corporation. All rights reserved.

Exports the XML definition of a work item type.

Usage: witadmin exportwitd /collection:collectionurl /p:project /n:typename 
       [/f:filename] [/e:encoding] [/exportgloballists] 

 /collection           Specifies the Team Foundation project collection. 
                       Use a fully specified URL such as
                       http://servername:8080/tfs/Collection0.
 /p                    Specifies the name of the team project.
 /n                    Specifies the name of the work item type to export.
 /f                    Specifies the destination file for exporting 
                       the work item type XML. If not specified, the XML is output to
                       the display.
 /e                    Specifies the name of the .NET Framework 2.0 encoding 
                       used to import the XML file. For example, /e:utf-7
                       will use Unicode (UTF-7) encoding. 
                       Encoding is automatically detected whenever possible. 
                       If the encoding cannot be detected, UTF-8 is used.
 /exportgloballists    Exports the definitions of referenced global lists. 
                       If not specified, global list definitions are omitted.

导出工作WorkItemType.xml文件的可用副本不需要/e:encoding/exportgloballists选项。

提取主要状态

WorkItemType XML 按<FIELDS>部分、<WORKFLOW>部分和<FORM>部分组织。对于基于原因的状态转换,我们只需要关注<WORKFLOW>部分。此部分细分为<STATES>子部分和<TRANSITIONS>子部分。如果您使用 DGML 分析工作流,请为WorkItemType .xml 文件中的每个<STATE>元素在.dgml文件中创建一个<Node>元素。

WorkItemType.xml

<STATES>
  <STATE value="Active">...</STATE>
  <STATE value="Approved"/>
  <STATE value="Feature Request">...</STATE>
  <STATE value="Fixed">...</STATE>
  <STATE value="Pending"/>
  <STATE value="Ready to Test">...</STATE>
  <STATE value="Removed">...</STATE>
  <STATE value="TBD">...</STATE>
  <STATE value="Tested">...</STATE>
</STATES>

WorkItemType.dgml

<DirectedGraph GraphDirection="LeftToRight" Layout="Sugiyama" 
 ZoomLevel="1.25" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
  <Nodes>
    <!--Primary 'Work Queue' STATES-->
    <Node Id="New" Label="" NodeRadius="50"/>
    <Node Id="TBD" Group="Expanded"/>
    <Node Id="Feature Request" Group="Expanded" 
          StrokeThickness="4" StrokeDashArray="3 2"/>
    <Node Id="Removed" Group="Expanded" StrokeThickness="4"/>
    <Node Id="Approved" Group="Expanded"/>
    <Node Id="Active" Group="Expanded"/>
    <Node Id="Fixed" Group="Expanded"/>
    <Node Id="Ready to Test" Group="Expanded"/>
    <Node Id="Pending" Group="Expanded"/>
    <Node Id="Tested" Group="Expanded" StrokeThickness="4"/>
  </Nodes>
</DirectedGraph>

在上面的 DGML 中,我添加了 TFS 隐藏的 New 或 "" <STATE>,用于新创建的工作项,并在<TRANSITIONS>部分后续显示。我还添加了 DGML 装饰属性来修改“New”节点的显示形状(例如NodeRadious="50")以及各种“暂停”节点的显示边框粗细和图案(例如StrokeThickness="4"StrokeDashArray="3 2")。我使用粗边框来区分“暂停”状态和“活动”状态。最后,为将来的分析做准备,我已将每个主要状态转换为 DGML 中的分层节点,并使用了Group="Expanded"属性。

提取转换和原因

WorkItemType XML 的<TRANSITIONS>部分详细介绍了您当前工作流允许的所有STATE转换。

WorkItemType.xml

<TRANSITION from="Active" to="Removed">
  <REASONS>
    <DEFAULTREASON value="Insufficient Priority and/or Inconvenience to User" />
    <REASON value="Duplicate" />
    <REASON value="Unapproved for work" />
  </REASONS>
</TRANSITION>

WorkItemType.dgml

<DirectedGraph GraphDirection="LeftToRight" Layout="Sugiyama" 
 ZoomLevel="1.25" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
  <Links>
    <Link Source="Active" Target="Removed" Index="1" 
     Label="Insufficient Priority and/or Inconvenience to User"/>
    <Link Source="Active" Target="Removed" 
        Index="2" Label="Duplicate"/>
    <Link Source="Active" Target="Removed" 
        Index="3" Label="Unapproved for work"/>
  </Links>
</DirectedGraph>

对于每个<TRANSITION>元素,在 DGML 文件中创建相应的<Link>元素,为 XML 文件中的每个<REASON>子元素创建一个。DGML 中的Index属性告诉显示引擎不要折叠冗余链接。

审查和完善

捕获完所有工作流<REASONS>作为 DGML <Link>后,您现在可以通过使用 Visual Studio IDE 中的默认图形编辑器打开.dgml文件来查看和分析您团队的当前工作流。图形编辑器允许您重新定位和重新排序节点,还可以将 DGML 图的图像复制到计算机剪贴板(如果您想继续编辑 XML,请不要保存您的图形编辑)。即使您不实现此处提倡的完整基于原因的转换,您也可以通过根据需要修改WorkItemType.xml文件来对现有工作流进行直接的改进。

导入当前工作流改进(如有)

无论您是继续进行<REASON>到次要<STATE>的提升,还是不进行,都可以根据您的分析结果对当前工作流进行微调。您可以添加原因,更改字段约束,甚至预填充许多WorkItem字段,所有这些都通过导入修改后的WorkItemType.xml文件来实现。

#>witadmin.exe importwitd /?      
Microsoft (R) Work Item Tracking Administration tool.
Copyright (c) Microsoft Corporation. All rights reserved.

This command imports a work item type XML definition file into a team project 
on a Team Foundation Server. 
If a work item type with the same name already exists, 
the new work item type definition will overwrite the existing definition. 
If the work item type does not already exist, a new work item type will be created.

Usage: witadmin importwitd /collection:collectionurl 
       [/p:project] /f:filename [/e:encoding] [/v] 

 /collection    Specifies the Team Foundation project collection. 
                Use a fully specified URL such as
                http://servername:8080/tfs/Collection0.
 /p             Specifies the team project in which the new work item type 
                is imported.  This is required, except when the
                validation-only option is used.
 /f             Specifies the work item type XML definition file to import.
 /e             Specifies the name of the .NET Framework 2.0 encoding 
                used to import the XML file. For example, /e:utf-7 will use
                Unicode (UTF-7) encoding. Encoding is automatically detected 
                whenever possible. If the encoding cannot be detected,
                UTF-8 is used.
 /v             Validates the XML definitions for the work item type, 
                link type, or global workflow without importing them.

虽然不在本文档的范围内,但以下参考信息可能有助于您完善现有工作流

第二阶段:精简/反向分析,为升格原因到次要状态做准备

取决于您选择实现多少个过渡原因,您的第一阶段 DGML 图可能会很快变得难以管理。解决方案是认识到原因会围绕它们的目的状态聚集。此外,将其反向导入 DGML 分层结构,通过将外部原因转换群集包含到内部原因节点中,大大简化了图形。这还为 DGML 的结构奠定了基础,以匹配将来的WorkItemType XML。我将通过示例来展示这一点,因为过渡原因(现在是<Link>元素)成为次要状态(DGML 中的<Node>元素,以及将来WorkItemType.xml文件中的<STATE>元素),并伴随新的支持性 DGML <Link>元素。

将 DGML 原因<Link>元素升格为<Node>元素

WorkItemType.dgml (之前)

<DirectedGraph GraphDirection="LeftToRight" Layout="Sugiyama" 
 ZoomLevel="1.25" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
  <Nodes>...</Nodes>
  <Links>
    <Link Source="Active" Target="Removed" Index="1" 
     Label="Insufficient Priority and/or Inconvenience to User"/>
    ...
  </Links>
</DirectedGraph>

WorkItemType.dgml (之后)

<DirectedGraph GraphDirection="LeftToRight" Layout="Sugiyama" 
 ZoomLevel="1.25" xmlns="http://schemas.microsoft.com/vs/2009/dgml">
  <Nodes>
    ...
    <!--Secondary 'Reason' STATES-->
    <Node Id="Insufficient Priority and/or Inconvenience to User" 
     NodeRadius="12" Stroke="#FFCF1F1F" StrokeDashArray="2 3"/>
    ...
  </Nodess>
  <Links>
    ...
    <!--Each Primary STATE 'Contains' the reasons that cause TRANSITIONs to it.-->

    <Link Source="Removed" Target="Insufficient Priority 
     and/or Inconvenience to User" Category="Contains"/>
    <Link Target="Removed" Source="Insufficient Priority 
     and/or Inconvenience to User" Stroke="#FFCF1F1F" StrokeDashArray="2 3"/>
    ...
    <!--TRANSITIONS from Primary STATES to Secondary 'Reason' STATES-->

    <Link Source="Active" Target="Insufficient Priority 
     and/or Inconvenience to User" Stroke="#FF1FCF1F" StrokeThickness="3"/>
    ...
  </Links>
</DirectedGraph>
  1. (上面第 15 行)每个原因<Link>变成一个<Node>Label属性升格为Id属性,并移除SourceTarget属性。我添加了NodeRadiusStrokeStrokeDashArray装饰属性,以帮助在视觉上区分这些次要原因状态和主要状态。
  2. (上面第 22 行)在<Links>部分,新的次要“Reason”状态的每个主要目标都必须通过 DGML Category="Contains"属性在一个重载的、反向定向的<Link>元素中层级包含新的次要原因<Node>
  3. (上面第 23 行)为了视觉上的对称性,我更倾向于创建从次要原因<Node>到目标主要“Work Queue”<Node>的有向链接,并伴随其包含关系。请注意,我颠倒了SourceTarget属性的顺序以实现视觉一致性,并添加了不同的StrokeStrokeDashArray属性以在后续分析中进行视觉区分。
  4. (上面第 27 行)最后,主要状态可以链接到插入的次要原因状态。同样,添加了StrokeStrokeDashArray属性以在后续分析中进行视觉区分。

深入审查和完善

我在文章顶部发布了我的完整 DGML 文件供您下载、审查和操作。您可以将我的作为示例,但您团队的流程应占主导地位,并且可能与我的不同。将精简/反向 DGML 加载到 Visual Studio 图形编辑器中,您可以重新定位主要状态以获得更好的视觉清晰度。

Stroke 等装饰属性,尤其在选择节点时起作用。选择一个主要状态将突出显示到每个次要原因过渡状态的<Link>或未来的<TRANSITION>

同样,由于 Stroke 等属性,选择一个次要原因过渡状态将突出显示从主要状态到所选次要状态的每个路径。

在您逐步分析转换和工作流时,请使用这些选择高亮。根据需要进行细化和审查,因为此设计阶段比后续实现阶段更具灵活性。

第三阶段:服务器端策略编辑

<?xml version="1.0" encoding="utf-8"?>
<AggregatorConfiguration>
  <runtime debug="false">
    <rateLimiting interval="00:00:01.0" changes="5" />
    <logging level="Normal" />
    <script language="C#" />
    <authentication autoImpersonate="false" />
  </runtime>
  <rule name="AdvanceByReason" hasFields="System.State">
    <![CDATA[
      string currentstate = (string)self["System.State"];
      logger.Log(LogLevel.Verbose, "AdvanceByReason considering {1} #{0} 
      with State of '{2}'.", self.Id, self.TypeName, currentstate); 
      if (!string.IsNullOrWhiteSpace(currentstate) && currentstate.Contains("->"))
      {
        string newstate = currentstate.Remove(0, currentstate.LastIndexOf("->") + 2);
        if (!string.IsNullOrWhiteSpace(newstate))
        {
          self.TransitionToState(newstate, "Seems reasonable,");
          logger.Log(LogLevel.Normal, "AdvanceByReason of {1} #{0} 
          to State of '{2}'.", self.Id, self.TypeName, newstate);
        }
      }
    ]]>
  </rule>
  <policy name="YourPolicies">
    <collectionScope collections="YourCollection" />
    <templateScope/>
    <projectScope projects="YourProject(s)" />
    <ruleRef name="AdvanceByReason" />
  </policy>
</AggregatorConfiguration>

TFSAggregator附带示例策略文件,以及一个空的主策略文件。请参阅 https://tfsaggregator.github.io/using/writing-rules/writing-rules/ 和用户指南中的其他页面以获取更多指导。上面是我使用的主要策略文件的精简版本(已移除注释)。我发现并非所有 C# 原始类型都能在我的 TFS2013 系统上正常工作,甚至一些文档和示例中显示的脚本在测试时也会失败。因此,我建议您逐步编写和测试。

  • (第 11 行)我无法在没有脚本错误的情况下编写null检查(例如, (string)(self["System.State"] ?? "")),而是使用了本地变量。
  • (第 13 行)我采用了通用、开放式的方法来提升次要状态;即使用“->”作为分隔符来编码提升。您可以选择实现更严格的方法。
  • (第 18 行)self.TransitionToState()是一个 TFS 服务器端 API,它可以在可能的情况下将工作项(“self”)推进到指定状态(稍后将详细介绍)。

在您验证了您的策略脚本能够有效运行,没有错误,也没有无限循环(参见 https://tfsaggregator.github.io/using/scripting-pitfalls/)之前。请在导入完整解决方案之前,从下一节实现并验证单个基于原因的转换。

第四阶段:最终实现

TFS/TFSAggregator 约束

从次要状态到主要状态的状态更改不应不受限制(即,没有<FIELDS>元素)。

由于服务器是更改的代理,而不是用户;因此不能提示用户提供未提供的字段。此外,被阻止或未指定的转换将不会发生,WorkItem将卡在一个未被监视的次要状态。这是通过将 TFS 工作流约束(或<FIELDS>元素)从主要状态<TRANSITION>元素迁移到次要状态<TRANSITION>元素来实现的,如下所述。

TFS<TRANSITION>必须提供<DEFAULTREASON>

另一个会阻止 TFS 状态转换的因素是缺少System.Reason字段的指定值。最好确保每个自动的次要到主要状态转换都指定一个可用的<DEFAULTREASON>

TFS 需要一个单一<TRANSITION from="" 到您的初始主要状态,用于新创建的工作项。

总的来说,您可以将这个初始<TRANSITON from="" ...>元素保持不变。

将次要状态添加到 TFS 工作流;迁移流程中的 TFS 约束

WorkItemType.xml (之前)

<WORKFLOW>
  <STATES>
    ...
    <STATE value="TBD"/>
      <FIELDS>
        <FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.CMMI.Blocked">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ClosedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ClosedDate">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Scheduling.Effort">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Scheduling.RemainingWork">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ResolvedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ResolvedDate">
          <EMPTY />
        </FIELD>
      </FIELDS>
    </STATE>
    ...
  </STATES>
</WORKFLOW>

WorkItemType.xml (之后)

<WORKFLOW>
  <STATES>
    <!--Primary 'Work Queue' States-->
    ...
    <STATE value="TBD"/>
    ...

    <!--Secondary 'Reason' States-->
    ...
    <STATE value="failed regression->TBD">
      <FIELDS>
        <FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.CMMI.Blocked">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ClosedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ClosedDate">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Scheduling.Effort">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Scheduling.RemainingWork">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ResolvedBy">
          <EMPTY />
        </FIELD>
        <FIELD refname="Microsoft.VSTS.Common.ResolvedDate">
          <EMPTY />
        </FIELD>
      </FIELDS>
    </STATE>
    ...
  </STATES>
</WORKFLOW>

遵循您的 DGML 设计的大纲,创建次要原因状态,并将 TFS<FIELD>约束从主要状态迁移到每个前驱次要状态。现在或在第二次验证基本功能后(参见 https://msdn.microsoft.com/en-us/library/aa337626(v=vs.90).aspx)可以添加或删除其他字段约束。

插入次要“基于原因”的状态转换

WorkItemType.xml (之前)

<WORKFLOW>
  ...
  <TRANSITIONS>
    ...
    <TRANSITION from="Tested" to="TBD">
      <REASONS>
        <DEFAULTREASON value="Regression Failure." />
        <REASON value="Needs reevaluation and research." />
      </REASONS>
      <FIELDS>
        <FIELD refname="System.AssignedTo">
          <COPY from="field" field="Microsoft.VSTS.Common.ResolvedBy" />
        </FIELD>
      </FIELDS>
    </TRANSITION>
    ...
  </TRANSITIONS>
</WORKFLOW>

WorkItemType.xml (之后)

<WORKFLOW>
  ...
  <TRANSITIONS>
    ...
    <!--Primary to Secondary State Transitions-->
    ...
    <TRANSITION from="Tested" to="failed regression->TBD">
      <REASONS>
        <DEFAULTREASON value="Regression Failure" />
      </REASONS>
      <FIELDS>
        <FIELD refname="System.AssignedTo">
          <COPY from="field" field="Microsoft.VSTS.Common.ResolvedBy" />
        </FIELD>
      </FIELDS>
    </TRANSITION>
    ...

    <!--Secondary to Primary State Transitions-->
    ...
    <TRANSITION from="failed regression->TBD" to="TBD">
      <REASONS>
        <DEFAULTREASON value="Regression Failure" />
      </REASONS>
    </TRANSITION>
    ...
  </TRANSITIONS>
</WORKFLOW>

同样,遵循您的 DGML 设计,从每个主要状态到每个次要状态创建一个<TRANSITION>,复制来自相应前一个目的<TRANSITION><FIELD>约束。您可能需要保留主要到主要的<TRANSITION>,以便复制;直到完成所有插入后才删除它们。

然后创建简化的(仅<DEFAULTREASON>)次要到主要<TRANSITION>元素。

在您的 TFS 沙盒中对工作流进行验证后,将其部署给您的团队并根据需要进行细化。

历史

  • 2017 年 8 月 17 日 - 初始提交
© . All rights reserved.