private void MarkLinkChangeActionCompleted(LinkChangeAction action, WorkItemLinkStore relatedArtifactsStore) { if (action.Status == LinkChangeAction.LinkChangeActionStatus.ReadyForMigration) { action.Status = LinkChangeAction.LinkChangeActionStatus.Completed; } var actions = new List <LinkChangeAction>(); actions.Add(action); relatedArtifactsStore.UpdateSyncedLinks(actions); }
protected bool SubmitNonWorkItemLinkChanges( LinkChangeGroup linkChanges, ServiceContainer serviceContainer, ConfigurationService configService, ITranslationService translationService, TfsLinkingProviderBase.LinkSubmissionPhase submissionPhase) { // group non-WorkItemLink changes by work item Id Dictionary <int, List <LinkChangeAction> > perWorkItemLinkChanges = RegroupLinkChangeActions(linkChanges); var orderedWorkitemId = new Dictionary <int, int>(); int index = 0; foreach (int workItemId in perWorkItemLinkChanges.Keys) { orderedWorkitemId.Add(index++, workItemId); } // batch-submit links of each work item var updateDocs = new List <XmlDocument>(perWorkItemLinkChanges.Count); foreach (var perWorkItemLinkChange in perWorkItemLinkChanges) { if (perWorkItemLinkChange.Value.Count == 0) { continue; } WorkItem workItem = WorkItemStore.GetWorkItem(perWorkItemLinkChange.Key); var tfsUpdateDocument = InitializeUpdateDocument(); tfsUpdateDocument.CreateWorkItemUpdateDoc(workItem); bool hasNonWorkItemLinkChanges = false; foreach (LinkChangeAction linkChangeAction in perWorkItemLinkChange.Value) { if (linkChangeAction.Status != LinkChangeAction.LinkChangeActionStatus.ReadyForMigration || linkChangeAction.IsConflicted || linkChangeAction.Link.LinkType is WorkItemLinkTypeBase) { continue; } if (!ProcessActionInCurrentSubmissionPhase(linkChangeAction, submissionPhase)) { continue; } hasNonWorkItemLinkChanges = true; var handler = linkChangeAction.Link.LinkType as ILinkHandler; Debug.Assert(null != handler); handler.UpdateTfs(tfsUpdateDocument, linkChangeAction); } if (hasNonWorkItemLinkChanges) { updateDocs.Add(tfsUpdateDocument.UpdateDocument); } } if (updateDocs.Count == 0) { return(true); } UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocs.ToArray()); if (results.Length != updateDocs.Count) { throw new SynchronizationEngineException("Wrong number of link update results."); } bool succeeded = true; for (int i = 0; i < results.Length; ++i) { UpdateResult rslt = results[i]; if (rslt.Exception != null && !rslt.Exception.Message.Contains("The specified link already exists")) { TraceManager.TraceError(rslt.Exception.ToString()); succeeded = false; // TODO // Try resolve conflict and push to backlog if resolution fails foreach (LinkChangeAction action in perWorkItemLinkChanges[orderedWorkitemId[i]]) { action.IsConflicted = true; } } else { foreach (LinkChangeAction action in perWorkItemLinkChanges[orderedWorkitemId[i]]) { if (ProcessActionInCurrentSubmissionPhase(action, submissionPhase)) { MarkLinkChangeActionCompleted(action); } } if (rslt.Exception == null) { UpdateLinkConversionHistory(configService, translationService, rslt, perWorkItemLinkChanges[orderedWorkitemId[i]]); } else if (rslt.Exception.Message.Contains("The specified link already exists")) { WorkItemLinkStore relatedArtifactsStore = new WorkItemLinkStore(configService.SourceId); relatedArtifactsStore.UpdateSyncedLinks(perWorkItemLinkChanges[orderedWorkitemId[i]]); } } } 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."); } 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); }