Пример #1
0
        /// <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;
        }
Пример #2
0
        /// <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;
        }
        // Load in the settings from file
        private static void GetSettings()
        {
            _configAggregatorItems = new List <ConfigAggregatorItem>();
            XDocument doc;

            // Load the options
            if (string.IsNullOrEmpty(SettingsOverride))
            {
                string xmlFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase), "AggregatorItems.xml");
                doc = XDocument.Load(xmlFileName);
            }
            else
            {
                doc = XDocument.Parse(SettingsOverride);
            }

            // Save off the TFS server name
            _tfsUri = doc.Element("AggregatorItems").Attribute("tfsServerUrl").Value;

            //Save off the Logging level
            _loggingVerbosity = doc.Element("AggregatorItems").LoadEnumAttribute("loggingVerbosity", MiscHelpers.LoggingLevel.None);

            // Get all the AggregatorItems loaded in
            foreach (XElement xmlAggItem in doc.Element("AggregatorItems").Elements())
            {
                // Setup the actual item
                ConfigAggregatorItem aggItem = new ConfigAggregatorItem();

                aggItem.Operation          = xmlAggItem.LoadEnumAttribute("operation", OperationEnum.Sum);
                aggItem.LinkType           = xmlAggItem.LoadEnumAttribute("linkType", ConfigLinkTypeEnum.Self);
                aggItem.OperationType      = xmlAggItem.LoadEnumAttribute("operationType", OperationTypeEnum.Numeric);
                aggItem.LinkLevel          = xmlAggItem.LoadAttribute("linkLevel", 1);
                aggItem.Name               = xmlAggItem.LoadAttribute("name", "Name not set");
                aggItem.WorkItemType       = xmlAggItem.Attribute("workItemType").Value;
                aggItem.TargetWorkItemType = xmlAggItem.LoadAttribute("targetWorkItemType", "");

                // Iterate through all the sub items (Mappings, source and target items.))
                foreach (XElement xmlConfigItem in xmlAggItem.Elements())
                {
                    // If this is a target item then add it as such
                    if (xmlConfigItem.Name == "TargetField")
                    {
                        aggItem.TargetField = new ConfigItemType {
                            Name = xmlConfigItem.Attribute("name").Value
                        };
                    }
                    // If this is a source item then add it as such
                    if (xmlConfigItem.Name == "SourceField")
                    {
                        aggItem.SourceFields.Add(new ConfigItemType {
                            Name = xmlConfigItem.Attribute("name").Value
                        });
                    }

                    // If this is an outputFormat item then add it as such
                    if (xmlConfigItem.Name == "OutputFormat")
                    {
                        aggItem.OutputFormat = xmlConfigItem.Attribute("formatString").Value;
                    }

                    // If this is conditions (for the target) then read them in.
                    if (xmlConfigItem.Name == "Conditions")
                    {
                        // Iterate all the conditions we have.
                        foreach (XElement xmlCondition in xmlConfigItem.Elements())
                        {
                            Condition condition = new Condition
                            {
                                LeftFieldName  = xmlCondition.LoadAttribute("leftField", ""),
                                LeftValue      = xmlCondition.LoadAttribute <string>("leftValue", null),
                                CompOperator   = xmlCondition.LoadEnumAttribute("operator", ComparisionOperator.EqualTo),
                                RightValue     = xmlCondition.LoadAttribute <string>("rightValue", null),
                                RightFieldName = xmlCondition.LoadAttribute <string>("rightField", null)
                            };
                            aggItem.Conditions.Add(condition);
                        }
                    }

                    // If this is the mappings then read them in
                    if (xmlConfigItem.Name == "Mappings")
                    {
                        // Iterate all the mappings we have.
                        foreach (XElement xmlMappingItem in xmlConfigItem.Elements())
                        {
                            Mapping mapping = new Mapping();
                            // Read in the target and source values (we set the target field
                            // to this value if all of the source fields are in the list of source values)
                            mapping.TargetValue = xmlMappingItem.Attribute("targetValue").Value;
                            // load in the inclusivity of the mapping (default to "And")
                            mapping.Inclusive = xmlMappingItem.LoadAttribute("inclusive", "And") == "And";
                            foreach (XElement xmlSourceValue in xmlMappingItem.Elements())
                            {
                                mapping.SourceValues.Add(xmlSourceValue.Value);
                            }

                            aggItem.Mappings.Add(mapping);
                        }
                    }
                }
                // add this one to the list
                _configAggregatorItems.Add(aggItem);
            }

            // Indicate that we don't need to load the settings again.
            _settingsRetrieved = true;
        }
        // Load in the settings from file
        private static void GetSettings()
        {
            _configAggregatorItems = new List<ConfigAggregatorItem>();

            // Load the options
            string xmlFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase), "AggregatorItems.xml");
            XDocument doc = XDocument.Load(xmlFileName);

            // Save off the TFS server name
            _tfsUri = doc.Element("AggregatorItems").Attribute("tfsServerUrl").Value;

            //Save off the Logging level
            _loggingVerbosity = doc.Element("AggregatorItems").LoadEnumAttribute("loggingVerbosity", MiscHelpers.LoggingLevel.None);

            // Get all the AggregatorItems loaded in
            foreach (XElement xmlAggItem in doc.Element("AggregatorItems").Elements())
            {
                // Setup the actual item
                ConfigAggregatorItem aggItem = new ConfigAggregatorItem();

                aggItem.Operation = xmlAggItem.LoadEnumAttribute("operation", OperationEnum.Sum);
                aggItem.LinkType = xmlAggItem.LoadEnumAttribute("linkType", ConfigLinkTypeEnum.Self);
                aggItem.OperationType = xmlAggItem.LoadEnumAttribute("operationType", OperationTypeEnum.Numeric);
                aggItem.LinkLevel = xmlAggItem.LoadAttribute("linkLevel", 1);
                aggItem.Name = xmlAggItem.LoadAttribute("name", "Name not set");
                aggItem.WorkItemType = xmlAggItem.Attribute("workItemType").Value;

                // Iterate through all the sub items (Mappings, source and target items.))
                foreach (XElement xmlConfigItem in xmlAggItem.Elements())
                {
                    // If this is a target item then add it as such
                    if (xmlConfigItem.Name == "TargetItem")
                    {
                        aggItem.TargetItem = new ConfigItemType { Name = xmlConfigItem.Attribute("name").Value };

                    }
                    // If this is a source item then add it as such
                    if (xmlConfigItem.Name == "SourceItem")
                    {
                        aggItem.SourceItems.Add(new ConfigItemType { Name = xmlConfigItem.Attribute("name").Value });
                    }

                    // If this is conditions (for the target) then read them in.
                    if (xmlConfigItem.Name == "Conditions")
                    {
                        // Iterate all the conditions we have.
                        foreach (XElement xmlCondition in xmlConfigItem.Elements())
                        {
                            Condition condition = new Condition();
                            condition.LeftFieldName = xmlCondition.LoadAttribute("leftField", "");
                            condition.CompOperator = xmlCondition.LoadEnumAttribute("operator",
                                                                                    ComparisionOperator.EqualTo);
                            condition.RightValue = xmlCondition.LoadAttribute<string>("rightValue", null);
                            condition.RightFieldName = xmlCondition.LoadAttribute<string>("rightField", null);

                            aggItem.Conditions.Add(condition);
                        }

                    }

                    // If this is the mappings then read them in
                    if (xmlConfigItem.Name == "Mappings")
                    {
                        // Iterate all the mappings we have.
                        foreach (XElement xmlMappingItem in xmlConfigItem.Elements())
                        {
                            Mapping mapping = new Mapping();
                            // Read in the target and source values (we set the target field
                            // to this value if all of the source fields are in the list of source values)
                            mapping.TargetValue = xmlMappingItem.Attribute("targetValue").Value;
                            // load in the inclusivity of the mapping (default to "And")
                            mapping.Inclusive = xmlMappingItem.LoadAttribute("inclusive", "And") == "And";
                            foreach (XElement xmlSourceValue in xmlMappingItem.Elements())
                            {
                                mapping.SourceValues.Add(xmlSourceValue.Value);
                            }

                            aggItem.Mappings.Add(mapping);
                        }
                    }
                }
                // add this one to the list
                _configAggregatorItems.Add(aggItem);
            }

            // Indicate that we don't need to load the settings again.
            _settingsRetrieved = true;
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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;
        }
