This server side plugin for TFS 2010/2012 enables dynamic calculation of field values in TFS. (For example: Dev work + Test Work = Total Work). It supports same work item and parent-child links. It also has support for aggregating string values (ie Children are Done so the parent is Done).

Because this is a server side plug-in, it is very fast. The very first aggregation takes about 7-10 seconds (as it caches connection information). After that updates usually take place faster than you can refresh your client.

Example Uses

  • Update the state of a Bug, PBI (or any parent) to "In Progress" when a child gets moved to "In Progress"
  • Update the state of a Bug, PBI (or any parent) to "Done" when all children get moved to "Done" or "Removed"
  • Update the "Work Remaining" on a Bug, PBI, etc with the sum of all the Task's "Work Remaining".
  • Update the "Work Remaining" on a Sprint with the sum of all the "Work Remaining" of its grandchildren (i.e. tasks of the PBIs and Bugs in the Sprint).
  • Sum up totals on a single work item (ie Dev Estimate + Test Estimate = Total Estimate)

Setup

  1. Download and extract the binaries from the latest release
  2. Open up AggregatorItems.xml and change the example settings to your actual settings.
    • See AggregatorItems.xml Options below to find out how to correctly customize your AggregatorItems.xml file to fit your needs.

Installation

  1. Copy TFSAggregator.dll and AggregatorItems.xml to the plugin location on the Application Tier of your TFS Server
    • The plugin folder is usually at this path: C:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin\Plugins

That is all. TFS will detect that a file was copied in and will load it in.

Troubleshooting


AggregatorItems.xml Options

<?xml version="1.0" encoding="utf-8"?> 
This is the basic beginning to an xml file. Do not change it.

<AggregatorItems tfsServerUrl="http://vsalm:8080/tfs/FabrikamFiberCollection"  username="Adminstrator" password="P2ssw0rd" loggingVerbosity="Diagnostic" >
AggregatorItems: The main node for all the configuration options. (Single)
tfsServerURL: This is the URL for your TFS Server. (Required)
username: This is the username for TFS Aggregator to use with your TFS Server. (Optional)
password: This is the password for TFS Aggregator to use with your TFS Server. (Optional)
loggingVerbosity: The level of logging that will be sent to DebugView. Valid values are Normal and Diagnostic. Normal will show only exception messages, Diagnostic will show complete logging. The default value is Normal. (Optional) - Requires TFS 2012 beta version or higher. See the Help page for more info: TFS Aggregator Troubleshooting
<AggregatorItem name="SumTaskEstimatesToParent" operationType="Numeric" operation="Sum" linkType="Parent" linkLevel="2" workItemType="Task">
AggregatorItem: Represents a single aggregation rule. (Repeatable)
name: The name of this aggregation. Used to differentiate aggregations in the Debug Log. (Optional) - Requires TFS 2012 beta version or higher. See the Help page for more info: TFS Aggregator Troubleshooting
operationType: Indicates if the aggregation will be performing "math" or aggregating mapped text values. Valid options are: Numeric or String. (Default is Numeric) If Numeric is specified, then your field type must be a numeric type (ie double or integer).
operation: Indicates what mathematical operation will be performed for the aggregation. Only used if operationType is Numeric. Valid options are: Sum, Subtract, Multiply or Divide. (Default is Sum)
linkType: Indicates if the target for this aggregation is the same as the source or if it is a parent of the source. Valid options are: Self or Parent (Default is Self)
linkLevel: If linkType is Parent then linkLevel indicates how many "parents" up to go. (So linkLevel="2" will find the "grandparent" of the source for the aggregation.) (Default is 1)
workItemType: The name of the work item type that this aggregation will target. (Required)
<TargetItem name="Total Estimate"/>
TargetItem: Represents the TFS Field to be updated in the aggregation. (Single)
name: The TFS field name* of the location to write the aggregation.
<SourceItem name="Estimated Dev Work"/>
SourceItem: Represents a TFS Field to pull data from for an aggregation. (Repeatable)
name: The TFS field name* of the location to pull data from for the aggregation.
<Conditions>
Conditions: Represents a list of conditions, of which if any are false will block the aggregation from happening. If all are true then the aggregation will run (Single, Optional)
<Condition leftField="Finish Date" operator="GreaterThan" rightValue="$NOW$"/>
Condition: Represents a single condition in a list of conditions. Note: if this is incorrectly entered then it will default to true (meaning the condition will pass). (Repeatable)
leftField: The TFS field name* to use as the left value of a condition. This taken from the Target Work Item (Required)
operator: The comparison operator to use for this condition. If the type of the TFS Field (leftField) is String then EqualTo will be used regardless of what is entered. Valid options are: LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo. EqualTo, NotEqualTo (Default is EqualTo)
rightValue: Value to compare the leftField to. If this is set to $NOW$ then the current date time will be entered. If it is set to $NULL$ then null will be used. (Either rightValue or rightField is required)
rightField: the TFS field name* to use as the right value. This taken from the Target Work Item. Will be compared to the left value. Not used if rightValue is specified.
<Mappings>
Mappings: Represents a list mappings to allow string aggregations. (Optional)
<Mapping targetValue="Done" inclusive="And">
Mapping: Represents a single mapping possibility for an aggregation. If satisfied then the mapping will result in the TargetItem for the AggregatorItem being set to the mapping's targetValue (Repeatable)
targetValue: The actual value that the TargetItem of the AggregatorItem will be set to if the mapping is satisfied. (Required)
inclusive: This decides the inclusivity or exclusivity of the mapping. Used to decide if all (And) or just one (Or) of the source values have to be met to cause a mapping to be valid. Valid options are: And or Or (Default is And)
<SourceValue>Removed</SourceValue>
SourceValue: Represents a possible value for the mapping. If the AggregatorItem SourceItem's value is listed as a SourceValue then the mapping will have a match on that work item. (Repeatable)
*Note this is not the refname attribute on a TFS Field. It is the name attribute.) So for <FIELD name="State" refname="System.State" type="String" /> you would enter State NOT System.State.)

