forked from Vaccano/TFS-Aggregator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Aggregator.cs
149 lines (135 loc) · 7.2 KB
/
Aggregator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
namespace TFSAggregator
{
public static class Aggregator
{
/// <summary>
/// Used to actually do the aggregating.
/// </summary>
/// <returns>true if a change was made. False if not</returns>
public static bool Aggregate(IEnumerable<WorkItem> sourceWorkItems, WorkItem targetWorkItem, ConfigAggregatorItem configAggregatorItem)
{
if (configAggregatorItem.OperationType == OperationTypeEnum.Numeric)
{
return NumericAggregation(sourceWorkItems, targetWorkItem, configAggregatorItem);
}
else if (configAggregatorItem.OperationType == OperationTypeEnum.String)
{
return StringAggregation(sourceWorkItems, targetWorkItem, configAggregatorItem);
}
// This should never happen
return false;
}
/// <summary>
/// Adds up all the values that need aggregating
/// </summary>
/// <returns>true if a change was made. False if not</returns>
private static bool NumericAggregation(IEnumerable<WorkItem> sourceWorkItems, WorkItem targetWorkItem, ConfigAggregatorItem configAggregatorItem)
{
double aggregateValue = 0;
// Iterate through all of the work items that we are pulling data from.
// For link type of "Self" this will be just one item. For "Parent" this will be all of the co-children of the work item sent in the event.
foreach (WorkItem sourceWorkItem in sourceWorkItems)
{
// Iterate through all of the TFS Fields that we are aggregating.
foreach (ConfigItemType sourceField in configAggregatorItem.SourceItems)
{
double sourceValue = sourceWorkItem.GetField(sourceField.Name, 0.0);
aggregateValue = configAggregatorItem.Operation.Perform(aggregateValue, sourceValue);
}
}
if (aggregateValue != targetWorkItem.GetField<double>(configAggregatorItem.TargetItem.Name, 0))
{
targetWorkItem[configAggregatorItem.TargetItem.Name] = aggregateValue;
return true;
}
return false;
}
/// <summary>
/// Checks to see if all of the source fields values are in one of the mappings.
/// The first mapping that is found that is a match is used. It will apply the target value from the mapping to
/// the Target Field.
/// </summary>
/// <returns>true if a change was made. False if not</returns>
private static bool StringAggregation(IEnumerable<WorkItem> sourceWorkItems, WorkItem targetWorkItem, ConfigAggregatorItem configAggregatorItem)
{
string aggregateValue = "";
bool aggregateFound = false;
// Iterate through the mappings until (or if) we find one that we match on
foreach (Mapping mapping in configAggregatorItem.Mappings)
{
bool mappingMatches;
// The default value depends on the inclusivity of the mappings.
// If it is And then we are trying to prove that all of them match so we start with true, any mismatches will cause us to set to false.
// If it is Or then we are trying to prove that only one them match to succeed so we start with false, any matches will cause us to set to true.
if (mapping.Inclusive)
mappingMatches = true;
else
mappingMatches = false;
// Iterate through all of the work items that we are pulling data from.
// For link type of "Self" this will be just one item. For "Parent" this will
// be all of the co-children of the work item sent in the event.
foreach (WorkItem sourceWorkItem in sourceWorkItems)
{
// Iterate through all of the TFS Fields that we are aggregating.
foreach (ConfigItemType sourceField in configAggregatorItem.SourceItems)
{
// Get the value of the sourceField on the sourceWorkItem
string sourceValue = sourceWorkItem.GetField(sourceField.Name, "");
// Check to see if the value we have is not in the list of SourceValues
// If it is not then this mapping is not going to be satisfied because this source item
// breaks it (because we are inclusively checking (i.e. "And")).
if (!mapping.SourceValues.Contains(sourceValue) &&(mapping.Inclusive))
{
// it was not in the list. We are done with this mapping.
// if we get here then this is an "And" mapping that failed.
mappingMatches = false;
break;
}
// Check to see if the value we have is in the list of SourceValues
// If it is, this mapping is satisfied because we are non inclusive (i.e. "Or")
if (mapping.SourceValues.Contains(sourceValue) && (!mapping.Inclusive))
{
// it was in the list. We are done with this mapping.
// If we get here then this was an "Or" mapping that succeeded
mappingMatches = true;
break;
}
}
// If this is an "And" and mapping does not match then we may as well be done with this iteration of work items.
if ((!mappingMatches) && (mapping.Inclusive))
break;
// If this is an "Or" and mapping does match then we need to be done.
if ((mappingMatches) && (!mapping.Inclusive))
break;
}
// If the mapping matched then we are done looking
if (mappingMatches)
{
aggregateValue = mapping.TargetValue;
aggregateFound = true;
break;
}
}
if (aggregateFound)
{
// see if we need to make a change:
if (targetWorkItem[configAggregatorItem.TargetItem.Name].ToString() != aggregateValue)
{
// If this is the "State" field then we may have do so special stuff
// (to get the state they want from where we are). If not then just set the value.
if (configAggregatorItem.TargetItem.Name != "State")
targetWorkItem[configAggregatorItem.TargetItem.Name] = aggregateValue;
else
targetWorkItem.TransitionToState(aggregateValue, "TFS Aggregator: ");
return true;
}
}
return false;
}
}
}