Пример #9
0
        /// <summary>
        /// This is the one where all the magic starts.  Main() so to speak.  I will load the settings, connect to tfs and apply the aggregation rules.
        /// </summary>
        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs,
                                                    out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
        {
            statusCode    = 0;
            properties    = null;
            statusMessage = String.Empty;
            int    currentAggregationId   = 0;
            int    workItemId             = 0;
            string currentAggregationName = string.Empty;

            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    // Change this object to be a type we can easily get into
                    WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
                    // Connect to the setting file and load the location of the TFS server
                    string tfsUri = TFSAggregatorSettings.TFSUri;
                    // Connect to TFS so we are ready to get and send data.
                    Store store = new Store(tfsUri);
                    // Get the id of the work item that was just changed by the user.
                    workItemId = ev.CoreFields.IntegerFields[0].NewValue;
                    // Download the work item so we can update it (if needed)
                    WorkItem        eventWorkItem    = store.Access.GetWorkItem(workItemId);
                    string          workItemTypeName = eventWorkItem.Type.Name;
                    List <WorkItem> workItemsToSave  = new List <WorkItem>();

                    if (TFSAggregatorSettings.LoggingIsEnabled)
                    {
                        MiscHelpers.LogMessage(String.Format("Change detected to {0} [{1}]", workItemTypeName, workItemId));
                        MiscHelpers.LogMessage(String.Format("{0}Processing {1} AggregationItems", "  ", TFSAggregatorSettings.ConfigAggregatorItems.Count.ToString()));
                    }

                    // Apply the aggregation rules to the work item
                    foreach (ConfigAggregatorItem configAggregatorItem in TFSAggregatorSettings.ConfigAggregatorItems)
                    {
                        IEnumerable <WorkItem> sourceWorkItems = null;
                        WorkItem targetWorkItem = null;
                        currentAggregationName = configAggregatorItem.Name;

                        // Check to make sure that the rule applies to the work item type we have
                        if (eventWorkItem.Type.Name == configAggregatorItem.WorkItemType)
                        {
                            if (TFSAggregatorSettings.LoggingIsEnabled)
                            {
                                MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' applies to {1} work items", "    ", workItemTypeName, currentAggregationId, currentAggregationName));
                            }

                            // Use the link type to see what the work item we are updating is
                            if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Self)
                            {
                                // We are updating the same workitem that was sent in the event.
                                sourceWorkItems = new List <WorkItem> {
                                    eventWorkItem
                                };
                                targetWorkItem = eventWorkItem;

                                if (TFSAggregatorSettings.LoggingIsEnabled)
                                {
                                    MiscHelpers.LogMessage(String.Format("{0}{0}{0}Aggregation applies to SELF. ({1} {2})", "  ", workItemTypeName, workItemId));
                                }

                                // Make sure that all conditions are true before we do the aggregation
                                // If any fail then we don't do this aggregation.
                                if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem))
                                {
                                    if (TFSAggregatorSettings.LoggingIsEnabled)
                                    {
                                        MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are not met.", "    "));
                                    }
                                    currentAggregationId++;
                                    continue;
                                }

                                if (TFSAggregatorSettings.LoggingIsEnabled)
                                {
                                    MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are met.", "    "));
                                }
                            }
                            // We are aggregating to the parent
                            else if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Parent)
                            {
                                bool parentLevelFound = true;

                                // Go up the tree till we find the level of parent that we are looking for.
                                WorkItem iterateToParent = eventWorkItem;
                                for (int i = 0; i < configAggregatorItem.LinkLevel; i++)
                                {
                                    // Load the parent from the saved list (if we have it in there) or just load it from the store.
                                    WorkItem nullCheck = iterateToParent.GetParentFromListOrStore(workItemsToSave, store);
                                    //
                                    if (nullCheck != null)
                                    {
                                        iterateToParent = nullCheck;
                                    }
                                    else
                                    {
                                        parentLevelFound = false;
                                    }
                                }
                                // If we did not find the correct parent then we are done with this aggregation.
                                if (!parentLevelFound)
                                {
                                    if (TFSAggregatorSettings.LoggingIsEnabled)
                                    {
                                        MiscHelpers.LogMessage(String.Format("{0}{0}{0}Couldn't find a PARENT {2} {4} up from {3} [{1}]. This aggregation will not continue.", "  ", workItemId, configAggregatorItem.LinkLevel, workItemTypeName, configAggregatorItem.LinkLevel > 1 ? "levels" : "level"));
                                    }
                                    currentAggregationId++;
                                    continue;
                                }

                                if (TFSAggregatorSettings.LoggingIsEnabled)
                                {
                                    MiscHelpers.LogMessage(String.Format("{0}{0}{0}Found {1} [{2}] {3} {4} up from {5} [{6}].  Aggregation continues.", "  ", iterateToParent.Type.Name, iterateToParent.Id, configAggregatorItem.LinkLevel, configAggregatorItem.LinkLevel > 1 ? "levels" : "level", workItemTypeName, workItemId));
                                }

                                targetWorkItem = iterateToParent;

                                // Make sure that all conditions are true before we do the aggregation
                                // If any fail then we don't do this aggregation.
                                if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem))
                                {
                                    if (TFSAggregatorSettings.LoggingIsEnabled)
                                    {
                                        MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are not met", "    "));
                                    }
                                    currentAggregationId++;
                                    continue;
                                }

                                if (TFSAggregatorSettings.LoggingIsEnabled)
                                {
                                    MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are met", "    "));
                                }

                                // Get the children down how ever many link levels were specified.
                                List <WorkItem> iterateFromParents = new List <WorkItem> {
                                    targetWorkItem
                                };
                                for (int i = 0; i < configAggregatorItem.LinkLevel; i++)
                                {
                                    List <WorkItem> thisLevelOfKids = new List <WorkItem>();
                                    // Iterate all the parents to find the children of current set of parents
                                    foreach (WorkItem iterateFromParent in iterateFromParents)
                                    {
                                        thisLevelOfKids.AddRange(iterateFromParent.GetChildrenFromListOrStore(workItemsToSave, store));
                                    }

                                    iterateFromParents = thisLevelOfKids;
                                }

                                // remove the kids that are not the right type that we are working with
                                ConfigAggregatorItem configAggregatorItemClosure = configAggregatorItem;
                                iterateFromParents.RemoveAll(x => x.Type.Name != configAggregatorItemClosure.WorkItemType);

                                sourceWorkItems = iterateFromParents;
                            }

                            // Do the actual aggregation now
                            bool changeMade = Aggregator.Aggregate(sourceWorkItems, targetWorkItem, configAggregatorItem);

                            // If we made a change then add this work item to the list of items to save.
                            if (changeMade)
                            {
                                // Add the target work item to the list of work items to save.
                                workItemsToSave.AddIfUnique(targetWorkItem);
                            }
                        }
                        else
                        {
                            if (TFSAggregatorSettings.LoggingIsEnabled)
                            {
                                MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' does not apply to {1} work items", "    ", workItemTypeName, currentAggregationId, currentAggregationName));
                            }
                        }

                        currentAggregationId++;
                    }

                    // Save any changes to the target work items.
                    workItemsToSave.ForEach(x =>
                    {
                        bool isValid = x.IsValid();

                        if (TFSAggregatorSettings.LoggingIsEnabled)
                        {
                            MiscHelpers.LogMessage(String.Format("{0}{0}{0}{1} [{2}] {3} valid to save. {4}",
                                                                 "    ",
                                                                 x.Type.Name,
                                                                 x.Id,
                                                                 isValid ? "IS" : "IS NOT",
                                                                 String.Format("\n{0}{0}{0}{0}Invalid fields: {1}", "    ", MiscHelpers.GetInvalidWorkItemFieldsList(x).ToString())));
                        }

                        if (isValid)
                        {
                            x.PartialOpen();
                            x.Save();
                        }
                    });

                    MiscHelpers.AddRunSeparatorToLog();
                }
            }
            catch (Exception e)
            {
                string message = String.Format("Exception encountered processing Work Item [{2}]: {0} \nStack Trace:{1}", e.Message, e.StackTrace, workItemId);
                if (e.InnerException != null)
                {
                    message += String.Format("\n    Inner Exception: {0} \nStack Trace:{1}", e.InnerException.Message, e.InnerException.StackTrace);
                }
                MiscHelpers.LogMessage(message, true);
            }

            return(EventNotificationStatus.ActionPermitted);
        }
