public void UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecordsWithoutImplicitDelete( string sourceItemUri, LinkChangeGroup group, ILinkProvider linkProvider) { UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords(sourceItemUri, group, linkProvider, false); }
public void ExtractLinkChangeActions(TfsMigrationWorkItem source, List <LinkChangeGroup> linkChangeGroups, WorkItemLinkStore store) { if (null == source) { throw new ArgumentNullException("source"); } if (null == source.WorkItem) { throw new ArgumentException("source.WorkItem is null"); } var linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); foreach (Link l in source.WorkItem.Links) { ExternalLink el = l as ExternalLink; if (el != null && IsMyLink(el)) { var link = new Toolkit.Linking.ArtifactLink( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), new Toolkit.Linking.Artifact(source.Uri, s_sourceArtifactType), new Toolkit.Linking.Artifact(LinkingConstants.ExternalArtifactPrefix + el.LinkedArtifactUri, s_targetArtifactType), el.Comment, this); linkChangeGroup.AddChangeAction(new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false)); } } linkChangeGroups.Add(linkChangeGroup); }
public void ExtractLinkChangeActions(TfsMigrationWorkItem source, List <LinkChangeGroup> linkChangeGroups, WorkItemLinkStore store) { if (null == source) { throw new ArgumentNullException("source"); } if (null == source.WorkItem) { throw new ArgumentException("source.WorkItem is null"); } var linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); ReadOnlyCollection <ExternalLink> myLinks = ExtractMyLinks(source.WorkItem); foreach (ExternalLink el in myLinks) { var link = new Toolkit.Linking.ArtifactLink( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), new Toolkit.Linking.Artifact(source.Uri, s_sourceArtifactType), new Toolkit.Linking.Artifact(el.LinkedArtifactUri, s_targetArtifactType), el.Comment, this); linkChangeGroup.AddChangeAction(new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false)); } linkChangeGroups.Add(linkChangeGroup); }
public void UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords( string sourceItemUri, LinkChangeGroup group, ILinkProvider linkProvider) { UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords(sourceItemUri, group, linkProvider, true); }
protected override Dictionary <int, List <LinkChangeAction> > RegroupLinkChangeActions( LinkChangeGroup linkChangeGroup) { var perWorkItemLinkChanges = new Dictionary <int, List <LinkChangeAction> >(); foreach (LinkChangeAction linkChangeAction in linkChangeGroup.Actions) { Debug.Assert(!string.IsNullOrEmpty(linkChangeAction.Link.SourceArtifactId)); // skipping v2 WorkItemLinks, as they are submitted separately if (linkChangeAction.Link.LinkType is WorkItemLinkTypeBase) { continue; } int sourceArtifactWorkItemId; bool idConversionResult = int.TryParse(linkChangeAction.Link.SourceArtifactId, out sourceArtifactWorkItemId); Debug.Assert(idConversionResult); if (!perWorkItemLinkChanges.ContainsKey(sourceArtifactWorkItemId)) { perWorkItemLinkChanges.Add(sourceArtifactWorkItemId, new List <LinkChangeAction>()); } if (!perWorkItemLinkChanges[sourceArtifactWorkItemId].Contains(linkChangeAction)) { perWorkItemLinkChanges[sourceArtifactWorkItemId].Add(linkChangeAction); } } return(perWorkItemLinkChanges); }
public void ExtractLinkChangeActions( Session session, OAdEntity hostRecord, List <LinkChangeGroup> linkChangeGroups) { string hostRecDispName = CQWrapper.GetEntityDisplayName(hostRecord); string hostRecEntityDefName = CQWrapper.GetEntityDefName(hostRecord); string hostRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(hostRecEntityDefName, hostRecDispName); var linkChangeGroup = new LinkChangeGroup(hostRecMigrItemId, LinkChangeGroup.LinkChangeGroupStatus.Created, false); if (!CQWrapper.HasDuplicates(hostRecord)) { return; } object[] dupRecObjs = CQWrapper.GetDuplicates(hostRecord) as object[]; foreach (object dupRecObj in dupRecObjs) { OAdLink aLink = dupRecObj as OAdLink; if (null != aLink) { OAdEntity childRecord = CQWrapper.GetChildEntity(aLink) as OAdEntity; if (null != childRecord) { string childRecDispName = CQWrapper.GetEntityDisplayName(childRecord); string childRecEntityDefName = CQWrapper.GetEntityDefName(childRecord); string childRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(childRecEntityDefName, childRecDispName); ILink dupLink = new ArtifactLink(hostRecDispName, new Artifact(hostRecMigrItemId, new ClearQuestRecordArtifactType()), new Artifact(childRecMigrItemId, new ClearQuestRecordArtifactType()), string.Empty, this); LinkChangeAction action = new LinkChangeAction(WellKnownChangeActionId.Add, dupLink, LinkChangeAction.LinkChangeActionStatus.Created, false); linkChangeGroup.AddChangeAction(action); } else { // [teyang] TODO replace debug assertion with a conflict? Debug.Assert(false, "null == childRecord"); } } else { // [teyang] TODO replace debug assertion with a conflict? Debug.Assert(false, "null == aLink"); } } linkChangeGroups.Add(linkChangeGroup); }
public void BatchSubmitLinkChange(LinkChangeGroup linkChanges) { if (linkChanges.Actions.Count == 0) { linkChanges.Status = LinkChangeGroup.LinkChangeGroupStatus.Completed; return; } // group changes by work item Id Dictionary <string, List <LinkChangeAction> > perRecordLinkChanges = RegroupLinkChangeActions(linkChanges); WorkItemLinkStore relatedArtifactsStore = new WorkItemLinkStore(m_configurationService.SourceId); // batch-submit links of each cq record bool successForAllActions = true; foreach (var perWorkItemLinkChange in perRecordLinkChanges) { string[] identity = UtilityMethods.ParseCQRecordMigrationItemId(perWorkItemLinkChange.Key); OAdEntity hostEntity = CQWrapper.GetEntity(m_userSession, identity[0], identity[1]); foreach (LinkChangeAction linkChangeAction in perWorkItemLinkChange.Value) { if (linkChangeAction.Status != LinkChangeAction.LinkChangeActionStatus.ReadyForMigration || linkChangeAction.IsConflicted) { continue; } var handler = linkChangeAction.Link.LinkType as ILinkHandler; Debug.Assert(null != handler, "linktype is not an ILinkHandler"); if (!handler.Update(m_migrationContext, m_userSession, hostEntity, linkChangeAction)) { successForAllActions = false; // [teyang] todo conflict handling linkChangeAction.Status = LinkChangeAction.LinkChangeActionStatus.Completed; linkChangeAction.IsConflicted = true; TraceManager.TraceError("Failed processing link change action: {0} linked to {1}", linkChangeAction.Link.SourceArtifact.Uri, linkChangeAction.Link.TargetArtifact.Uri); } else { MarkLinkChangeActionCompleted(linkChangeAction, relatedArtifactsStore); } } } linkChanges.Status = successForAllActions ? LinkChangeGroup.LinkChangeGroupStatus.Completed : LinkChangeGroup.LinkChangeGroupStatus.ReadyForMigration; }
public virtual void BatchSubmitLinkChange(LinkChangeGroup linkChanges) { try { m_migrationSource.WorkItemStore.SubmitLinkChanges(linkChanges, m_serviceContainer); } catch (Exception exception) { ErrorManager errMgr = m_serviceContainer.GetService(typeof(ErrorManager)) as ErrorManager; errMgr.TryHandleException(exception); linkChanges.IsConflicted = true; } }
private List <LinkChangeAction> ExtractWorkItemLinkChanges( LinkChangeGroup linkChangeGroup) { var extractedLinkChanges = new List <LinkChangeAction>(); foreach (LinkChangeAction linkChangeAction in linkChangeGroup.Actions) { Debug.Assert(!string.IsNullOrEmpty(linkChangeAction.Link.SourceArtifactId)); if (linkChangeAction.Link.LinkType is WorkItemLinkTypeBase) { extractedLinkChanges.Add(linkChangeAction); } } return(extractedLinkChanges); }
public void ExtractLinkChangeActions(ClearQuestOleServer.Session session, ClearQuestOleServer.OAdEntity hostRecord, List <LinkChangeGroup> linkChangeGroups) { string recordId = CQWrapper.GetFieldValue(CQWrapper.GetEntityFieldValue(hostRecord, CQIdFieldName)); string url = string.Format(m_urlFormat, recordId); var linkChangeGroup = new LinkChangeGroup(recordId, LinkChangeGroup.LinkChangeGroupStatus.Created, false); string hostEntityDefName = CQWrapper.GetEntityDefName(hostRecord); string hostEntityDispName = CQWrapper.GetEntityDisplayName(hostRecord); string hostRecordId = UtilityMethods.CreateCQRecordMigrationItemId(hostEntityDefName, hostEntityDispName); ArtifactLink link = new ArtifactLink(hostRecordId, new Artifact(hostRecordId, s_sourceArtifactType), new Artifact(url, s_targetArtifactType), string.Empty, this); LinkChangeAction action = new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false); linkChangeGroup.AddChangeAction(action); linkChangeGroups.Add(linkChangeGroup); }
protected override void SubmitLinkChangesWithUpdateDoc( LinkChangeGroup linkChanges, ServiceContainer serviceContainer, TfsLinkingProviderBase.LinkSubmissionPhase submissionPhase) { ConfigurationService configService = serviceContainer.GetService(typeof(ConfigurationService)) as ConfigurationService; ITranslationService translationService = serviceContainer.GetService(typeof(ITranslationService)) as ITranslationService; bool nonWorkItemLinkChangesAllSubmitted = SubmitNonWorkItemLinkChanges( linkChanges, serviceContainer, configService, translationService, submissionPhase); bool workItemLinkChangesAllSubmitted = SubmitWorkItemLinkChanges( linkChanges, serviceContainer, configService, translationService, submissionPhase); linkChanges.Status = (nonWorkItemLinkChangesAllSubmitted && workItemLinkChangesAllSubmitted && AllActionSubmitted(linkChanges)) ? LinkChangeGroup.LinkChangeGroupStatus.Completed : LinkChangeGroup.LinkChangeGroupStatus.ReadyForMigration; }
internal void ValidateLinkChangeMigrationInstructions(LinkChangeGroup group) { string sourceItemUri = group.Actions[0].Link.SourceArtifact.Uri; var queryByItem = QueryByItem(sourceItemUri); var perItemExistingLinks = from link in queryByItem where link.RelationshipExistsOnServer select link; foreach (LinkChangeAction action in group.Actions) { var existingLinkQuery = from link in perItemExistingLinks where link.Relationship.Equals(action.Link.LinkType.ReferenceName) && link.RelatedArtifactId.Equals(action.Link.TargetArtifact.Uri) select link; if (action.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { if (existingLinkQuery.Count() > 0) { if (existingLinkQuery.First().OtherProperty.HasValue) { bool linkInStoreIsLocked = ((WorkItemLinkStore.LinkLockStatus)existingLinkQuery.First().OtherProperty.Value == WorkItemLinkStore.LinkLockStatus.Locked); if (linkInStoreIsLocked == action.Link.IsLocked) { // link already exist on server, no need to "add" action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped; } } } } else if (action.ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { if (existingLinkQuery.Count() == 0) { // link doesn't exist on server, no need to "delete" action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped; } } else { // we don't know anything about the action in this case } } }
public virtual void ExtractLinkChangeActions(TfsMigrationWorkItem source, List <LinkChangeGroup> linkChangeGroups, WorkItemLinkStore store) { if (null == source) { throw new ArgumentNullException("source"); } if (null == source.WorkItem) { throw new ArgumentException("source.WorkItem is null"); } var linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); foreach (Link l in source.WorkItem.Links) { RelatedLink rl = l as RelatedLink; if (rl != null) { // v1 work item related link does not have direction info // to avoid generating two link change actions for the same link // we only pick one from the work item of smaller id if (source.WorkItem.Id >= rl.RelatedWorkItemId) { continue; } var link = new Toolkit.Linking.ArtifactLink( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), new Toolkit.Linking.Artifact(source.Uri, s_sourceArtifactType), new Toolkit.Linking.Artifact(TfsWorkItemHandler.UriFromId(rl.RelatedWorkItemId.ToString(CultureInfo.InvariantCulture)), s_targetArtifactType), rl.Comment, this); linkChangeGroup.AddChangeAction(new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false)); } } linkChangeGroups.Add(linkChangeGroup); }
protected override void SubmitLinkChangesWithUpdateDoc( LinkChangeGroup linkChanges, ServiceContainer serviceContainer, TfsLinkingProviderBase.LinkSubmissionPhase submissionPhase) { ConfigurationService configService = serviceContainer.GetService(typeof(ConfigurationService)) as ConfigurationService; ITranslationService translationService = serviceContainer.GetService(typeof(ITranslationService)) as ITranslationService; if (m_hwmSubmittedLinkChangeId == null) { m_hwmSubmittedLinkChangeId = new HighWaterMark <long>(TfsConstants.HwmSubmittedLinkChangeId); configService.RegisterHighWaterMarkWithSession(m_hwmSubmittedLinkChangeId); } bool nonWorkItemLinkChangesAllSubmitted = SubmitNonWorkItemLinkChanges( linkChanges, serviceContainer, configService, translationService, submissionPhase); bool workItemLinkChangesAllSubmitted = SubmitWorkItemLinkChanges( linkChanges, serviceContainer, configService, translationService, submissionPhase); linkChanges.Status = (nonWorkItemLinkChangesAllSubmitted && workItemLinkChangesAllSubmitted && AllActionSubmitted(linkChanges)) ? LinkChangeGroup.LinkChangeGroupStatus.Completed : LinkChangeGroup.LinkChangeGroupStatus.ReadyForMigration; }
private Dictionary <string, List <LinkChangeAction> > RegroupLinkChangeActions(LinkChangeGroup linkChanges) { Dictionary <string, List <LinkChangeAction> > retVal = new Dictionary <string, List <LinkChangeAction> >(); foreach (LinkChangeAction action in linkChanges.Actions) { if (!retVal.ContainsKey(action.Link.SourceArtifactId)) { retVal.Add(action.Link.SourceArtifactId, new List <LinkChangeAction>()); } if (!retVal[action.Link.SourceArtifactId].Contains(action)) { retVal[action.Link.SourceArtifactId].Add(action); } } return(retVal); }
public void ExtractLinkChangeActions( Session session, OAdEntity hostRecord, List <LinkChangeGroup> linkChangeGroups) { string hostRecDispName = CQWrapper.GetEntityDisplayName(hostRecord); string hostRecEntityDefName = CQWrapper.GetEntityDefName(hostRecord); if (string.IsNullOrEmpty(hostRecEntityDefName) || !CQStringComparer.EntityName.Equals(hostRecEntityDefName, this.m_hostRecordType)) { return; } string hostRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(hostRecEntityDefName, hostRecDispName); var linkChangeGroup = new LinkChangeGroup(hostRecMigrItemId, LinkChangeGroup.LinkChangeGroupStatus.Created, false); OAdFieldInfo fldInfo = CQWrapper.GetEntityFieldValue(hostRecord, m_referenceFieldName); int cqFieldType = CQWrapper.GetFieldType(fldInfo); if (cqFieldType == CQConstants.FIELD_REFERENCE) { // get the current entity def handle OAdEntityDef curEntityDef = CQWrapper.GetEntityDef(session, hostRecEntityDefName); OAdEntityDef refEntityDef = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, m_referenceFieldName); string childRecEntityDefName = CQWrapper.GetEntityDefName(refEntityDef); int valueStatus = CQWrapper.GetFieldValueStatus(fldInfo); if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE) { // single value required string refFldVal = CQWrapper.GetFieldValue(fldInfo); if (!CQStringComparer.RecordName.Equals(refFldVal, hostRecDispName)) { // NOT a reference to self.. Note TFS cannot have a reference to self OAdEntity childRecord = CQWrapper.GetEntity(session, childRecEntityDefName, refFldVal); if (null != childRecord) { string childRecDispName = CQWrapper.GetEntityDisplayName(childRecord); string childRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId( childRecEntityDefName, childRecDispName); ILink refFieldLink = new ArtifactLink( hostRecDispName, new Artifact(hostRecMigrItemId, new ClearQuestRecordArtifactType()), new Artifact(childRecMigrItemId, new ClearQuestRecordArtifactType()), string.Empty, this); LinkChangeAction action = new LinkChangeAction( WellKnownChangeActionId.Add, refFieldLink, LinkChangeAction.LinkChangeActionStatus.Created, false); linkChangeGroup.AddChangeAction(action); } else { // [teyang] TODO replace debug assertion with a conflict? Debug.Assert(false, "null == childRecord"); } } } } linkChangeGroups.Add(linkChangeGroup); }
public ReadOnlyCollection <LinkChangeGroup> GenerateNextLinkDeltaSlice( LinkService linkService, int maxDeltaSliceSize) { try { var linkChangeGroups = new List <LinkChangeGroup>(); if (null == ExtractLinkChangeActionsCallback) { return(linkChangeGroups.AsReadOnly()); } // load high watermark; as for CQ, we store local time for queries m_hwmLink.Reload(); DateTime hwmDeltaValue = m_hwmLink.Value; if (hwmDeltaValue.Equals(default(DateTime))) { hwmDeltaValue = new DateTime(1900, 1, 1); } hwmDeltaValue = hwmDeltaValue.AddSeconds(-1); // go back 1 second as we'll drop the millisec below string hwmDeltaValueStr = hwmDeltaValue.ToString(m_migrationContext.CQQueryDateTimeFormat, CultureInfo.InvariantCulture); // record current time to update HWM after processing DateTime newHwmValue = CQUtilityMethods.GetTimeForNewHighWaterMark(m_migrationContext.CQTimeOffsetFromServerHistoryTimesInMinutes); // store to be used for analysis WorkItemLinkStore store = new WorkItemLinkStore(m_configurationService.SourceId); // extract links var inMaxDeltaSliceSize = maxDeltaSliceSize; foreach (CQRecordFilter filter in m_filters) { CQRecordQueryBase recordQuery = CQRecordQueryFactory.CreateQuery(m_userSession, filter, hwmDeltaValueStr, this); foreach (ClearQuestOleServer.OAdEntity record in recordQuery) { // HACK HACK if (record == null) { continue; } // HACK HACK string recDispName = CQWrapper.GetEntityDisplayName(record); TraceManager.TraceInformation("Generating linking delta for CQ Record: {0}", recDispName); var perWorkItemlinkChangeGroups = new List <LinkChangeGroup>(); ExtractLinkChangeActionsCallback(m_userSession, record, perWorkItemlinkChangeGroups); if (perWorkItemlinkChangeGroups.Count == 0) { TraceManager.TraceInformation("Number of links: {0}", 0); continue; } LinkChangeGroup consolidatedLinkChangeGroup = perWorkItemlinkChangeGroups[0]; for (int i = 1; i < perWorkItemlinkChangeGroups.Count; ++i) { foreach (LinkChangeAction action in perWorkItemlinkChangeGroups[i].Actions) { consolidatedLinkChangeGroup.AddChangeAction(action); } } TraceManager.TraceInformation("Number of links: {0}", consolidatedLinkChangeGroup.Actions.Count.ToString()); // VERY IMPORTANT STEP: update the link delta to store string hostRecMigrItemId = UtilityMethods.CreateCQRecordMigrationItemId(record); store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords( hostRecMigrItemId, consolidatedLinkChangeGroup, this); if (consolidatedLinkChangeGroup.Actions.Count > 0) { linkChangeGroups.Add(consolidatedLinkChangeGroup); } maxDeltaSliceSize -= consolidatedLinkChangeGroup.Actions.Count; if (maxDeltaSliceSize <= 0) { // size limit reached - persist groups to DB, then empty the slice and process next slice linkService.AddChangeGroups(linkChangeGroups); linkChangeGroups.Clear(); maxDeltaSliceSize = inMaxDeltaSliceSize; } } } // 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(newHwmValue); TraceManager.TraceInformation("Persisted CQ linking HWM: {0}", ClearQuestConstants.CqLinkHwm); TraceManager.TraceInformation("Updated CQ linking HWM: {0}", newHwmValue.ToString()); return(linkChangeGroups.AsReadOnly()); } catch (Exception exception) { // [teyang] TODO CONFLICT HANDLING //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); TraceManager.TraceException(exception); return(new List <LinkChangeGroup>().AsReadOnly()); } }
private void UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords( string sourceItemUri, LinkChangeGroup group, ILinkProvider linkProvider, bool createDeleteActionImplicitly) { var queryByItem = QueryByItem(sourceItemUri); var perItemExistingLinks = from link in queryByItem where link.RelationshipExistsOnServer select link; if (perItemExistingLinks.Count() == 0) { // no link existed before, all 'add' link actions should be pushed to the other side // AND we are going to record these links as existing on this side now AddLinks(group.Actions); } else { // check the delta link change actions // this list contains all the actions that do not need to push into the pipeline List <LinkChangeAction> actionThatEstablishExistingLinkRelationship = new List <LinkChangeAction>(); foreach (LinkChangeAction action in group.Actions) { if (action.Link.LinkType.GetsActionsFromLinkChangeHistory) { // For link types that can provide a history of link changes, we don't need to keep track of related artifact metadata // so continue to the next LinkChangeAction continue; } Debug.Assert(sourceItemUri.Equals(action.Link.SourceArtifact.Uri), "link of different action exists in the same group"); var linkQuery = from l in perItemExistingLinks where l.Relationship.Equals(action.Link.LinkType.ReferenceName) && l.RelatedArtifactId.Equals(action.Link.TargetArtifact.Uri) select l; if (action.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { if (linkQuery.Count() > 0) { if (!linkQuery.First().OtherProperty.HasValue) { // link lock property is not available - required by backward-compability UpdateLink(action, true); } else { bool linkInStoreHasLock = (((WorkItemLinkStore.LinkLockStatus)linkQuery.First().OtherProperty.Value) == WorkItemLinkStore.LinkLockStatus.Locked); if (action.Link.IsLocked == linkInStoreHasLock) { // link already exist and lock-property matches - no need to push to the other side actionThatEstablishExistingLinkRelationship.Add(action); } else { UpdateLink(action, true); } } } else { // link does not exist, keep it and push through the pipeline // AND we are going to record these links as existing on this side now UpdateLink(action, true); } } else // delete { if (linkQuery.Count() > 0) { // link exists, so we will mark in our store that it no longer exists UpdateLink(action, false); } else { // link does not exist, no need to migrate this action actionThatEstablishExistingLinkRelationship.Add(action); } } } // make sure we generate "Delete Link" action for ones that exist in the our recorded link table but is not included // in delta link actions List <LinkChangeAction> deletionActions = new List <LinkChangeAction>(); if (createDeleteActionImplicitly) { foreach (var recordedExistingLink in perItemExistingLinks) { Debug.Assert(linkProvider.SupportedLinkTypes.ContainsKey(recordedExistingLink.Relationship), "linkProvider.SupportedLinkTypes.ContainsKey(recordedExistingLink.Relationship) returns false"); LinkType linkType = linkProvider.SupportedLinkTypes[recordedExistingLink.Relationship]; if (linkType.GetsActionsFromLinkChangeHistory) { // The link type is one that support link change history, so we ignore the contents of the // RelatedArtifactTable and rely on the link change history instead. continue; } bool recordedActionInGroup = false; foreach (LinkChangeAction action in group.Actions) { if (action.Link.LinkType.ReferenceName.Equals(recordedExistingLink.Relationship, StringComparison.OrdinalIgnoreCase) && action.Link.TargetArtifact.Uri.Equals(recordedExistingLink.RelatedArtifactId, StringComparison.OrdinalIgnoreCase)) { recordedActionInGroup = true; break; } } if (!recordedActionInGroup) { TraceManager.TraceInformation("Link '{0}'->'{1}' ({2}) appears to have been deleted - generating link deletion action to be migrated", recordedExistingLink.ItemId, recordedExistingLink.RelatedArtifactId, recordedExistingLink.Relationship); LinkChangeAction linkDeleteAction = linkType.CreateLinkDeletionAction( recordedExistingLink.ItemId, recordedExistingLink.RelatedArtifactId, recordedExistingLink.Relationship); if (null != linkDeleteAction) { deletionActions.Add(linkDeleteAction); } recordedExistingLink.RelationshipExistsOnServer = false; } } } if (actionThatEstablishExistingLinkRelationship.Count > 0) { foreach (LinkChangeAction actionToDelete in actionThatEstablishExistingLinkRelationship) { group.DeleteChangeAction(actionToDelete); } } if (deletionActions.Count > 0) { group.PrependActions(deletionActions); } } m_context.TrySaveChanges(); }
public void ExtractLinkChangeActions(TfsMigrationWorkItem source, List <LinkChangeGroup> linkChangeGroups, WorkItemLinkStore store) { if (null == source) { throw new ArgumentNullException("source"); } if (null == source.WorkItem) { throw new ArgumentException("source.WorkItem is null"); } var linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); List <string> revertedLinkSourceWorkItemUris = new List <string>(); if (null != store) { revertedLinkSourceWorkItemUris = store.GetRevertedLinkSourceItems(source.Uri, ReferenceName); } foreach (WorkItemLink l in source.WorkItem.WorkItemLinks) { #region obsolete //// always recognize the "ForwardLink" //if (!l.LinkTypeEnd.IsForwardLink) //{ // continue; //} #endregion // always recognize the WorkItem with smaller Id for non-directional link if (!l.LinkTypeEnd.LinkType.IsDirectional && l.SourceId > l.TargetId) { continue; } if (!TFStringComparer.LinkName.Equals(l.LinkTypeEnd.LinkType.ReferenceName, ReferenceName)) { continue; } var sourceIdStr = l.SourceId.ToString(CultureInfo.InvariantCulture); var targetIdStr = l.TargetId.ToString(CultureInfo.InvariantCulture); var sourceArtifact = new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(sourceIdStr), s_sourceArtifactType); var targetArtifact = new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(targetIdStr), s_targetArtifactType); ToolkitLinking.ArtifactLink link; if (l.LinkTypeEnd.IsForwardLink) { link = new ToolkitLinking.ArtifactLink(sourceIdStr, sourceArtifact, targetArtifact, l.Comment, this, l.IsLocked); } else { link = new ToolkitLinking.ArtifactLink(targetIdStr, targetArtifact, sourceArtifact, l.Comment, this, l.IsLocked); if (revertedLinkSourceWorkItemUris.Contains(targetArtifact.Uri)) { revertedLinkSourceWorkItemUris.Remove(targetArtifact.Uri); } } var linkChangeAction = new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false); linkChangeGroup.AddChangeAction(linkChangeAction); } foreach (string revertedLinkSrcItemUri in revertedLinkSourceWorkItemUris) { string sourceWorkItemId = TfsWorkItemHandler.IdFromUri(revertedLinkSrcItemUri); LinkChangeGroup group = new LinkChangeGroup(sourceWorkItemId, LinkChangeGroup.LinkChangeGroupStatus.Created, false); var deleteLinkChangeAction = new LinkChangeAction( WellKnownChangeActionId.Delete, new ToolkitLinking.ArtifactLink(sourceWorkItemId, new ToolkitLinking.Artifact(revertedLinkSrcItemUri, s_sourceArtifactType), new ToolkitLinking.Artifact(source.Uri, s_targetArtifactType), string.Empty, this), LinkChangeAction.LinkChangeActionStatus.Created, false); group.AddChangeAction(deleteLinkChangeAction); linkChangeGroups.Add(group); } linkChangeGroups.Add(linkChangeGroup); }
private void CreateLinkChangeGroupsForForceSyncItem(TfsMigrationWorkItem tfsMigrationWorkItem) { if (m_linkService == null) { Debug.Fail("LinkService is null"); return; } var linkChangeGroups = new List <LinkChangeGroup>(); var detectedLinkChangeGroups = new List <LinkChangeGroup>(); ExtractLinkChangeActionsCallback(tfsMigrationWorkItem, detectedLinkChangeGroups, null); if (detectedLinkChangeGroups.Count == 0) { TraceManager.TraceInformation("Number of non-Work Item links: {0}", 0); } else { 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); } } foreach (var workItemLinkGroup in perWorkItemConsolidatedLinkChangeGroup) { string workItemIdStr = TfsWorkItemHandler.IdFromUri(workItemLinkGroup.Key); TraceManager.TraceInformation("Detected {0} non-Work Item links for force sync Work Item '{1}'", workItemLinkGroup.Value.Actions.Count, workItemIdStr); if (workItemLinkGroup.Value.Actions.Count > 0) { workItemLinkGroup.Value.IsForcedSync = true; linkChangeGroups.Add(workItemLinkGroup.Value); } } } if (tfsMigrationWorkItem.WorkItem.WorkItemLinks.Count > 0) { // Handle work item to work item links LinkChangeGroup workItemlinkChangeGroup = new LinkChangeGroup( tfsMigrationWorkItem.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); Dictionary <string, LinkType> linkTypesByName = new Dictionary <string, LinkType>(); foreach (WorkItemLink workItemLink in tfsMigrationWorkItem.WorkItem.WorkItemLinks) { string linkTypeName = workItemLink.LinkTypeEnd.LinkType.ReferenceName; LinkType linkType; if (!linkTypesByName.TryGetValue(linkTypeName, out linkType)) { ExtendedLinkProperties extendedLinkProperties = new ExtendedLinkProperties(); linkType = new WorkItemLinkTypeBase(linkTypeName, linkTypeName, extendedLinkProperties, m_migrationSource.WorkItemStore.WorkItemStore); linkTypesByName.Add(linkTypeName, linkType); } LinkChangeAction addLinkChangeAction = GetAddLinkChangeActionFromWorkItemLink(workItemLink, linkType); workItemlinkChangeGroup.AddChangeAction(addLinkChangeAction); } if (workItemlinkChangeGroup.Actions.Count > 0) { workItemlinkChangeGroup.IsForcedSync = true; linkChangeGroups.Add(workItemlinkChangeGroup); TraceManager.TraceInformation("Detected {0} Work Item links for force sync Work Item '{1}'", workItemlinkChangeGroup.Actions.Count, tfsMigrationWorkItem.WorkItem.Id); } } // Persist link change groups to DB if (linkChangeGroups.Count > 0) { m_linkService.AddChangeGroups(linkChangeGroups); } }
public virtual 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; 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 newHwmLinkValue = Convert.ToDateTime(hwmLinkValueStr, CultureInfo.InvariantCulture); // store to be used to analyze deleted links WorkItemLinkStore store = new WorkItemLinkStore(new Guid(sourceId)); // extract links 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 perWorkItemlinkChangeGroups = new List <LinkChangeGroup>(); ExtractLinkChangeActionsCallback(tfsMigrationWorkItem, perWorkItemlinkChangeGroups, store); if (perWorkItemlinkChangeGroups.Count == 0) { TraceManager.TraceInformation("Number of links: {0}", 0); continue; } LinkChangeGroup consolidatedLinkChangeGroup = perWorkItemlinkChangeGroups[0]; for (int i = 1; i < perWorkItemlinkChangeGroups.Count; ++i) { foreach (LinkChangeAction action in perWorkItemlinkChangeGroups[i].Actions) { consolidatedLinkChangeGroup.AddChangeAction(action); } } TraceManager.TraceInformation("Number of links: {0}", consolidatedLinkChangeGroup.Actions.Count.ToString()); // VERY IMPORTANT: use the RelatedArtifactsStore to detect link deletion store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords( tfsMigrationWorkItem.Uri, consolidatedLinkChangeGroup, this); if (consolidatedLinkChangeGroup.Actions.Count > 0) { linkChangeGroups.Add(consolidatedLinkChangeGroup); } maxDeltaSliceSize -= consolidatedLinkChangeGroup.Actions.Count; if (maxDeltaSliceSize <= 0) { // size limit reached - persist groups to DB linkService.AddChangeGroups(linkChangeGroups); linkChangeGroups.Clear(); maxDeltaSliceSize = inMaxDeltaSliceSize; } } // 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); TraceManager.TraceInformation("Persisted WIT linking HWM: {0}", Toolkit.Constants.HwmDeltaLink); TraceManager.TraceInformation(TfsWITAdapterResources.UpdatedHighWatermark, hwmLinkValueStr); return(linkChangeGroups.AsReadOnly()); } catch (Exception exception) { ErrorManager errMgr = m_serviceContainer.GetService(typeof(ErrorManager)) as ErrorManager; errMgr.TryHandleException(exception); return(new List <LinkChangeGroup>().AsReadOnly()); } }
private LinkChangeGroup GetLinkChangeGroupFromLinkChanges(TfsMigrationWorkItem source) { LinkChangeGroup linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); Dictionary <string, LinkType> linkTypesByName = new Dictionary <string, LinkType>(); foreach (WorkItemLinkChange linkChange in source.LinkChanges) { LinkType linkType; if (!linkTypesByName.TryGetValue(linkChange.LinkType, out linkType)) { ExtendedLinkProperties extendedLinkProperties = new ExtendedLinkProperties(); linkType = new WorkItemLinkTypeBase(linkChange.LinkType, linkChange.LinkType, extendedLinkProperties, m_migrationSource.WorkItemStore.WorkItemStore); linkTypesByName.Add(linkChange.LinkType, linkType); } bool actionAdded = false; if (linkChange.IsActive) // Link added { // Get matching link l from WorkItem links collection WorkItemLink l = GetWorkItemLinkFromLinkChange(source, linkChange); if (l != null) { LinkChangeAction addLinkChangeAction = GetAddLinkChangeActionFromWorkItemLink(l, linkType); addLinkChangeAction.ServerLinkChangeId = linkChange.RowVersion.ToString(); linkChangeGroup.AddChangeAction(addLinkChangeAction); actionAdded = true; } else { TraceManager.TraceInformation(String.Format( "Unable to find link on work item {0} corresponding to detected link addition from {1} to {2} of type {3}; it may have been recently deleted", source.WorkItem.Id, linkChange.SourceID, linkChange.TargetID, linkChange.LinkType)); } } else // Link deleted { var deleteLinkChangeAction = new LinkChangeAction( WellKnownChangeActionId.Delete, new ToolkitLinking.ArtifactLink(linkChange.SourceID.ToString(), new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(linkChange.SourceID.ToString()), WorkItemLinkTypeBase.s_sourceArtifactType), new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(linkChange.TargetID.ToString()), WorkItemLinkTypeBase.s_targetArtifactType), string.Empty, linkType), LinkChangeAction.LinkChangeActionStatus.Created, false); deleteLinkChangeAction.ServerLinkChangeId = linkChange.RowVersion.ToString(); linkChangeGroup.AddChangeAction(deleteLinkChangeAction); actionAdded = true; } if (actionAdded) { TraceManager.TraceVerbose("Adapter: Generating link change action: {0} '{1}'->'{2}' (Type: {3})", linkChange.IsActive ? "Add" : "Delete", linkChange.SourceID, linkChange.TargetID, linkChange.LinkType); } } return(linkChangeGroup); }
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 SubmitWorkItemLinkChanges( LinkChangeGroup linkChanges, ServiceContainer serviceContainer, ConfigurationService configService, ITranslationService translationService, TfsLinkingProviderBase.LinkSubmissionPhase submissionPhase) { var linkChangeActions = ExtractWorkItemLinkChanges(linkChanges); if (linkChangeActions.Count == 0) { return(true); } ConflictManager conflictManageer = serviceContainer.GetService(typeof(ConflictManager)) as ConflictManager; var updatedocsForEditLinks = new List <XmlDocument>(linkChangeActions.Count); var updateDocsForAddLinks = new List <XmlDocument>(linkChangeActions.Count); var updateDocsForDeleteLinks = new List <XmlDocument>(linkChangeActions.Count); Dictionary <int, LinkChangeAction> docForEditlinksToActionMap = new Dictionary <int, LinkChangeAction>(); Dictionary <int, LinkChangeAction> docForAddlinksToActionMap = new Dictionary <int, LinkChangeAction>(); Dictionary <int, LinkChangeAction> docForDeletelinksToActionMap = new Dictionary <int, LinkChangeAction>(); for (int i = 0; i < linkChangeActions.Count; ++i) { if (linkChangeActions[i].Status != LinkChangeAction.LinkChangeActionStatus.ReadyForMigration || linkChangeActions[i].IsConflicted) { continue; } if (!ProcessActionInCurrentSubmissionPhase(linkChangeActions[i], submissionPhase)) { continue; } var tfsUpdateDocument = InitializeUpdateDocument(); var handler = linkChangeActions[i].Link.LinkType as ILinkHandler; Debug.Assert(null != handler); handler.UpdateTfs(tfsUpdateDocument, linkChangeActions[i]); if (linkChangeActions[i].ChangeActionId.Equals(WellKnownChangeActionId.Add)) { docForAddlinksToActionMap.Add(updateDocsForAddLinks.Count, linkChangeActions[i]); updateDocsForAddLinks.Add(tfsUpdateDocument.UpdateDocument); } else if (linkChangeActions[i].ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { docForDeletelinksToActionMap.Add(updateDocsForDeleteLinks.Count, linkChangeActions[i]); updateDocsForDeleteLinks.Add(tfsUpdateDocument.UpdateDocument); } else if (linkChangeActions[i].ChangeActionId.Equals(WellKnownChangeActionId.Edit)) { docForEditlinksToActionMap.Add(updatedocsForEditLinks.Count, linkChangeActions[i]); updatedocsForEditLinks.Add(tfsUpdateDocument.UpdateDocument); } else { TraceManager.TraceVerbose("Change action '{0}' in Link Change Group '{1}' is not supported.", linkChangeActions[i].ChangeActionId.ToString(), linkChanges.GroupName); linkChangeActions[i].Status = LinkChangeAction.LinkChangeActionStatus.Completed; } } bool succeeded = true; if (updatedocsForEditLinks.Count > 0) { succeeded &= SubmitBatchedAddOrDeleteLinkChanges( updatedocsForEditLinks, docForEditlinksToActionMap, translationService, configService, conflictManageer); } if (updateDocsForDeleteLinks.Count > 0) { succeeded &= SubmitBatchedAddOrDeleteLinkChanges( updateDocsForDeleteLinks, docForDeletelinksToActionMap, translationService, configService, conflictManageer); } if (updateDocsForAddLinks.Count > 0) { succeeded &= SubmitBatchedAddOrDeleteLinkChanges( updateDocsForAddLinks, docForAddlinksToActionMap, translationService, configService, conflictManageer); } return(succeeded); }
public override void ExtractLinkChangeActions(TfsMigrationWorkItem source, List <LinkChangeGroup> linkChangeGroups, WorkItemLinkStore store) { if (null == source) { throw new ArgumentNullException("source"); } if (null == source.WorkItem) { throw new ArgumentException("source.WorkItem is null"); } var linkChangeGroup = new LinkChangeGroup( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), LinkChangeGroup.LinkChangeGroupStatus.Created, false); foreach (Link l in source.WorkItem.Links) { RelatedLink rl = l as RelatedLink; if (rl != null) { // v1 work item related link does not have direction info // to avoid generating two link change actions for the same link // we only pick one from the work item of smaller id if (source.WorkItem.Id >= rl.RelatedWorkItemId) { continue; } #region TFS 2010 specific logic if (rl.LinkTypeEnd != null && rl.LinkTypeEnd.LinkType != null) { if (rl.LinkTypeEnd.LinkType.ReferenceName.Equals(Tfs2010RelatedLinkTypeReferenceName, StringComparison.OrdinalIgnoreCase)) { #endregion var link = new Toolkit.Linking.ArtifactLink( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), new Toolkit.Linking.Artifact(source.Uri, s_sourceArtifactType), new Toolkit.Linking.Artifact(TfsWorkItemHandler.UriFromId(rl.RelatedWorkItemId.ToString(CultureInfo.InvariantCulture)), s_targetArtifactType), rl.Comment, this, rl.IsLocked); linkChangeGroup.AddChangeAction(new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false)); } } else { var link = new Toolkit.Linking.ArtifactLink( source.WorkItem.Id.ToString(CultureInfo.InvariantCulture), new Toolkit.Linking.Artifact(source.Uri, s_sourceArtifactType), new Toolkit.Linking.Artifact(TfsWorkItemHandler.UriFromId(rl.RelatedWorkItemId.ToString(CultureInfo.InvariantCulture)), s_targetArtifactType), rl.Comment, this); linkChangeGroup.AddChangeAction(new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false)); } } } linkChangeGroups.Add(linkChangeGroup); }
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); }