// Get the Uri for the TR before disconnected assuming disconnect was done in // previous save. Preconditions should be checked by caller. static public Uri getDisconnectedTRLink( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, WorkItemChangedEvent notification) { // Apparently we need to check on second last revision to get the correct // value for the previous value. This does not show in UI, but is clear when // debugging. So check we have > 2 revisions, and then compare. if (workItem.Revision < 3) { return(null); } Revision lastRev = workItem.Revisions[workItem.Revision - 2]; String oldTrLink = lastRev.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value.ToString(); if (oldTrLink == null || oldTrLink.Length == 0) { return(null); } HandlerSettings.LogMessage( String.Format( "Disconnected TR '{0}' from WorkItem with id {1}.", oldTrLink, "" + workItem.Id), HandlerSettings.LoggingLevel.INFO); return(new Uri(HandlerSettings.GetUriForTR(oldTrLink))); }
// ============================================================= // Ignore all changes done by ourselves - i.e. the functional user used to handle save events. // Note that IF functional user would be logged in as regular user, events will not be handled. private bool ignoreSaveEvent(WorkItemChangedEvent ev) { bool ignore = HandlerSettings.IgnoreEventByUser( getStore().TeamProjectCollection, ev.ChangerTeamFoundationId); return(ignore); }
// Check if we should disconnect a TR. Condition is that an external save // (by TFSProviderUser) has caused the TR Link field to transition from a // value to an empty value, This indicates disconnect. private EventType CheckDisconnect( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi, WorkItemChangedEvent notification, String user) { if (!user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase)) { // Only disconnect based on incoming external event. // Disconnect by user is handled by separate code return(EventType.Ignore); } if (notification.ChangeType == ChangeTypes.New) { // Disconnect can only happen for a changed WI, not a new. return(EventType.Ignore); } // Get the current field - Disconnect case assume this is "" if (!wi.Fields.Contains(TFSMapper.ERICSSON_DEFECT_LINK_FIELD)) { // Odd case where the mandatory field is missing return(EventType.Ignore); } Object trLinkValue = wi.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value; if (trLinkValue == null) { return(EventType.Ignore); } String trLink = trLinkValue.ToString(); if (trLink != null && trLink.Length > 0) { return(EventType.Ignore); } TextField[] changedTextFields = notification.TextFields; if (changedTextFields == null || changedTextFields.Length == 0) { // The TR Link field is a Text field - if no changes, ignore. return(EventType.Ignore); } // Check so also the TR Link field is changed for (int i = 0; i < changedTextFields.Length; i++) { String name = changedTextFields[i].ReferenceName; if (name.Equals(TFSMapper.ERICSSON_DEFECT_LINK_FIELD)) { return(EventType.Disconnect); } } return(EventType.Ignore); }
// UC 6: Create a TR based on a Bug. // Return if the bug is updated or not. private void createTR( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, WorkItemChangedEvent notification, String user, ref Status status) { // Create the ECR callCreateTR(ECRMapper.mapFromWorkitem(workItem, null, ECRMapper.ACTION_CREATE), user, ref status); if (!status.OK) { return; } // UC 3 (one case): Update all changed attributes before handling any state change // Note: If adding an entry in History on create this should propagate to Progress Info, but // this caused Bug to appear dirty after Save, see issue 79. Given almost all fields are used on // create, it does not make sense to make extra update as below. TBD if we should re-add in a // changed form. //EnterpriseChangeRequest updatedEcr = ECRMapper.mapFromUpdatedWorkitem(workItem, status.TRAbout, notification); //if (updatedEcr != null) //{ // // Note: Failure to update will be Warning not Error, so status still OK. // callUpdateTR(updatedEcr, user, null, ref status); //} // Set the ECR in state Registered EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, status.TRAbout, ECRMapper.ACTION_REGISTER_ROUTE); callUpdateTR(ecr, user, ECRMapper.TR_STATE_REGISTERED_S, ref status); if (!status.OK) { return; } // Set the ECR in state Assigned if we have a defined owner ecr = ECRMapper.mapFromWorkitem(workItem, status.TRAbout, ECRMapper.ACTION_ASSIGN); if (ecr.GetOwner() != null && ecr.GetOwner().Length > 0) { callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref status); if (!status.OK) { return; } } if (status.OK) { HandlerSettings.LogMessage( String.Format("Created TR based on workitem named: {0}", workItem.Title), HandlerSettings.LoggingLevel.INFO); } }
// For call to create TR we need Ericsson user id (also domain?) - seems like we have what we want here. // TDOD: Try and make sure we are getting the correct attribute. // See http://stackoverflow.com/questions/19911368/using-the-tfs-2012-api-how-do-i-get-the-email-address-of-a-user static public String GetSignumForChangeNotification( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, WorkItemChangedEvent notification) { TfsTeamProjectCollection tpc = workItem.Store.TeamProjectCollection; String userId = notification.ChangerTeamFoundationId; IIdentityManagementService mgmntService = tpc.GetService <IIdentityManagementService>(); Guid[] ids = new Guid[1]; ids[0] = new Guid(notification.ChangerTeamFoundationId); TeamFoundationIdentity[] members = mgmntService.ReadIdentities(ids, MembershipQuery.Direct); return(GetUserFromSignum(members[0].UniqueName)); }
// Update the changed fields that are mapped. Return if the bug is updated or not. private void updateTRFields( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, WorkItemChangedEvent notification, String user, Uri about, ref Status status) { // UC 3 (one case): Update all changed attributes before handling any state change. EnterpriseChangeRequest updatedEcr = ECRMapper.mapFromUpdatedWorkitem(workItem, about, notification); if (updatedEcr != null) { // Note: Failure to update will be Warning not Error, so status still OK. callUpdateTR(updatedEcr, user, null, ref status); } }
// Return if the workitem is updated (saved) by the handling code. public void handleEvent( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, String user, WorkItemChangedEvent notification) { Status status = new Status(); // If the user is the OSLC Provider functional user we will only update status // message if so needed. This as changes from the OSLC Provider originates from // external source = currently: MHWeb. Need revisit to allow multiple clients. String aboutStr = AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ABOUT, workItem); if (!user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase)) { if (aboutStr.Length == 0) { // We do not have a linked TR, we need to create createTR(workItem, notification, user, ref status); } else { Uri about = new Uri(aboutStr); Status statusAssign = null; EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ASSIGN); TeamFoundationIdentity assignedTo = HandlerSettings.GetSignumForAssignedTo(workItem); if (user != null && assignedTo != null && !user.Equals(HandlerSettings.GetUserFromSignum(assignedTo.UniqueName), StringComparison.OrdinalIgnoreCase)) { statusAssign = new Status(); ecr.SetOwner(user); callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref statusAssign); } // We have a TR linked which might need to be updated updateTR(workItem, notification, user, about, ref status); if (statusAssign != null && statusAssign.OK) { ecr.SetOwner(HandlerSettings.GetUserFromSignum(assignedTo.UniqueName)); callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref statusAssign); } } } // Handle update of Bug ECRMapper.updateBug(status, user, workItem); }
public static XmlNode SerializeXml(WorkItemChangedEvent workItemChangedEvent) { if (null == workItemChangedEvent) { return(null); } var xmlSerializer = new XmlSerializer(typeof(WorkItemChangedEvent)); var memoryStream = new MemoryStream(); xmlSerializer.Serialize(memoryStream, workItemChangedEvent); memoryStream.Position = 0; var xmlDocument = new XmlDocument(); xmlDocument.Load(memoryStream); memoryStream.Close(); return(xmlDocument.ChildNodes[1]); }
public TeamFoundationJobExecutionResult Run( TeamFoundationRequestContext requestContext, TeamFoundationJobDefinition jobDefinition, DateTime queueTime, out string resultMessage) { resultMessage = string.Empty; try { string strConfigFile = this.workflowRunner.ExecutionPath.FullName + ".config"; XmlConfigurator.Configure(new Uri(strConfigFile)); AppendSuffixToLoggingPath("_JobAgent"); this.LogInfo(string.Format("Enter Job for WorkitemChangedEvent")); lock (JobLock) { XmlNode xmlData = jobDefinition.Data; WorkItemChangedEvent workItemChangedEvent = WorkItemChangedEventSerializer.DeserializeXml(xmlData); this.workflowRunner.ProcessEvent(requestContext, workItemChangedEvent); } } catch (RequestCanceledException e) { this.LogError(string.Format("Workflow cancel: "), e); return(TeamFoundationJobExecutionResult.Stopped); } catch (Exception e) { this.LogError(string.Format("Workflow error: "), e); resultMessage = e.ToString(); return(TeamFoundationJobExecutionResult.Failed); } this.LogInfo(string.Format("Leave Job for WorkitemChangedEvent")); return(TeamFoundationJobExecutionResult.Succeeded); }
// ========================================================= // Handle the WorkItemChangedEvent event // Disconnect TR if conditions are matching. Return if workitem has been saved. public void handleDisconnectEvent( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, String user, WorkItemChangedEvent notification) { Uri about = ECRMapper.getDisconnectedTRLink(workItem, notification); if (about == null) { return; } EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem( workItem, about, ECRMapper.ACTION_DISCONNECT); Status status = new Status(); callUpdateTR(ecr, user, null, ref status); if (!status.OK) { HandlerSettings.LogMessage( "Failed to disconnect TR from Bug.", HandlerSettings.LoggingLevel.WARN); } }
/// <summary> /// Main factory method that determines the workitem type /// </summary> /// <param name="_wice"> /// Workitem Change Event object /// </param> /// <returns> /// Correct child object for workitem changed /// </returns> public IHarleysvilleWorkItemAlerts GetWorkItem(WorkItemChangedEvent _wice, TFSIdentity _tfsId) { IHarleysvilleWorkItemAlerts _Ihar = null; foreach (StringField _sf in _wice.CoreFields.StringFields) { if (_sf.Name.Equals("Work Item Type", StringComparison.CurrentCultureIgnoreCase)) { switch (_sf.NewValue) { case "Deployment Backlog Item": _Ihar = new HarleysvilleDBIAlerts(_wice, _tfsId); break; case "Build Backlong Item": _Ihar = new HarelysvilleWorkItemAlerts(); break; case "Sprint Backlog Item": _Ihar = new HarelysvilleWorkItemAlerts(); break; case "Release Backlog Item": _Ihar = new HarelysvilleWorkItemAlerts(); break; case "Product Backlog Item": _Ihar = new HarelysvilleWorkItemAlerts(); break; case "Label Backlog Item": _Ihar = new HarleysvilleLBIAlerts(_wice, _tfsId); break; default : _Ihar = new HarelysvilleWorkItemAlerts(); break; } } } return _Ihar; }
private IdentityDescriptor GetIdentityToImpersonate(TeamFoundationRequestContext requestContext, WorkItemChangedEvent workItemChangedEvent) { Uri server = this.GetCollectionUriFromContext(requestContext); var configurationServer = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(server); // TODO: Find a way to read the identity from the server object model instead. IIdentityManagementService identityManagementService = configurationServer.GetService<IIdentityManagementService>(); TeamFoundationIdentity identity = identityManagementService.ReadIdentities( new Guid[] { new Guid(workItemChangedEvent.ChangerTeamFoundationId) }, MembershipQuery.None).FirstOrDefault(); return identity?.Descriptor; }
public void SetWorkItemHelper(WorkItemChangedEvent wice, TFWI tfs) { _wice = wice; SetWorkItemHelper(); _tfs = tfs; _wiFields = _tfs.GetWorkItemFields(); _wiState = _wiFields["State"]; }
public void SetWorkItemHelper(WorkItemChangedEvent wice, string tfsUrl) { _wice = wice; SetWorkItemHelper(); _tfs = new TFWI(tfsUrl, _wiNumber); _wiFields = _tfs.GetWorkItemFields(); _wiState = _wiFields["State"]; }
private void Catcher(Exception ex, WorkItemChangedEvent _wice) { WriteErrorLog("ERROR: " + ex.ToString() + "\n" + _wice.DisplayUrl); }
private void Catcher(Exception ex, IHarleysvilleWorkItemAlerts _Iha, WorkItemChangedEvent _wice) { //WriteLog(ex.ToString()); StringBuilder _sb = new StringBuilder(); _sb.AppendLine(ex.ToString()) .AppendLine() .AppendLine("Below is URL to Work item: ") .AppendLine(_wice.DisplayUrl); _Iha.DebugMailer(ConfigurationManager.AppSettings.Get("DebugEmailSubject"), _sb.ToString()); WriteErrorLog(_sb.ToString()); if (ConfigurationManager.AppSettings.Get("DebugMode").Equals("on", StringComparison.CurrentCultureIgnoreCase)) { WriteLog(_sb.ToString()); } }
// ======================================================================= // Mapping from workItem to ECR // Return the Bug and TR state change if part of update public static void getStatusChange(WorkItemChangedEvent notification, Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, out String oldState, out String newState, out String action) { newState = null; oldState = null; action = null; // If the Bug and TR are in different states, block update from Bug to TR. if (ECRMapper.IsSyncError(workItem)) { action = ACTION_IGNORE; return; } bool changedAssignedTo = false; // If Bug marked as Duplicate, the only activity to be propagated to TR is Unduplicate. String substate = workItem.Fields[TFSMapper.TFS_SUBSTATE].Value.ToString(); bool isDuplicate = substate.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE); bool isDuplicateChanged = false; if (notification.ChangedFields == null || notification.ChangedFields.StringFields == null) { // No fields of interest are changed return; } StringField[] changedFields = notification.ChangedFields.StringFields; for (int i = 0; i < changedFields.Length; i++) { String name = changedFields[i].ReferenceName; if (name.Equals(TFSMapper.TFS_STATE, StringComparison.OrdinalIgnoreCase)) { oldState = changedFields[i].OldValue; newState = changedFields[i].NewValue; } else if (name.Equals(TFSMapper.TFS_OWNER, StringComparison.OrdinalIgnoreCase)) { changedAssignedTo = true; } // If TFS_SUBSTATE is changed to/from Duplicate the TR should be set to // corresponding state. If marked as Duplicate, the only activity that // should be propagated to TR is Unduplicate. else if (name.Equals(TFSMapper.TFS_SUBSTATE)) { if (changedFields[i].NewValue.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE) || changedFields[i].OldValue.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE)) { isDuplicateChanged = true; } } // If the release is changed, we need to update the TR product // Note: In case we also set to Duplicate, we will disregard product change else if (name.Equals(TFSMapper.TFS_FAULTY_PRODUCT)) { action = ACTION_CHANGE_PRODUCT; } } if (isDuplicateChanged) { // If the Duplicate flag is changed we need to act on this. This is a substate flag, so // it can happen also during a state transition. action = isDuplicate ? ACTION_DUPLICATE : ACTION_UNDUPLICATE; return; } else if (isDuplicate) { // If Bug is duplicate and there is no change for this state, we should send no // updates to TR until unduplicated. action = ACTION_IGNORE; return; } // If we have a changed of "Assigned To" this will only be possible to update in specific // TR states. So if Assigned To changed at same time as state - likely need to prevent. if (changedAssignedTo) { if (newState == null || oldState == null) { // No state change for Bug, but for TR oldState = BUG_STATE_ACTIVE; newState = BUG_STATE_ACTIVE; } else { HandlerSettings.LogMessage( String.Format( "The 'Assigned To' change can not be done for TR: {0} at same time as state change", workItem.Title), HandlerSettings.LoggingLevel.WARN); } } }
// Return an EnterpriseChangeRequest with mapped values for the update public static EnterpriseChangeRequest mapFromUpdatedWorkitem( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, Uri about, WorkItemChangedEvent notification) { EnterpriseChangeRequest newEcr = new EnterpriseChangeRequest(); newEcr.SetAbout(about); // The notification contain all changed fields. To understand what to // propagate to the client, we need to check which ecm fields that are // affected by the changes and are configured for notifyChange int noOfMappedChanged = 0; if (notification.ChangedFields != null) { // Most fields are String fields StringField[] changedStrFields = notification.ChangedFields.StringFields; if (changedStrFields != null) { for (int i = 0; i < changedStrFields.Length; i++) { String fieldName = changedStrFields[i].ReferenceName; noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName); } } // For example Priority is an Integer field IntegerField[] changedIntFields = notification.ChangedFields.IntegerFields; if (changedIntFields != null) { for (int i = 0; i < changedIntFields.Length; i++) { String fieldName = changedIntFields[i].ReferenceName; noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName); } } } // For example the Description is a Text field TextField[] changedTextFields = notification.TextFields; if (changedTextFields != null) { for (int i = 0; i < changedTextFields.Length; i++) { String fieldName = changedTextFields[i].ReferenceName; noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName); } } // To find a change in the Comment/History one need to look at revision - 1. noOfMappedChanged += mapFromUpdated(workItem, newEcr, TFSMapper.TFS_HISTORY); // Need to send list of attachments in all cases when we have another update. So if we already have // an update (noOfMappedChanged > 0), send - otherwise, check if changed then send. if ((noOfMappedChanged > 0 || TFSMapper.getInstance().hasLinksChanged(workItem))) { noOfMappedChanged += mapFromUpdated(workItem, newEcr, TFSMapper.ERICSSON_DEFECT_HYPERLINK); } if (noOfMappedChanged > 0) { // More than 1 field that was mapped changed return(newEcr); } else { // No field of interest was changed HandlerSettings.LogMessage( String.Format("No mapped fields was updated for: {0}", workItem.Title), HandlerSettings.LoggingLevel.INFO); return(null); } }
int getWorkItemID(WorkItemChangedEvent ev) { try { IntegerField idField = ev.CoreFields.IntegerFields.Where<IntegerField>(field => field.Name.Equals("ID")).FirstOrDefault<IntegerField>(); return idField.NewValue; } catch (Exception) { return 0; } }
private IdentityDescriptor GetIdentityToImpersonate(TeamFoundationRequestContext requestContext, WorkItemChangedEvent workItemChangedEvent) { Uri server = this.GetCollectionUriFromContext(requestContext); var configurationServer = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(server); // TODO: Find a way to read the identity from the server object model instead. IIdentityManagementService identityManagementService = configurationServer.GetService <IIdentityManagementService>(); TeamFoundationIdentity identity = identityManagementService.ReadIdentities( new Guid[] { new Guid(workItemChangedEvent.ChangerTeamFoundationId) }, MembershipQuery.None).FirstOrDefault(); return(identity?.Descriptor); }
public BBIHelper(WorkItemChangedEvent _wice, string tfsUrl, int _bbiNum) { SetWorkItemHelper(_wice, tfsUrl, _bbiNum); }
public NotificationWrapper(NotificationType notification, WorkItemChangedEvent eventArgs) { this.notification = notification; this.eventArgs = eventArgs; }
// Update the connected TR. private void updateTR( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, WorkItemChangedEvent notification, String user, Uri about, ref Status status) { String oldState, newState, action; ECRMapper.getStatusChange(notification, workItem, out oldState, out newState, out action); if (action != null) { if (action.Equals(ECRMapper.ACTION_IGNORE)) { // Ignore all changes return; } if (action.Equals(ECRMapper.ACTION_DUPLICATE)) { // UC 9.4: Duplicate - Find Bug with duplicate id, get attached TR and send action duplicate // Update needs to be done before setting the Bug as Duplicate as the TR can't change after. updateTRFields(workItem, notification, user, about, ref status); EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_DUPLICATE); if (ecr.GetPrimaryTR() == null || ecr.GetPrimaryTR().Length == 0) { // Failed to find a Bug with a connected TR. Log error and return. String msg = String.Format( "Failed to find duplicate to Bug: {0}, or duplicate Bug had not TR Link set", workItem.Title); HandlerSettings.LogMessage(msg, HandlerSettings.LoggingLevel.ERROR); status.ErrorMessage = msg; return; } callUpdateTR(ecr, user, null, ref status); if (!status.OK) { // Log issue, but continue if e.g. a state change HandlerSettings.LogMessage( String.Format("Failed to set TR as duplicate based on Bug: {0}", workItem.Title), HandlerSettings.LoggingLevel.WARN); } // After setting Bug/TR as Duplicated, no futher changes should be propagated. return; } if (action.Equals(ECRMapper.ACTION_UNDUPLICATE)) { // UC 9.4: Unduplicate - Move TR back to Registered by sending action unduplicate EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_UNDUPLICATE); callUpdateTR(ecr, user, null, ref status); if (!status.OK) { // Log issue, but continue if e.g. a state change HandlerSettings.LogMessage( String.Format("Failed to unduplicate TR based on Bug ", workItem.Title), HandlerSettings.LoggingLevel.WARN); } // Update needs to be done after "Unduplicating" the Bug as the TR can't change before. updateTRFields(workItem, notification, user, about, ref status); // Return before handling a possible state change as states can be out of sync // (normal case) when Bug has been Duplicate. Bug then Resolved / Closed, and // TR in an Active state. User needs to set TR state to Active. return; } else if (action.Equals(ECRMapper.ACTION_CHANGE_PRODUCT)) { // UC 10.2: Update of the release - propagate info to TR EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_CHANGE_PRODUCT); bool noProduct = ecr.GetProduct().Length == 0; if (noProduct) { // No product found, so value is for internal release - add message in notebook ecr.SetNotebook("The referenced design item was moved to a product internal to Design"); } callUpdateTR(ecr, user, null, ref status); if (!status.OK) { // Log issue, but continue if e.g. a state change HandlerSettings.LogMessage( String.Format("Failed to change product on TR based on Bug ", workItem.Title), HandlerSettings.LoggingLevel.WARN); } } } updateTRFields(workItem, notification, user, about, ref status); if (newState != null) { // Handle state change updateTRState(workItem, oldState, newState, user, about, ref status);; } }
//private BBIHelper _bbihelper; public HarleysvilleDBIAlerts(WorkItemChangedEvent _wice, TFSIdentity tfsId) { WIChangeEvent = _wice; _dbihelper.SetDBI(_wice, tfsId); SetMailPriority(); }
/// <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); }
public LBIHelper(WorkItemChangedEvent _wice, string tfsUrl) { SetWorkItemHelper(_wice, tfsUrl); }
// Check the Release is or just changed from a maintenance product. // TODO: This is cheating as we have hardcoded knowledge where release field is. // Need to make this fast, but to be correct we should use regular TFSMapper way. public EventType GetEventType( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi, WorkItemChangedEvent notification, String user) { Field createTR = wi.Fields[TFSMapper.ERICSSON_DEFECT_CREATETR]; if (createTR == null || createTR.Value.ToString().Length == 0 || createTR.Value.ToString().Equals("No", StringComparison.OrdinalIgnoreCase)) { return(EventType.Ignore); } // Check project name. If not as defined for product mapping, disregard event. // This allows other projects on TFS server to be non-connected to TR system. if (serviceProvider.Length > 0 && !wi.Project.Name.Equals(serviceProvider, StringComparison.OrdinalIgnoreCase)) { return(EventType.Ignore); } bool inMaint = IsProductInMaintenance(wi); if (inMaint) { // Currenty selected release / product is in maintenance EventType evType = CheckDisconnect(wi, notification, user); if (evType == EventType.Disconnect) { return(EventType.Disconnect); } return(EventType.CreateUpdate); } // ======================================================================== // Check if we just changed from having a product in maintenance. Rare case, // then need to allow severing links and updating state of the workitem. if (notification.ChangeType == ChangeTypes.New) { // Can only happen for a changed WI, not a new. return(EventType.Ignore); } if (notification.ChangedFields == null || notification.ChangedFields.StringFields == null) { // No fields of interest are changed return(EventType.Ignore); } StringField[] changedFields = notification.ChangedFields.StringFields; for (int i = 0; i < changedFields.Length; i++) { String name = changedFields[i].ReferenceName; // If the release is changed, we need to update the TR product // Note: In case we also set to Duplicate, we will disregard product change if (name.Equals(TFSMapper.TFS_FAULTY_PRODUCT)) { String releaseName = changedFields[i].OldValue; if (releaseName == null || releaseName.Length == 0) { // Should not happen - Mapping needs to be initialized HandlerSettings.LogMessage( "Can not tell if product is in maintenance as the Release name not defined.", HandlerSettings.LoggingLevel.WARN); return(EventType.Ignore); } if (releaseToProductMap.ContainsKey(releaseName)) { return(EventType.CreateUpdate); } else { return(EventType.Ignore); } } } return(EventType.Ignore); }
public NotificationWrapper(NotificationType notification, WorkItemChangedEvent eventArgs) { this.notification = notification; this.eventArgs = eventArgs; }
public void SetDBI(WorkItemChangedEvent wice, TFSIdentity tfsId) { _dbi = new DBI(GetDBINumber(wice.CoreFields.IntegerFields), tfsId.Url); this.SetWorkItemHelper(wice, (TFWI)_dbi); _dbiType = GetDBIType(); _state = GetState(); _stateChange = GetStateChangeType(); _targetEnv = GetTargetEnvironment(); if (ChangeType == ChangeTypes.New || !HasBeenAutoFilled() || Check4NewBuildPackage()) { this.AutoFill(); SetBuildNumbersField(); ResetWIFields(); PopBuildNumbersList(); LinkBBIs(); } else { PopBuildNumbersList(); LinkBBIs(); } if (WiFields["New Test Environment"].Equals("Production", StringComparison.CurrentCultureIgnoreCase)) { _isPrd = true; } if ((_state == DBIStates.Ready4IRB || _state == DBIStates.IRBApproved) && _stateChange == WIStateChangeType.New) { _isIRB = true; } }