Пример #10
0
        /// <summary>
        /// Copies a value from one workitem into another.
        /// Values are copied from the target into the source (the event item)
        /// </summary>
        /// <returns>true if a change was made.  False if not</returns>
        private static IWorkItem CopyToAggregation(IWorkItem childWorkItem, IWorkItem parentWorkItem, ConfigAggregatorItem configAggregatorItem)
        {
            var aggregateSourceValues = new List <string>();

            // Iterate through all of the TFS Fields that we are aggregating.
            foreach (ConfigItemType sourceField in configAggregatorItem.SourceFields)
            {
                object value = parentWorkItem.GetField(sourceField.Name, (object)null);
                // Get the value of the sourceField on the sourceWorkItem and add it to the list
                string sourceValue = (value ?? "").ToString();
                aggregateSourceValues.Add(sourceValue);
            }

            var resultValue = string.Format(configAggregatorItem.OutputFormat, aggregateSourceValues.ToArray());

            // see if we need to make a change:
            if (childWorkItem[configAggregatorItem.TargetField.Name].ToString() != resultValue)
            {
                //We don't want to use copyfrom for the state. There are other ways of doing that.
                if (configAggregatorItem.TargetField.Name != "State")
                {
                    childWorkItem[configAggregatorItem.TargetField.Name] = resultValue;
                    return(childWorkItem);
                }
            }

            return(null);
        }
