public static ProductMapper getInstance() { if (instance == null) { instance = new ProductMapper(); } return(instance); }
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; // TODO: Make impact on performance minimal by optimize logic for understanding if we are interested // in this event or not. Also put longer running task in Jobs. For now - do basic checks. if (notificationType != NotificationType.Notification) { return(EventNotificationStatus.ActionPermitted); } var notification = notificationEventArgs as WorkItemChangedEvent; if (notification == null) { return(EventNotificationStatus.ActionPermitted); } // Should not thow exception - if so, the code will be disabled by TFS. try { // Init adapter - will only be done once per deployment of plugin if (!HandlerSettings.initFromFile()) { // Fatal error when trying to init - return // TODO: How allow retry without server restart or re-deploy of plugin? return(EventNotificationStatus.ActionPermitted); } // Handle case where event is fired because of Save we initiated. if (ignoreSaveEvent(notification)) { return(EventNotificationStatus.ActionPermitted); } int workItemId = notification.CoreFields.IntegerFields[0].NewValue; HandlerSettings.LogMessage( String.Format( "WorkItem with id {0} named '{1}' was saved.", "" + workItemId, notification.WorkItemTitle), HandlerSettings.LoggingLevel.INFO); // TODO: In examples I have seen you get actual WI by process below, i.e. opening a new connection to TFS. // I would expect as we already are in the context of a TFS you somehow could use this. Note: There is a // WorkItem class in the namespace Microsoft.TeamFoundation.WorkItemTracking.Server - no documentation found. Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem = getStore().GetWorkItem(workItemId); // If a new item is based on an existing (copied) we need to reset the connection to any existing TR. // Note exception if item is created by the functional user. This to allow test case where TR is set // by test case code. String user = HandlerSettings.GetSignumForChangeNotification(workItem, notification); if (notification.ChangeType == ChangeTypes.New) { if (!user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase)) { // Note: Will not save - done in event handling or at end. ECRMapper.disconnectBug(workItem); } } ProductMapper.EventType eventType = ProductMapper.getInstance().GetEventType(workItem, notification, user); if (eventType == ProductMapper.EventType.CreateUpdate) { // Handle the event as the release is for a maintenance product RESTCallHandler.getHandler().handleEvent(workItem, user, notification); } else if (eventType == ProductMapper.EventType.Disconnect) { // Handle the event as the release is for a maintenance product RESTCallHandler.getHandler().handleDisconnectEvent(workItem, user, notification); } else { HandlerSettings.LogMessage( String.Format( "WorkItem with id {0} save event was ignored by integration.", "" + workItemId), HandlerSettings.LoggingLevel.INFO); } // If updated but not saved, we need to explicitly call save. Very unusual case but will happen // e.g. if item is copied with a product value that before was in maintenance but now not. Then // code to disconnect bug is called, but event not handled or Bug saved, hence save here. if (workItem.IsDirty) { RESTCallHandler.getHandler().saveBug(workItem); } } catch (Exception ex) { // Error when reading mapping file - assume fatal HandlerSettings.LogMessage( "Error when handling the change of workitem." + "\nError: " + ex.Message + "\nStack: " + ex.StackTrace, HandlerSettings.LoggingLevel.ERROR); } return(EventNotificationStatus.ActionPermitted); }
// Update the TR State field for the bug based either on incoming ecr, or if this is null // get the current TR State from the bug. If missing link for a maintenance product or if // having a link for a non-maintenance product, also show this. static public void updateBug(Status status, String user, Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem) { // Check if we are connected when we should be bool isProdInMaint = ProductMapper.getInstance().IsProductInMaintenance(workItem); String currentLink = HandlerSettings.GetIDFromLink(workItem); bool hasLink = currentLink.Length > 0; if (isProdInMaint && (!hasLink && status.TRAbout == null)) { // Error - should have link and nothing in the status.TRAbout so have not created. workItem.Fields[TFSMapper.ERICSSON_DEFECT_STATE_FIELD].Value = trStateToString[TRStateInfo.ErrorMissingTR]; } else if (!isProdInMaint) { // OK - clear any status fields and return ECRMapper.disconnectBug(workItem); return; } else { // OK - prod is in maint and has link - normal case // Check if state is updated String newTrState = null; if (status.TRState != null) { String currentTrState = getTRState(workItem); String updatedTrState = status.TRState; if (!updatedTrState.Equals(currentTrState)) { newTrState = updatedTrState; workItem.Fields[TFSMapper.ERICSSON_DEFECT_STATE_FIELD].Value = newTrState; } } if (status.TRAbout != null) { // We will store the relative path of the "Edit TR" link in the bug, reason being that the Link // that we need to define for the UI to allow click to navigate require a non blank UriRoot value, // see http://msdn.microsoft.com/en-us/library/dd936107.aspx. String updatedLink = HandlerSettings.GetIDFromUri(status.TRAbout.ToString()); if (updatedLink.Length > 0) { if (!currentLink.Equals(updatedLink)) { workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value = updatedLink; } } } } // Put the error and expected state string into system history field String message = status.GetMessage(); // Append any defined guiding message TRSyncState newSyncState = getSyncState(status, workItem); String guidingMessage = ""; switch (newSyncState) { case TRSyncState.SyncStateNone: guidingMessage = HandlerSettings.SyncNoSyncMessage; break; case TRSyncState.SyncStateOK: guidingMessage = HandlerSettings.SyncSuccessMessage; break; case TRSyncState.SyncStateWarning: guidingMessage = HandlerSettings.SyncWarningMessage; break; case TRSyncState.SyncStateError: guidingMessage = HandlerSettings.SyncErrorMessage; break; } if (message.Length > 0 || guidingMessage.Length > 0) { workItem.History = message + ((guidingMessage.Length > 0) ? " " + guidingMessage : ""); } // Put the sync state in the Sync State field String currentSyncStateStr = workItem.Fields[TFSMapper.ERICSSON_DEFECT_SYNCSTATE].Value.ToString(); String newSyncStateStr = trSyncStateToString[newSyncState]; bool incomingChange = user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase); newSyncStateStr = String.Format(newSyncStateStr, incomingChange ? "(in)" : "(out)"); if (!currentSyncStateStr.Equals(trSyncStateToString)) { workItem.Fields[TFSMapper.ERICSSON_DEFECT_SYNCSTATE].Value = newSyncStateStr; } }
private static bool initMapping(XElement config, String adapterHome) { try { attributeMappingFile = config.Element("attributeMappingFile").Attribute("name").Value; attributeMappingFile = replaceRelativePath(adapterHome, attributeMappingFile); handleConfigFileChange(ConfigFile.ATTRIBUTE_MAPPINGS, attributeMappingFile); if (!File.Exists(attributeMappingFile)) { LogMessage( String.Format("Failed to find attribute mapping file at: {0}. Exit.", attributeMappingFile), LoggingLevel.ERROR); return(false); } else if (!AttributesMapper.getInstance().Load(attributeMappingFile, false)) { // Logging of error in Load method return(false); } LogMessage("Attribute mapping file read: " + attributeMappingFile, LoggingLevel.INFO); customerMappingFile = config.Element("customerMappingFile").Attribute("name").Value; customerMappingFile = replaceRelativePath(adapterHome, customerMappingFile); handleConfigFileChange(ConfigFile.CUSTOMER_MAPPINGS, customerMappingFile); if (!File.Exists(customerMappingFile)) { LogMessage( String.Format("Failed to find customer mapping file at: {0}. Exit.", customerMappingFile), LoggingLevel.ERROR); return(false); } else if (!AttributesMapper.getInstance().Load(customerMappingFile, true)) { // Logging of error in Load method return(false); } LogMessage("Customer mapping file read: " + customerMappingFile, LoggingLevel.INFO); productMappingFile = config.Element("productMappingFile").Attribute("name").Value; productMappingFile = replaceRelativePath(adapterHome, productMappingFile); handleConfigFileChange(ConfigFile.PRODUCT_MAPPINGS, productMappingFile); if (!File.Exists(productMappingFile)) { LogMessage( String.Format("Failed to find product mapping file at: {0}. Exit.", productMappingFile), LoggingLevel.ERROR); return(false); } else if (!ProductMapper.getInstance().Load(productMappingFile)) { // Logging of error in Load method return(false); } LogMessage("Product mapping file read: " + productMappingFile, LoggingLevel.INFO); } catch (Exception e) { LogMessage( String.Format("Exception when loading a mapping file: {0}. Exit.", e.Message), LoggingLevel.ERROR); return(false); } return(true); }