private RTSession FindSessionForConflictedAction( MigrationConflict conflict, RuntimeEntityModel context) { // figure out which session the conflicted change action belongs to Guid sessionId = Guid.Empty; if (conflict.ConflictedChangeAction.ChangeGroup == null) { RTChangeGroup rtChangeGroup = FindChangeGroupForConflictedAction(conflict, context); if (null != rtChangeGroup) { sessionId = rtChangeGroup.SessionUniqueId; } } else { sessionId = conflict.ConflictedChangeAction.ChangeGroup.SessionId; } if (sessionId.Equals(Guid.Empty)) { Debug.Assert(false, "cannot find session for the conflicted action"); return(null); } var sessionQuery = context.RTSessionSet.Where(s => s.SessionUniqueId.Equals(sessionId)); if (sessionQuery.Count() > 0) { return(sessionQuery.First()); } else { return(null); } }
public InvalidFieldConflictTypeDetails GetConflictDetails(MigrationConflict conflict) { if (!conflict.ConflictType.ReferenceName.Equals(this.ReferenceName)) { throw new InvalidOperationException(); } if (string.IsNullOrEmpty(conflict.ConflictDetails)) { throw new ArgumentNullException("conflict.ConflictDetails"); } try { // V2 conflict details, i.e. using property bag return(new InvalidFieldConflictTypeDetails(conflict.ConflictDetailsProperties)); } catch (Exception) { GenericSerializer <InvalidFieldConflictTypeDetails> serializer = new GenericSerializer <InvalidFieldConflictTypeDetails>(); return(serializer.Deserialize(conflict.ConflictDetails)); } }
public ConflictResolutionResult Resolve(IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName)) { return(new ConflictResolutionResult(true, ConflictResolutionType.Other)); } else if (rule.ActionRefNameGuid.Equals(new WITUnmappedWITConflictUpdateWITMappingAction().ReferenceName)) { return(ResolveByUsingWITMapping(conflict, rule)); } else if (rule.ActionRefNameGuid.Equals(new WITUnmappedWITConflictExcludeWITInSessionFilter().ReferenceName) || rule.ActionRefNameGuid.Equals(new SkipConflictedActionResolutionAction().ReferenceName)) { conflict.ConflictedChangeAction.ChangeGroup.Status = ChangeStatus.Skipped; conflict.ConflictedChangeAction.State = ActionState.Skipped; return(new ConflictResolutionResult(true, ConflictResolutionType.SkipConflictedChangeAction)); } else { return(new ConflictResolutionResult(false, ConflictResolutionType.Other)); } }
private ConflictResolutionResult ResolveByValueMap(MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; ClearQuestInvalidFieldValueConflictType conflictType = conflict.ConflictType as ClearQuestInvalidFieldValueConflictType; if (null == conflictType) { throw new InvalidOperationException(); } string mapFromValue = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_MapFromValue]; string mapToValue = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_MapToValue]; string targetFieldName = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_TargetFieldName]; // // apply value map to the Action's Description document // XmlDocument desc = conflict.ConflictedChangeAction.MigrationActionDescription; XmlNode column = desc.SelectSingleNode(string.Format( @"/WorkItemChanges/Columns/Column[@ReferenceName=""{0}""]", targetFieldName)); if (column == null) { // defer to migration time to resolve the conflict, mark it as resolved for now return(new ConflictResolutionResult(true, ConflictResolutionType.Other)); } else if (!mapFromValue.Equals(column.FirstChild.InnerText, StringComparison.InvariantCulture)) { return(new ConflictResolutionResult(false, ConflictResolutionType.Other)); } column.FirstChild.InnerText = mapToValue; //note: changes to "MigrationConflict conflict" is saved by the conflict manager automatically return(new ConflictResolutionResult(true, ConflictResolutionType.UpdatedConflictedChangeAction)); }
public virtual ConflictResolutionResult Resolve(IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName)) { return(ManualResolve(conflict, rule, out actions)); } return(new ConflictResolutionResult(false, ConflictResolutionType.Other)); }
/// <summary> /// Try to process the change group, assuming it contains context sync instructions. /// </summary> /// <param name="nextChangeGroup"></param> /// <returns>true if the change group is a context sync group and it has been processed (either successfully or not)</returns> /// <exception cref="MigrationUnresolvedConflictException"></exception> /// <remarks> /// If sync succeeds, the change group will be marked as 'Completed'; otherwise, a conflict /// will be raised and we do not expect it to be auto-resolved. /// </remarks> private bool TryProcessContextSyncChangeGroup(ChangeGroup changeGroup) { // context sync steps must be strictly ordered, although they may not come in expected order // the following logic sorts them bool foundSyncContextAction = true; MigrationAction[] contextSyncActions = new MigrationAction[6]; foreach (MigrationAction action in changeGroup.Actions) { if (action.Action.Equals(WellKnownChangeActionId.SyncContext)) { Debug.Assert(!string.IsNullOrEmpty(action.FromPath)); if (action.ItemTypeReferenceName.Equals(WellKnownContentType.UserGroupList.ReferenceName)) { contextSyncActions[0] = action; } else if (action.ItemTypeReferenceName.Equals(WellKnownContentType.ValueListCollection.ReferenceName)) { contextSyncActions[1] = action; } else if (action.ItemTypeReferenceName.Equals(WellKnownContentType.Tfs2005WorkItemFieldMetadata.ReferenceName) || action.ItemTypeReferenceName.Equals(WellKnownContentType.Tfs2008WorkItemFieldMetadata.ReferenceName)) { contextSyncActions[2] = action; } else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsAreaPathsContentTypeRefName)) { contextSyncActions[3] = action; } else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsIterationPathsContentTypeRefName)) { contextSyncActions[4] = action; } else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsCSSNodeChangesContentTypeRefName)) { contextSyncActions[5] = action; } } else { foundSyncContextAction = false; break; } } if (!foundSyncContextAction) { return(false); } IMigrationAction currSyncAction = null; try { if (contextSyncActions[0] != null) { currSyncAction = contextSyncActions[0]; SyncUserAccount(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy); } if (contextSyncActions[1] != null) { currSyncAction = contextSyncActions[1]; SyncGlobalList(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy); } if (contextSyncActions[2] != null) { currSyncAction = contextSyncActions[2]; SyncWorkItemTypeDefinition(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy); } if (contextSyncActions[3] != null && !m_migrationSource.WorkItemStore.Core.DisableAreaPathAutoCreation) { // keep for backward compatibility only (replaced by SyncCSSNodeChanges) currSyncAction = contextSyncActions[3]; SyncAreaPaths(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy); } if (contextSyncActions[4] != null && !m_migrationSource.WorkItemStore.Core.DisableIterationPathAutoCreation) { // keep for backward compatibility only (replaced by SyncCSSNodeChanges) currSyncAction = contextSyncActions[4]; SyncIterationPaths(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy); } if (contextSyncActions[5] != null) { currSyncAction = contextSyncActions[5]; SyncCSSNodeChanges( currSyncAction.MigrationActionDescription, m_migrationSource.WorkItemStore.Core.DisableAreaPathAutoCreation, m_migrationSource.WorkItemStore.Core.DisableIterationPathAutoCreation); } changeGroup.Status = ChangeStatus.Complete; changeGroup.Save(); return(true); } catch (Exception ex) { if (!(ex is MigrationUnresolvedConflictException)) { TraceManager.TraceError(ex.ToString()); // backlog the conflict context sync action/group MigrationConflict genericeConflict = InvalidSubmissionConflictType.CreateConflict( currSyncAction, ex, currSyncAction.ChangeGroup.Name, currSyncAction.ChangeGroup.Name); var conflictManager = m_conflictManagementService.GetService(typeof(ConflictManager)) as ConflictManager; Debug.Assert(null != conflictManager); List <MigrationAction> resolutionActions; ConflictResolutionResult resolveRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, genericeConflict, out resolutionActions); Debug.Assert(!resolveRslt.Resolved); return(true); } else { throw; } } }
public override System.Collections.ObjectModel.ReadOnlyCollection <LinkChangeGroup> GenerateNextLinkDeltaSlice( LinkService linkService, int maxDeltaSliceSize) { try { var linkChangeGroups = new List <LinkChangeGroup>(); if (null == ExtractLinkChangeActionsCallback) { return(linkChangeGroups.AsReadOnly()); } // load main Highwater Mark m_hwmLink.Reload(); DateTime hwmLinkValue = m_hwmLink.Value; // search back 60 seconds to deal with potential WIT race condition if (!hwmLinkValue.Equals(default(DateTime))) { hwmLinkValue = hwmLinkValue.AddSeconds(-60); } string hwmLinkValueStr = hwmLinkValue.ToString(CultureInfo.InvariantCulture); // load Work Items for extracting links string sourceId = m_migrationSource.UniqueId; string storeName = m_migrationSource.WorkItemStore.StoreName; // Get items based on primary Highwater Mark TraceManager.TraceInformation(TfsWITAdapterResources.GettingModifiedItems, sourceId, storeName); IEnumerable <TfsMigrationWorkItem> items = m_migrationSource.WorkItemStore.GetItems(ref hwmLinkValueStr); TraceManager.TraceInformation(TfsWITAdapterResources.ReceivedModifiedItems, sourceId, storeName); // Record the updated HWM value DateTime wiqlExecutionTime = Convert.ToDateTime(hwmLinkValueStr, CultureInfo.InvariantCulture); // store to be used to analyze deleted links WorkItemLinkStore store = new WorkItemLinkStore(new Guid(sourceId)); // extract links DateTime lastWorkITemUpdateTime = DateTime.MinValue; var inMaxDeltaSliceSize = maxDeltaSliceSize; foreach (TfsMigrationWorkItem tfsMigrationWorkItem in items) { if (tfsMigrationWorkItem.WorkItem == null) { continue; } TraceManager.TraceInformation("Generating linking delta for Work Item: {0}", tfsMigrationWorkItem.WorkItem.Id.ToString()); var detectedLinkChangeGroups = new List <LinkChangeGroup>(); ExtractLinkChangeActionsCallback(tfsMigrationWorkItem, detectedLinkChangeGroups, store); if (detectedLinkChangeGroups.Count == 0) { TraceManager.TraceInformation("Number of links: {0}", 0); continue; } Dictionary <string, LinkChangeGroup> perWorkItemConsolidatedLinkChangeGroup = new Dictionary <string, LinkChangeGroup>(); for (int i = 0; i < detectedLinkChangeGroups.Count; ++i) { foreach (LinkChangeAction action in detectedLinkChangeGroups[i].Actions) { if (!perWorkItemConsolidatedLinkChangeGroup.ContainsKey(action.Link.SourceArtifact.Uri)) { var linkChangeGroup = new LinkChangeGroup( action.Link.SourceArtifactId, LinkChangeGroup.LinkChangeGroupStatus.Created, false); perWorkItemConsolidatedLinkChangeGroup.Add(action.Link.SourceArtifact.Uri, linkChangeGroup); } perWorkItemConsolidatedLinkChangeGroup[action.Link.SourceArtifact.Uri].AddChangeAction(action); } } // always make sure that the currently analyzed work item has a link change group to represent it // even though the group can be empty if (!perWorkItemConsolidatedLinkChangeGroup.ContainsKey(tfsMigrationWorkItem.Uri)) { perWorkItemConsolidatedLinkChangeGroup.Add( tfsMigrationWorkItem.Uri, new LinkChangeGroup(TfsWorkItemHandler.IdFromUri(tfsMigrationWorkItem.Uri), LinkChangeGroup.LinkChangeGroupStatus.Created, false)); } foreach (var workItemLinkGroup in perWorkItemConsolidatedLinkChangeGroup) { string workItemIdStr = TfsWorkItemHandler.IdFromUri(workItemLinkGroup.Key); TraceManager.TraceInformation("Detected {0} links for Work Item '{1}'", workItemLinkGroup.Value.Actions.Count, workItemIdStr); if (workItemLinkGroup.Key.Equals(tfsMigrationWorkItem.Uri, StringComparison.OrdinalIgnoreCase)) { // VERY IMPORTANT: use the RelatedArtifactsStore to detect link deletion store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords( workItemLinkGroup.Key, workItemLinkGroup.Value, this); } else { store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecordsWithoutImplicitDelete( workItemLinkGroup.Key, workItemLinkGroup.Value, this); } if (workItemLinkGroup.Value.Actions.Count > 0) { linkChangeGroups.Add(workItemLinkGroup.Value); } maxDeltaSliceSize -= workItemLinkGroup.Value.Actions.Count; if (maxDeltaSliceSize <= 0) { // size limit reached - persist groups to DB linkService.AddChangeGroups(linkChangeGroups); linkChangeGroups.Clear(); maxDeltaSliceSize = inMaxDeltaSliceSize; } } DateTime lastRevChangedDate = tfsMigrationWorkItem.WorkItem.ChangedDate; if (lastWorkITemUpdateTime.CompareTo(lastRevChangedDate) <= 0) { lastWorkITemUpdateTime = lastRevChangedDate; } } // persist remaining groups to DB linkService.AddChangeGroups(linkChangeGroups); // clean up the returned link change group collection // when the caller (toolkit) receives an empty collection, it understands there is no more // delta to generate for the moment, and proceeds to next phase linkChangeGroups.Clear(); // update primary Highwater Mark //m_hwmLink.Update(newHwmLinkValue); string newHwmValueStr = hwmLinkValueStr; if (lastWorkITemUpdateTime.Equals(DateTime.MinValue)) { // no changes in this sync cycle, record the wiql query execution time m_hwmLink.Update(wiqlExecutionTime); } else { // hwm is recorded in UTC, so does the WIQL query asof time lastWorkITemUpdateTime = lastWorkITemUpdateTime.ToUniversalTime(); if (lastWorkITemUpdateTime.CompareTo(wiqlExecutionTime) <= 0) { // last work item rev time is earlier than wiql query execution time, use it as hwm m_hwmLink.Update(lastWorkITemUpdateTime); newHwmValueStr = lastWorkITemUpdateTime.ToString(); } else { m_hwmLink.Update(wiqlExecutionTime); } } TraceManager.TraceInformation("Persisted WIT linking HWM: {0}", Toolkit.Constants.HwmDeltaLink); TraceManager.TraceInformation(TfsWITAdapterResources.UpdatedHighWatermark, newHwmValueStr); return(linkChangeGroups.AsReadOnly()); } catch (Exception exception) { MigrationConflict genericeConflict = WitGeneralConflictType.CreateConflict(exception); var conflictManager = m_conflictManager.GetService(typeof(ConflictManager)) as ConflictManager; Debug.Assert(null != conflictManager); List <MigrationAction> resolutionActions; ConflictResolutionResult resolveRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, genericeConflict, out resolutionActions); Debug.Assert(!resolveRslt.Resolved); return(new List <LinkChangeGroup>().AsReadOnly()); } }
private bool SubmitBatchedAddOrDeleteLinkChanges( List <XmlDocument> updateDocuments, Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap, ITranslationService translationService, ConfigurationService configService, ConflictManager conflictManager) { bool succeeded = true; UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray()); if (results.Length != updateDocuments.Count) { throw new SynchronizationEngineException("Wrong number of link update results."); } // Collect list of successful LinkChangeActions (for LinkTypes with GetsActionsFromLinkChangeHistory true) to pass to SetServerLinkChangeIds() List <LinkChangeAction> actionsNeedingServerLinkIdSet = new List <LinkChangeAction>(); for (int i = 0; i < results.Length; ++i) { UpdateResult rslt = results[i]; if (rslt.Exception != null) { if (rslt.Exception.Message.Contains("The specified link already exists")) { // it is ok to eat this exception // mark the change action completed so it is not retried later LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i]; action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped; TraceManager.TraceInformation("Tried to add a link that already exists so skipping it: " + GetLinkChangeActionDescription(action)); System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException; if (soapException != null) { TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml); } } else if (updateDocIndexToLinkChangeActionMap[i].ChangeActionId == WellKnownChangeActionId.Delete && rslt.Exception.Message.Contains("This specified link does not exist")) { // it is ok to eat this exception and skip the action // mark the change action completed so it is not retried later LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i]; action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped; TraceManager.TraceInformation("Tried to delete a link that does not exist so skipping it: " + GetLinkChangeActionDescription(action)); System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException; if (soapException != null) { TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml); } } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSMulitpleParentLinkConflictType.SingleParentViolationMessage, StringComparison.OrdinalIgnoreCase)) { MigrationConflict conflict = TFSMulitpleParentLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSCyclicLinkConflictType.CircularityLinkHierarchyViolationMessage, StringComparison.OrdinalIgnoreCase)) { ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider; Debug.Assert(null != linkProvider, "linkProvider is NULL"); LinkChangeAction conflictedAction = updateDocIndexToLinkChangeActionMap[i]; NonCyclicReferenceClosure linkRefClosure = linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact); MigrationConflict conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSModifyLockedWorkItemLinkConflictType.ModifyLockedWorkItemLinkViolationMessage, StringComparison.OrdinalIgnoreCase)) { MigrationConflict conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && (rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage1, StringComparison.OrdinalIgnoreCase) || rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage2, StringComparison.OrdinalIgnoreCase))) { MigrationConflict conflict = TFSLinkAccessViolationConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; } else { LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i]; // TODO // Try resolve conflict and push to backlog if resolution fails action.IsConflicted = true; TraceManager.TraceError(String.Format(CultureInfo.InvariantCulture, "Exception processing {0}: {1}", GetLinkChangeActionDescription(action), rslt.Exception.ToString())); succeeded = false; } } else // rslt.Exception == null { LinkChangeAction successfulAction = updateDocIndexToLinkChangeActionMap[i]; MarkLinkChangeActionCompleted(successfulAction); TraceManager.TraceVerbose("Successful " + GetLinkChangeActionDescription(successfulAction)); List <LinkChangeAction> updatedActions = new List <LinkChangeAction>(); updatedActions.Add(successfulAction); if (successfulAction.Link.LinkType.GetsActionsFromLinkChangeHistory) { actionsNeedingServerLinkIdSet.Add(successfulAction); } UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions); } } SetServerLinkChangeIds(actionsNeedingServerLinkIdSet); return(succeeded); }
public ConflictResolutionResult Resolve(System.ComponentModel.Design.IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName)) { return(ManualResolve(conflict, rule, out actions)); } else if (rule.ActionRefNameGuid.Equals(new SkipConflictedActionResolutionAction().ReferenceName)) { return(SkipConflictedAction(conflict, rule, out actions)); } return(new ConflictResolutionResult(false, ConflictResolutionType.Other)); }
private void AddRecord(IMigrationAction action, ConversionResult convRslt) { string recordType = UtilityMethods.ExtractRecordType(action); OAdEntity newRecord = CQWrapper.BuildEntity(m_userSession, recordType); string validationRsltString = string.Empty; List <string> processedFields = new List <string>(); #region add new record with MANDATORY field values if (!SetMandatoryFields(action, ref newRecord, out processedFields)) { return; } bool unResolvedConflictExists = false; bool validationErrorExists = false; validationRsltString = CQWrapper.Validate(newRecord); if (!string.IsNullOrEmpty(validationRsltString)) { validationErrorExists = true; IEnumerable <CQTextParser.RecordValidationResult> validationResults; if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults)) { foreach (CQTextParser.RecordValidationResult rslt in validationResults) { MigrationConflict conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action); List <MigrationAction> actions; var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { unResolvedConflictExists = true; break; } } } else { throw new InvalidOperationException(validationRsltString); } } if (unResolvedConflictExists) { return; } else if (validationErrorExists) { // All conflicts are resolved. Try re-applying the changes newRecord.Revert(); SetRecordEditable(newRecord); if (!SetMandatoryFields(action, ref newRecord, out processedFields)) { return; } else { validationRsltString = CQWrapper.Validate(newRecord); if (!string.IsNullOrEmpty(validationRsltString)) { IEnumerable <CQTextParser.RecordValidationResult> validationResults; if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults) && validationResults.Count() > 0) { CQTextParser.RecordValidationResult rslt = validationResults.First(); MigrationConflict conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action); m_conflictManagerService.BacklogUnresolvedConflict(m_conflictManagerService.SourceId, conflict, false); return; } else { throw new InvalidOperationException(validationRsltString); } } } } validationRsltString = CQWrapper.Commmit(newRecord); if (!string.IsNullOrEmpty(validationRsltString)) { // [teyang] TODO: invalid update conflict handling throw new InvalidOperationException(validationRsltString); } string newRecordDisplayName = CQWrapper.GetEntityDisplayName(newRecord); if (action.State == ActionState.Pending) { action.State = ActionState.Complete; } UpdateConversionHistory(action, newRecordDisplayName, ClearQuestRecordItem.NewRecordVersion, convRslt); #endregion #region update the new record with remaining field values ModifyRecordContent(newRecord, action, convRslt, processedFields); #endregion }
private ConflictResolutionResult ResolveByIncreasingMaxAttchSetting(MigrationConflict conflict, ConflictResolutionRule rule) { throw new NotImplementedException(); }
public bool CanResolve(MigrationConflict conflict, ConflictResolutionRule rule) { return(ConflictTypeHandled.ScopeInterpreter.IsInScope(conflict.ScopeHint, rule.ApplicabilityScope)); }
private ConflictResolutionResult ResolveBySubmitMissingChanges( IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; var retVal = new ConflictResolutionResult(false, ConflictResolutionType.Other); WITTranslationService translationService = serviceContainer.GetService(typeof(ITranslationService)) as WITTranslationService; Debug.Assert(null != translationService, "translationService is not initialized or not a wit translation service"); using (RuntimeEntityModel context = RuntimeEntityModel.CreateInstance()) { RTSessionGroup rtSessionGroup = FindSessionGroupForConflictedAction(conflict, context); if (null == rtSessionGroup) { return(retVal); } BM.BusinessModelManager bmm = new BM.BusinessModelManager(); BM.Configuration sessionGroupConfig = bmm.LoadConfiguration(rtSessionGroup.GroupUniqueId); // find target-side migration source config var parentChangeGroup = FindChangeGroupForConflictedAction(conflict, context); Guid targetMigrationSourceId = parentChangeGroup.SourceUniqueId; BM.MigrationSource targetMigrationSourceConfig = sessionGroupConfig.SessionGroup.MigrationSources[targetMigrationSourceId]; if (null == targetMigrationSourceConfig) { return(retVal); } // find source-side migration source config RTSession rtSession = FindSessionForConflictedAction(conflict, context); BM.Session parentSession = null; foreach (BM.Session s in sessionGroupConfig.SessionGroup.Sessions.Session) { if (new Guid(s.SessionUniqueId).Equals(rtSession.SessionUniqueId)) { parentSession = s; break; } } if (parentSession == null) { return(retVal); } Guid sourceMigrationSourceId = ((new Guid(parentSession.LeftMigrationSourceUniqueId)).Equals(targetMigrationSourceId)) ? new Guid(parentSession.RightMigrationSourceUniqueId) : new Guid(parentSession.LeftMigrationSourceUniqueId); BM.MigrationSource sourceMigrationSourceConfig = sessionGroupConfig.SessionGroup.MigrationSources[sourceMigrationSourceId]; if (null == sourceMigrationSourceConfig) { return(retVal); } string sourceServerUrl = sourceMigrationSourceConfig.ServerUrl; string sourceTeamProject = sourceMigrationSourceConfig.SourceIdentifier; string targetServerUrl = targetMigrationSourceConfig.ServerUrl; string targetTeamProject = targetMigrationSourceConfig.SourceIdentifier; string srcWorkItemIdStr = TfsMigrationWorkItemStore.GetSourceWorkItemId(conflict.ConflictedChangeAction); Debug.Assert(!string.IsNullOrEmpty(srcWorkItemIdStr), "srcWorkItemId is null or empty"); int srcWorkItemId; if (!int.TryParse(srcWorkItemIdStr, out srcWorkItemId)) { return(retVal); } string srcRevRanges = rule.DataFieldDictionary[HistoryNotFoundSubmitMissingChangesAction.DATAKEY_REVISION_RANGE]; int[] sourceRevToSync = new int[0]; if (string.IsNullOrEmpty(srcRevRanges)) { sourceRevToSync = ExtractMissingRevs(conflict.ConflictedChangeAction); } else { if (!IntegerRange.TryParseRangeString(srcRevRanges, out sourceRevToSync)) { return(retVal); } } if (sourceRevToSync.Length == 0) { return(retVal); } try { // compute delta from source side TfsWITAnalysisProvider analysisProvider = new TfsWITAnalysisProvider(sourceServerUrl, sourceTeamProject); WorkItem sourceWorkItem = analysisProvider.GetWorkItem(srcWorkItemId); Hist.MigrationAction[] sourceRevDetails = new Hist.MigrationAction[sourceRevToSync.Length]; for (int revIndex = 0; revIndex < sourceRevToSync.Length; ++revIndex) { var details = new TfsWITRecordDetails(sourceWorkItem, sourceRevToSync[revIndex]); SanitizeDetails(details); translationService.MapWorkItemTypeFieldValues( sourceWorkItem.Id.ToString(), details.DetailsDocument, sourceMigrationSourceId); TfsConstants.ChangeActionId actionId = (sourceRevToSync[revIndex] == 1 ? TfsConstants.ChangeActionId.Add : TfsConstants.ChangeActionId.Edit); sourceRevDetails[revIndex] = new Hist.MigrationAction(sourceWorkItem.Id.ToString(), details, actionId); } // migrate to target side TfsWITMigrationProvider migrationProvider = new TfsWITMigrationProvider(targetServerUrl, targetTeamProject, string.Empty); Hist.ConversionResult conversionResult = migrationProvider.ProcessChangeGroup(sourceRevDetails); // update conversion history ConversionResult convRslt = new ConversionResult(sourceMigrationSourceId, targetMigrationSourceId); convRslt.ChangeId = HistoryNotFoundResolutionChangeId; convRslt.ContinueProcessing = true; foreach (var itemConvHist in conversionResult.ItemConversionHistory) { convRslt.ItemConversionHistory.Add(new ItemConversionHistory( itemConvHist.SourceItemId, itemConvHist.SourceItemVersion, itemConvHist.TargetItemId, itemConvHist.TargetItemVersion)); } parentChangeGroup.SessionRunReference.Load(); int sessionRunId = parentChangeGroup.SessionRun.Id; convRslt.Save(sessionRunId, sourceMigrationSourceId); } catch (Exception ex) { TraceManager.TraceException(ex); retVal.Comment = ex.ToString(); return(retVal); } } retVal.Resolved = true; return(retVal); }
/// <summary> /// Try handling an exception /// </summary> /// <param name="e"></param> /// <param name="conflictManager"></param> /// <returns>The decision returned is either RoutedAsError or RaisedAsRuntimeConflict</returns> public ErrorHandlingResult TryHandleException(Exception e, ConflictManager conflictManager) { bool conflictManagementIsEnabled = (null != conflictManager); bool anErrorRouterIsFound = false; bool exceptionIsRoutedAsError = false; foreach (ErrorRouter errRouter in m_errRegService.RegisteredRouters) { ErrorHandlingResult rslt = errRouter.TryRouteError(e, this.m_routingChannels.AsReadOnly()); switch (rslt.Decision) { case ErrorHandlingResult.RoutingDecision.RaisedAsRuntimeConflict: anErrorRouterIsFound = true; exceptionIsRoutedAsError = true; break; case ErrorHandlingResult.RoutingDecision.PolicyConditionIsNotMet: anErrorRouterIsFound = true; break; case ErrorHandlingResult.RoutingDecision.RoutedAsError: return(rslt); default: break; } if (anErrorRouterIsFound || exceptionIsRoutedAsError) { break; } } if (exceptionIsRoutedAsError) { return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RoutedAsError)); } if (conflictManagementIsEnabled) { MigrationConflict conflict = GenericConflictType.CreateConflict(e); List <MigrationAction> actions; conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RaisedAsRuntimeConflict)); } else if (anErrorRouterIsFound) { // no conflict manager to log the runtime conflict throw new MissingErrorRouterException( "Runtime error does not meet the error routine policy and there is no conflict manager to log a conflict.", e); } else { // no conflict manager is present to raise the error as a runtime conflict // - default to report as an error foreach (IErrorRoutingChannel channel in m_routingChannels) { channel.RouteError(e); } return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RoutedAsError)); } }
private bool SubmitBatchedAddOrDeleteLinkChanges( List <XmlDocument> updateDocuments, Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap, ITranslationService translationService, ConfigurationService configService, ConflictManager conflictManager) { bool succeeded = true; UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray()); if (results.Length != updateDocuments.Count) { throw new SynchronizationEngineException("Wrong number of link update results."); } for (int i = 0; i < results.Length; ++i) { UpdateResult rslt = results[i]; if (rslt.Exception != null) { if (rslt.Exception.Message.Contains("The specified link already exists")) { // it is ok to eat this exception } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSMulitpleParentLinkConflictType.SingleParentViolationMessage, StringComparison.OrdinalIgnoreCase)) { MigrationConflict conflict = TFSMulitpleParentLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSCyclicLinkConflictType.CircularityLinkHierarchyViolationMessage, StringComparison.OrdinalIgnoreCase)) { ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider; Debug.Assert(null != linkProvider, "linkProvider is NULL"); LinkChangeAction conflictedAction = updateDocIndexToLinkChangeActionMap[i]; NonCyclicReferenceClosure linkRefClosure = linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact); MigrationConflict conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && rslt.Exception.Message.StartsWith( TFSModifyLockedWorkItemLinkConflictType.ModifyLockedWorkItemLinkViolationMessage, StringComparison.OrdinalIgnoreCase)) { MigrationConflict conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; } else if (rslt.Exception is System.Web.Services.Protocols.SoapException && null != rslt.Exception.Message && (rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage1, StringComparison.OrdinalIgnoreCase) || rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage2, StringComparison.OrdinalIgnoreCase))) { MigrationConflict conflict = TFSLinkAccessViolationConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); List <MigrationAction> actions; var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; } else { TraceManager.TraceError(rslt.Exception.ToString()); succeeded = false; // TODO // Try resolve conflict and push to backlog if resolution fails updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } } else { foreach (LinkChangeAction action in updateDocIndexToLinkChangeActionMap.Values) { MarkLinkChangeActionCompleted(action); } List <LinkChangeAction> updatedActions = new List <LinkChangeAction>(updateDocIndexToLinkChangeActionMap.Values); if (rslt.Exception == null) { UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions); } else if (rslt.Exception.Message.Contains("The specified link already exists")) { WorkItemLinkStore relatedArtifactsStore = new WorkItemLinkStore(configService.SourceId); relatedArtifactsStore.UpdateSyncedLinks(updatedActions); } } } return(succeeded); }
private bool SubmitBatchedAddOrDeleteLinkChanges( List <XmlDocument> updateDocuments, Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap, ITranslationService translationService, ConfigurationService configService, ConflictManager conflictManager) { bool succeeded = true; UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray()); if (results.Length != updateDocuments.Count) { throw new SynchronizationEngineException("Wrong number of link update results."); } // Collect list of successful LinkChangeActions (for LinkTypes with GetsActionsFromLinkChangeHistory true) to pass to SetServerLinkChangeIds() List <LinkChangeAction> actionsNeedingServerLinkIdSet = new List <LinkChangeAction>(); for (int i = 0; i < results.Length; ++i) { if (results[i] == null) { continue; } UpdateResult rslt = results[i]; if (rslt.Exception != null) { MigrationConflict conflict = null; ConflictResolutionResult resolutionRslt = null; List <MigrationAction> actions; bool createWitGeneralConflict = false; System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException; if (soapException != null) { int?tfsErrorNumber = GetTfsErrorNumberFromSoapException(soapException); if (tfsErrorNumber.HasValue) { LinkChangeAction linkChangeAction = updateDocIndexToLinkChangeActionMap[i]; switch (tfsErrorNumber) { case TfsConstants.TfsError_AddLink_LinkExists: case TfsConstants.TfsError_DeleteLink_LinkNotFound: // it is ok to eat these exception and skip the action // mark the change action completed so it is not retried later linkChangeAction.Status = LinkChangeAction.LinkChangeActionStatus.Skipped; if (tfsErrorNumber == TfsConstants.TfsError_AddLink_LinkExists) { TraceManager.TraceInformation("Tried to add a link that already exists so skipping it: " + GetLinkChangeActionDescription(linkChangeAction)); } else { TraceManager.TraceInformation("Tried to delete a link that does not exist so skipping it: " + GetLinkChangeActionDescription(linkChangeAction)); } if (soapException.Detail != null) { TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml); } break; case TfsConstants.TfsError_AddLink_TooManyParents: if (linkChangeAction.Group.IsForcedSync) { if (DeleteExistingParentLinkToForceSyncAddLink(linkChangeAction, updateDocuments[i])) { break; } } conflict = TFSMulitpleParentLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } break; case TfsConstants.TfsError_AddLink_Circular: case TfsConstants.TfsError_AddLink_ChildIsAncestor: ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider; Debug.Assert(null != linkProvider, "linkProvider is NULL"); LinkChangeAction conflictedAction = updateDocIndexToLinkChangeActionMap[i]; NonCyclicReferenceClosure linkRefClosure = linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact); conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure); resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } break; case TfsConstants.TfsError_LinkAuthorizationFailedLinkLocked: conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; break; case TfsConstants.TfsError_LinkAuthorizationFailed: case TfsConstants.TfsError_LinkAuthorizationFailedNotServiceAccount: conflict = TFSLinkAccessViolationConflictType.CreateConflict( updateDocIndexToLinkChangeActionMap[i], rslt.Exception); resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; } // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status succeeded = false; break; default: // TFS error doesn't match any that we explicitly handle TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges:TFS error number in SoapException not explictly handled: {0}", tfsErrorNumber); createWitGeneralConflict = true; break; } } else { TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges: Unable to get TFS error number from SoapException: {0}", soapException.ToString()); createWitGeneralConflict = true; } } else // Exception is not SoapException { TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges: Exception returned is not SoapException: {0}", rslt.Exception.ToString()); createWitGeneralConflict = true; } if (createWitGeneralConflict) { conflict = WitGeneralConflictType.CreateConflict(rslt.Exception); resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { updateDocIndexToLinkChangeActionMap[i].IsConflicted = true; succeeded = false; } } } else // rslt.Exception == null { LinkChangeAction successfulAction = updateDocIndexToLinkChangeActionMap[i]; MarkLinkChangeActionCompleted(successfulAction); TraceManager.TraceVerbose("Successful " + GetLinkChangeActionDescription(successfulAction)); List <LinkChangeAction> updatedActions = new List <LinkChangeAction>(); updatedActions.Add(successfulAction); if (successfulAction.Link.LinkType.GetsActionsFromLinkChangeHistory) { actionsNeedingServerLinkIdSet.Add(successfulAction); } UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions); } } SetServerLinkChangeIds(actionsNeedingServerLinkIdSet); return(succeeded); }
public ConflictResolutionResult Resolve(System.ComponentModel.Design.IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions) { actions = null; return(new ConflictResolutionResult(false, ConflictResolutionType.Other)); }
private void analyzeFolder(string rootPath, int versionToBeSynced, ChangeGroup changeGroup) { Dictionary <string, bool> localFileItems = new Dictionary <string, bool>(); Dictionary <string, bool> localDirectoryItems = new Dictionary <string, bool>(); Dictionary <string, bool> addItems = new Dictionary <string, bool>(); Dictionary <string, bool> deleteItems = new Dictionary <string, bool>(); string destinationTfsRootPath = TranslationService.GetMappedPath(rootPath, m_configurationService.SourceId); if (Directory.Exists(rootPath)) { foreach (string path in Directory.GetDirectories(rootPath, "*", SearchOption.AllDirectories)) { localDirectoryItems.Add(path, false); } localDirectoryItems.Add(rootPath, false); foreach (string path in Directory.GetFiles(rootPath, "*", SearchOption.AllDirectories)) { localFileItems.Add(path, false); } } else if (File.Exists(rootPath)) { localFileItems.Add(rootPath, false); } else { MigrationConflict deleteAllConfirmationConflict = VCUserPromptConflictType.CreateConflict( string.Format("After comparing the local system with TFS, the folder {0} and all its sub items will be deleted on TFS server. Please choose 'Delete' to continue with the delete; or retry the migration once the local file system is ready.", destinationTfsRootPath), versionToBeSynced.ToString()); List <MigrationAction> retActions; ConflictResolutionResult resolutionResult = m_conflictManagementService.TryResolveNewConflict(m_configurationService.SourceId, deleteAllConfirmationConflict, out retActions); if ((!resolutionResult.Resolved) || (resolutionResult.ResolutionType != ConflictResolutionType.SkipConflictedChangeAction)) { markChangeGroupAsObsolete(changeGroup); throw new MigrationUnresolvedConflictException(deleteAllConfirmationConflict); } } // We need a related branch that should be treated as the source for branches and merges. // TODO: Right now we assume this is the first parent that we find. There should be a way to configure this. List <String> parents = m_branchConfiguration.GetRIList(rootPath); String parentRootPath = (parents == null) ? null : parents[0]; TfsFileSystemRelatedBranchView relatedBranchView = new TfsFileSystemRelatedBranchView(rootPath, parentRootPath); ItemSet tfsItemSet; tfsItemSet = m_destinationTfs.GetItems(destinationTfsRootPath, new ChangesetVersionSpec(versionToBeSynced), RecursionType.Full); foreach (Item item in tfsItemSet.Items) { string localPath = TranslationService.GetMappedPath(item.ServerItem, m_configurationService.MigrationPeer); if (item.ItemType == ItemType.File) { if (localFileItems.ContainsKey(localPath)) { localFileItems[localPath] = true; // Consolidate the computation of MD5 hash in toolkit if (!Utils.ContentsMatch(localPath, item.HashValue)) { createMigrationAction(changeGroup, WellKnownChangeActionId.Edit, localPath, false); // If the contents in the edited file match the contents of the related file in the source branch // then we should pend a merge String relatedBranchItem; if (relatedBranchView.TryGetRelatedBranchItem(localPath, false, out relatedBranchItem) && Utils.ContentsMatch(localPath, relatedBranchItem)) { createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Merge, relatedBranchItem, localPath, false); } } } else { deleteItems.Add(localPath, false); } } else { if (localDirectoryItems.ContainsKey(localPath)) { localDirectoryItems[localPath] = true; } else { deleteItems.Add(localPath, true); } } } // Now add all directory items exist only on local system. foreach (KeyValuePair <string, bool> localItem in localDirectoryItems) { if (!localItem.Value) { String relatedBranchItem; if (relatedBranchView.TryGetRelatedBranchItem(localItem.Key, true, out relatedBranchItem)) { // Create the branch. Since we are dealing with folders we don't need to worry about // pending edits for different content. createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Branch, relatedBranchItem, localItem.Key, true); } else { addItems.Add(localItem.Key, true); } } } // Now add all file items exist only on local system. foreach (KeyValuePair <string, bool> localItem in localFileItems) { if (!localItem.Value) { String relatedBranchItem; if (relatedBranchView.TryGetRelatedBranchItem(localItem.Key, false, out relatedBranchItem)) { // Create the branch. createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Branch, relatedBranchItem, localItem.Key, false); // If the contents of the file we are branching from and our local item are different // then we will need to pend an edit as well. if (!Utils.ContentsMatch(localItem.Key, relatedBranchItem)) { createMigrationAction(changeGroup, WellKnownChangeActionId.Edit, localItem.Key, false); } } else { addItems.Add(localItem.Key, false); } } } if ((deleteItems.Count > 0) && (!m_renameListUpdated)) { m_renameList = GetRenameList(); } List <string> deleteItemToBeRemoved = new List <string>(); if (m_renameList != null && m_renameList.Count > 0) { foreach (string deleteItem in deleteItems.Keys) { string ancestryPath = deleteItem; while (!Path.Equals(rootPath, ancestryPath)) { if (m_renameList.ContainsKey(ancestryPath)) { string renameToAncestryPath = m_renameList[ancestryPath]; string renameToPath = string.Concat(renameToAncestryPath, deleteItem.Substring(ancestryPath.Length)); if (addItems.ContainsKey(renameToPath)) { createRenameMigrationAction(changeGroup, deleteItem, renameToPath, deleteItems[deleteItem]); addItems.Remove(renameToPath); deleteItemToBeRemoved.Add(deleteItem); break; } } ancestryPath = Path.GetDirectoryName(ancestryPath); } } } foreach (string addItem in addItems.Keys) { createMigrationAction(changeGroup, WellKnownChangeActionId.Add, addItem, addItems[addItem]); } foreach (string deleteItem in deleteItems.Keys) { // We have already transferred this delete to a rename, just continue. if (deleteItemToBeRemoved.Contains(deleteItem)) { continue; } createMigrationAction(changeGroup, WellKnownChangeActionId.Delete, deleteItem, deleteItems[deleteItem]); } }
private void ModifyRecordContent( OAdEntity entity, IMigrationAction action, ConversionResult convRslt, List <string> skipFields) { XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column"); if (null == columns) { throw new MigrationException(ClearQuestResource.ClearQuest_Error_InvalidActionDescription, action.ActionId); } // get the record's display name for updating conversion history string recordDisplayName = CQWrapper.GetEntityDisplayName(entity); // ********* // cache the current history count for all "history fields" // i.e. pairs of HistoryFieldName, count Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>(); BuildRecordHistoryCountCache(entity, recordHistoryCountCache); SetRecordEditable(entity); StringBuilder updateLog = new StringBuilder(); PrintUpdateLogHeader(action, updateLog); string entityDefName = CQWrapper.GetEntityDefName(entity); string stateTransitionFieldDefName = m_migrationContext.GetStateField(entityDefName); string retVal; bool recordIsUpdated = false; foreach (XmlNode columnData in columns) { string stringVal = columnData.FirstChild.InnerText; string fieldName = columnData.Attributes["ReferenceName"].Value; Debug.Assert(!string.IsNullOrEmpty(fieldName), "Field ReferenceName is absent in the Migration Description"); if (CQStringComparer.FieldName.Equals(fieldName, stateTransitionFieldDefName) || (null != skipFields && skipFields.Contains(fieldName, CQStringComparer.FieldName))) { // skip or "State" field, as it has already been submitted in a separate history/revision continue; } bool setFieldValue = false; OAdFieldInfo aFieldInfo = CQWrapper.GetEntityFieldValue(entity, fieldName); int fieldRequiredness = CQWrapper.GetRequiredness(aFieldInfo); switch (fieldRequiredness) { case CQConstants.MANDATORY: case CQConstants.OPTIONAL: setFieldValue = true; break; case CQConstants.READONLY: // [teyang] TODO conflict handling TraceManager.TraceWarning("Field {0} is READONLY", fieldName); setFieldValue = false; break; case CQConstants.USEHOOK: // [teyang] TODO conflict handling TraceManager.TraceWarning("Field {0} is USEHOOK", fieldName); setFieldValue = false; break; default: throw new InvalidOperationException(); } if (setFieldValue) { int attempt1Count = 0; if (!SetFieldValue(action, entity, fieldName, stringVal, ref attempt1Count)) { return; } AddFieldToUpdateLog(fieldName, stringVal, updateLog); recordIsUpdated = true; } } if (!recordIsUpdated) { // no update has been made to the record, mark this action to be skipped CQWrapper.Revert(entity); if (action.State == ActionState.Pending) { action.State = ActionState.Skipped; } return; } AddLineToUpdateLog(updateLog); int attempt2Count = 0; if (!SetFieldValue(action, entity, NoteEntryFieldName, updateLog.ToString(), ref attempt2Count)) { return; } retVal = CQWrapper.Validate(entity); if (!string.IsNullOrEmpty(retVal)) { IEnumerable <Microsoft.TeamFoundation.Migration.ClearQuestAdapter.CQTextParser.RecordValidationResult> validationResults; if (CQTextParser.RecordValidationTextParser.TryParse(retVal, out validationResults)) { foreach (CQTextParser.RecordValidationResult rslt in validationResults) { MigrationConflict conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action); List <MigrationAction> actions; var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions); if (!resolutionRslt.Resolved) { action.ChangeGroup.ContainsBackloggedAction = true; return; } } } else { throw new InvalidOperationException(retVal); } } retVal = CQWrapper.Commmit(entity); if (!string.IsNullOrEmpty(retVal)) { // [teyang] TODO: invalid update conflict handling throw new InvalidOperationException(retVal); } if (action.State == ActionState.Pending) { action.State = ActionState.Complete; } // ********* // now comparing to the cache, so that we can clearly identify the item:version pairs // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>(); FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices); recordHistoryCountCache.Clear(); foreach (string histFieldName in updatedHistoryIndices.Keys) { foreach (int histIndex in updatedHistoryIndices[histFieldName]) { UpdateConversionHistory(action, recordDisplayName, CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex), convRslt); } } }
public bool CanResolve(MigrationConflict conflict, ConflictResolutionRule rule) { return(string.Equals(conflict.ScopeHint, rule.ApplicabilityScope, StringComparison.OrdinalIgnoreCase)); }
private bool SetFieldValue( IMigrationAction action, OAdEntity record, string fieldName, string stringVal, ref int numOfAttempts) { numOfAttempts++; OAdFieldInfo aFieldInfo = CQWrapper.GetEntityFieldValue(record, fieldName); string originalFieldValue = CQWrapper.GetFieldValue(aFieldInfo); // doing the real job: setting field value with CQ OM string cqRetVal = CQWrapper.SetFieldValue(record, fieldName, stringVal); // error handling if (!string.IsNullOrEmpty(cqRetVal)) { MigrationConflict conflict = ClearQuestSetFieldValueConflictType.CreateConflict( UtilityMethods.ExtractSourceWorkItemId(action), UtilityMethods.ExtractSourceWorkItemRevision(action), fieldName, stringVal, cqRetVal); List <MigrationAction> migrationActions; var resolutionResult = m_conflictManagerService.TryResolveNewConflict( m_conflictManagerService.SourceId, conflict, out migrationActions); if (!resolutionResult.Resolved) { // cannot resolve the conflict, move on to next MigrationAction return(false); } else if (numOfAttempts <= 3) { // not reached maximum set value attempts yet if (resolutionResult.ResolutionType == ConflictResolutionType.UpdatedConflictedChangeAction) { XmlNode column = UtilityMethods.ExtractSingleFieldNodeFromMigrationDescription( action.MigrationActionDescription, fieldName); if (null == column) { // the field has been dropped during conflict resolution // restore the "original" value return(SetFieldValue(action, record, fieldName, originalFieldValue, ref numOfAttempts)); } else { string newFieldValue = UtilityMethods.ExtractSingleFieldValue(column); return(SetFieldValue(action, record, fieldName, stringVal, ref numOfAttempts)); } } } else { // reached max set value attempts WITH unresolved conflict return(false); } } return(true); }