Пример #11
0
        /// <summary>
        /// Used to acutally do the aggregating.
        /// </summary>
        /// <returns>true if a change was made.  False if not</returns>
        public static IWorkItem Aggregate(IWorkItem sourceWorkItem, IEnumerable <IWorkItem> sourceWorkItems, IWorkItem targetWorkItem, ConfigAggregatorItem configAggregatorItem)
        {
            if (configAggregatorItem.OperationType == OperationTypeEnum.Numeric)
            {
                return(NumericAggregation(sourceWorkItems, targetWorkItem, configAggregatorItem));
            }
            if (configAggregatorItem.OperationType == OperationTypeEnum.String)
            {
                return(StringAggregation(sourceWorkItems, targetWorkItem, configAggregatorItem));
            }
            if (configAggregatorItem.OperationType == OperationTypeEnum.CopyFrom)
            {
                return(CopyFromAggregation(sourceWorkItem, targetWorkItem, configAggregatorItem));
            }
            if (configAggregatorItem.OperationType == OperationTypeEnum.CopyTo)
            {
                return(CopyToAggregation(targetWorkItem, sourceWorkItem, configAggregatorItem));
            }

            // This should never happen
            return(null);
        }
Пример #12
0
        /// <summary>
        /// Copies a value from one workitem into another.
        /// Values are copied from the target into the source (the event item)
        /// </summary>
        /// <returns>true if a change was made.  False if not</returns>
        private static IWorkItem CopyFromAggregation(IWorkItem childWorkItem, IWorkItem parentWorkItem, ConfigAggregatorItem configAggregatorItem)
        {
            //Source is the item just updated. It's the one we want to copy values to, not from.
            //It means that this code is a little confusing since source and target have reversed meanings.
            //For that reason we switch things around

            var aggregateSourceValues = new List <string>();

            // Iterate through all of the TFS Fields that we are aggregating.
            foreach (ConfigItemType sourceField in configAggregatorItem.SourceFields)
            {
                object value = parentWorkItem.GetField(sourceField.Name, (object)null);
                // Get the value of the sourceField on the sourceWorkItem and add it to the list
                string sourceValue = (value ?? "").ToString();
                aggregateSourceValues.Add(sourceValue);
            }

            var resultValue = string.Format(configAggregatorItem.OutputFormat, aggregateSourceValues.ToArray());

            // see if we need to make a change:
            if (childWorkItem[configAggregatorItem.TargetField.Name].ToString() != resultValue)
            {
                //We don't want to use copyfrom for the state. There are other ways of doing that.
                if (configAggregatorItem.TargetField.Name != "State")
                {
                    childWorkItem[configAggregatorItem.TargetField.Name] = resultValue;
                    return(childWorkItem);
                }
            }

            return(null);
        }