private static int mapFromUpdated( Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem, EnterpriseChangeRequest newEcr, String fieldName) { int noOfMappedChanged = 0; // TODO: For the "calculated" fields we have defined ourselves we know the // dependencies, but should be expressed more elegant than this. Also the // Ericsson.Defect.User.DisplayName is dependent on System.AssignedTo but // will not be updated - we "know" that ... if (fieldName.Equals(TFSMapper.TFS_OWNER)) { fieldName = TFSMapper.ERICSSON_DEFECT_USER_SIGNUM; } // Can be multiple ECR properties updated by one TFS field List <Property> props = props = AttributesMapper.getInstance().getNotifyProperties(fieldName); if (props != null && props.Count > 0) { foreach (Property prop in props) { if (prop.getNotifyChange() && TFSMapper.getInstance().setEcrValues(newEcr, prop.getKey(), workItem)) { noOfMappedChanged++; } } } return(noOfMappedChanged); }
// =============================================== static public String GetTfsValueForEcrKey(String propertyName, WorkItem workItem) { List <String> values = TFSMapper.getInstance().mapToEcr(propertyName, workItem); if (values.Count == 0) { HandlerSettings.LogMessage( "Missing map entry for 'key': " + propertyName, HandlerSettings.LoggingLevel.INFO); return(""); } else if (values.Count > 1) { HandlerSettings.LogMessage( "More than one value for 'key': " + propertyName, HandlerSettings.LoggingLevel.WARN); } return(values[0]); }
// 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); } }
/// <summary> /// Initiatie application - if fatal error, return false. /// </summary> static public Boolean initFromFile() { if (initiated) { return(initiatedOK); } initiated = true; initiatedOK = false; // ===================================================================== // Get adapterHome and config file - fatal error if not found, report and exit adapterHome = Environment.GetEnvironmentVariable("ADAPTER_HOME_TFS"); if (adapterHome == null || !Directory.Exists(adapterHome)) { // TODO: Is there a reasonable deafult to use here? For now; C:\ + "tfs_adapter". // Note: Can't use the user home as the TFS process normally can't read there adapterHome = "C:\\adapter_home_tfs"; } if (!Directory.Exists(adapterHome)) { throw new DirectoryNotFoundException( String.Format("Failed to find adapter home at: {0}. Exit.", adapterHome)); } // Note: Using the recommended file construct Path.Combine(adapterHome + "properties.xml") // resulted in "C:\\adapter_home_tfsproperties.xml" i.e. not correct. So resort to basic. String configFile = adapterHome + "\\properties.xml"; // Handle re-read of files without need of server reboot. So if missing file is logged, if // adding a file at that location it should be picked up. handleConfigFileChange(ConfigFile.PROPERTIES, configFile); if (!File.Exists(configFile)) { throw new FileNotFoundException( String.Format("Failed to find properties.xml at: {0}. Exit.", configFile)); } // ===================================================================== // Read the configuration file XElement config = null; try { XDocument doc = XDocument.Load(configFile); config = doc.Element("configuration"); } catch (Exception e) { throw new Exception( String.Format("Exception when loading property file {0}. ", configFile), e); } // ===================================================================== // Initiate logging // For logging, log4net is recommended, available e.g. at http://www.nuget.org/packages/log4net/2.0.3 // BUT introduces another dependency, and found no clear examples of using this on server side. So // will use a simpler approach for now. initLogging(config, adapterHome); LogMessage(String.Format("Reading properties from file: {0}", configFile), LoggingLevel.INFO); // ===================================================================== // Get connection settings initiatedOK = initConnectionSettings(config); if (!initiatedOK) { return(initiatedOK); } // ===================================================================== // Read list of Friends initiatedOK = initFriends(config); if (!initiatedOK) { return(initiatedOK); } // ===================================================================== // Read list of Headers for REST call initiatedOK = initHeaders(config); if (!initiatedOK) { return(initiatedOK); } // ===================================================================== // Configure mapping - if mapping not found, fatal error initiatedOK = TFSMapper.initTFSFieldNames(config); if (!initiatedOK) { return(initiatedOK); } initiatedOK = initMapping(config, adapterHome); if (!initiatedOK) { return(initiatedOK); } // ====================================== // Read optional sync status messages XElement noSyncMessageAttr = config.Element("noSyncMessage"); if (noSyncMessageAttr != null) { noSyncMessage = noSyncMessageAttr.Value; } XElement successMessageAttr = config.Element("successMessage"); if (successMessageAttr != null) { successMessage = successMessageAttr.Value; } XElement warningMessageAttr = config.Element("warningMessage"); if (warningMessageAttr != null) { warningMessage = warningMessageAttr.Value; } XElement errorMessageAttr = config.Element("errorMessage"); if (errorMessageAttr != null) { errorMessage = errorMessageAttr.Value; } LogMessage("Read optional sync status messages.", LoggingLevel.INFO); LogMessage( String.Format("Read of properties from file {0} successful.", configFile), LoggingLevel.INFO); initiatedOK = true; return(initiatedOK); }