Example Aggregations

<!--Add up the estimated work on the task-->
<AggregatorItem operationType="Numeric" operation="Sum" linkType="Self" workItemType="Task">
	<TargetItem name="Estimated Work"/>
	<SourceItem name="Estimated Dev Work"/>
	<SourceItem name="Estimated Test Work"/>
</AggregatorItem>
This aggregation will total the values found in the Estimated Dev Work and Estimated Test Work fields for any Task work item. The total will be placed in the Estimated Work field on the same work item as the source values were found.
<!--Add the time from the task up to the parent (Bug or PBI)-->
<AggregatorItem operation="Sum" linkType="Parent" linkLevel="1" workItemType="Task">
  <TargetItem name="Total Estimate"/>
  <SourceItem name="Estimated Dev Work"/>
  <SourceItem name="Estimated Test Work"/>
</AggregatorItem>
This aggregation will total the values found in the Estimated Dev Work and Estimated Test Work fields for all Task work items on the parent.. The total will go in the Total Estimate field on the parent one level up from the Task (ie the direct parent). In the Microsoft Visual Studio Scrum template that is always a Bug or Product Backlog Item.
<!--Get the total of estimated work on the Sprint-->
<AggregatorItem operationType="Numeric" operation="Sum" linkType="Parent" linkLevel="2" workItemType="Task">
  <Conditions>
    <Condition leftField="Finish Date" operator="GreaterThan" rightValue="$NOW$"/>
  </Conditions>
  <TargetItem name="Total Estimate"/>
  <SourceItem name="Estimated Dev Work"/>
  <SourceItem name="Estimated Test Work"/>
</AggregatorItem>
In this aggregation a condition is added. The condition is that the field Finish Date has to be greater than the current date time on the target work item (meaning in the future). As long as that is true then the aggregation will happen. (The idea is that, after the sprint is over, if we move tasks from this sprint to the next, we don't want to lose the estimates that are saved on the work item.)
The Target Work Item is the second level parent of a task. In many templates this would be the Sprint (or some other iteration like) work item. That means that we only want to do this update if the sprint is not over. If it is not over then this aggregation will total all values found in the Estimated Dev Work and Estimated Test Work fields for all the tasks in the sprint and Total Estimate on the sprint.
  <!--When all Tasks are done being worked on set the parent (Bug or PBI) to Done (unless it is Removed)-->
  <AggregatorItem operationType="String" linkType="Parent" linkLevel="1" workItemType="Task">
    <Mappings>      
      <Mapping targetValue="Done" inclusive="And">
        <SourceValue>Removed</SourceValue>
        <SourceValue>Done</SourceValue>
      </Mapping>
    </Mappings>
    <Conditions>
      <Condition leftField="State" operator="NotEqualTo" rightValue="Removed"/>
    </Conditions>
    <TargetItem name="State"/>
    <SourceItem name="State"/>
  </AggregatorItem>

<!--When any Tasks are In Progress set the parent (Bug or PBI) to In Progress-->
<AggregatorItem operationType="String" linkType="Parent" linkLevel="1" workItemType="Task">
  <Mappings>
    <Mapping targetValue="In Progress" inclusive="Or">
      <SourceValue>In Progress</SourceValue>
      <SourceValue>Ready For Test</SourceValue>
    </Mapping>
  </Mappings>
  <TargetItem name="State"/>
  <SourceItem name="State"/>
</AggregatorItem>
</AggregatorItems>
These are two very similar aggregations. Both target the parent of a task. They are both targeting the state of the parent. For the first aggregation the state of all the tasks on the parent must be either Removed or Done. Also the parent must not be in the state of Removed. If these things all checkout then the State of the parent will be set to done. (If not nothing is done). For the second aggregation if any of the tasks on the parent are set to In Progress or Ready For Test then the parent will have its state set to In Progress. (The inclusive attribute is what makes the big difference here).
Note on States: TFS has controls setup on State Transitions. Most templates do not allow you to go directly from a New state to a Done state. TFS Aggregator will cycle the target work item through what ever states it needs to to find the shortest route to the target state. (For most templates that is also the route that makes the most sense from a business perspective too.)

Future Features

These are a list of features I would like to see in TFS Aggregator. I don't really need them so they have not made the cut yet. If this turns out to be a tool that others use and they vote for some of the items below then they may get added at some point.
  • Parent To Child Aggregations.
    • This would be useful so that when a work item (ie PBI/Bug) gets its iteration changed then the TFS Aggregator could change the children to that iteration too.
  • Make an editor for the options file.
  • More than one type allowed in workItemType on AggregatorItem.
  • More support for conditions (allowing differentials). For example having Today - 5 days.
  • Find a way to filter out repeat messages without having to re-do the aggregation.
    • A successful aggregations makes changes. That causes the aggregation code to fire again. The second time through it sees that no changes need to be made (because the totals are already right). But it would be nice to have a way to see that up front and not do it again.

Last edited Jun 20, 2013 at 6:50 PM by sstjean, version 80