private static void ParseExceptionMessage( Exception linkSubmissionException, LinkChangeAction action, out string scopeHint, out string conflictDetails) { /* * Example Exception: * System.Web.Services.Protocols.SoapException * * Example Message * Failed to modify links. The following linked work items have been locked by an administrator: * %LinkFailures="1954;1955;2;2,";% ---> Failed to modify links. The following linked work items * have been locked by an administrator: %LinkFailures="1954;1955;2;2,";% */ Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); Debug.Assert(!string.IsNullOrEmpty(linkSubmissionException.Message), "linkSubmissionException.Message is null or empty"); Debug.Assert(linkSubmissionException.Message.StartsWith(ModifyLockedWorkItemLinkViolationMessage, StringComparison.OrdinalIgnoreCase), string.Format("linkSubmissionException.Message does not start with '{0}'", ModifyLockedWorkItemLinkViolationMessage)); string sourceItem = action.Link.SourceArtifactId; string targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); string linkType = action.Link.LinkType.ReferenceName; scopeHint = string.Format("/{0}/{1}/{2}", linkType, sourceItem, targetItem); conflictDetails = InvalidWorkItemLinkDetails.CreateConflictDetails(sourceItem, targetItem, linkType); }
private static void ParseExceptionMessage(Exception linkSubmissionException, LinkChangeAction action, out string scopeHint, out string conflictDetails) { /* * Example Exception: * System.Web.Services.Protocols.SoapException * * Example Message * AddLink: The specified link type requires that work items have a single parent. * The target work item already has a parent of that type: %SourceID="969";%, %TargetID="967";%, %LinkType="2";% * ---> AddLink: The specified link type requires that work items have a single parent. The target work item already * has a parent of that type: %SourceID="969";%, %TargetID="967";%, %LinkType="2";% */ Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); Debug.Assert(!string.IsNullOrEmpty(linkSubmissionException.Message), "linkSubmissionException.Message is null or empty"); Debug.Assert(linkSubmissionException.Message.StartsWith(SingleParentViolationMessage, StringComparison.OrdinalIgnoreCase), string.Format("linkSubmissionException.Message does not start with '{0}'", SingleParentViolationMessage)); string sourceItem = action.Link.SourceArtifactId; string targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); string linkType = action.Link.LinkType.ReferenceName; scopeHint = string.Format("/{0}/{1}/{2}", linkType, sourceItem, targetItem); conflictDetails = InvalidWorkItemLinkDetails.CreateConflictDetails(sourceItem, targetItem, linkType); }
private static void ParseException( Exception linkSubmissionException, LinkChangeAction action, out string sourceItem, out string targetItem, out string linkType) { /* * Example Exception: * System.Web.Services.Protocols.SoapException * * Example Message * AddLink: The specified link type enforces noncircularity in its hierarchy. * The target work item is ancestor of the source work item and cannot be its child: %SourceID="960";%, %TargetID="962";%, %LinkType="2";% * ---> AddLink: The specified link type enforces noncircularity in its hierarchy. The target work item is ancestor of the source work item * and cannot be its child: %SourceID="960";%, %TargetID="962";%, %LinkType="2";% */ Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); Debug.Assert(!string.IsNullOrEmpty(linkSubmissionException.Message), "linkSubmissionException.Message is null or empty"); Debug.Assert(linkSubmissionException.Message.StartsWith(CircularityLinkHierarchyViolationMessage, StringComparison.OrdinalIgnoreCase), string.Format("linkSubmissionException.Message does not start with '{0}'", CircularityLinkHierarchyViolationMessage)); sourceItem = action.Link.SourceArtifactId; targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); linkType = action.Link.LinkType.ReferenceName; }
public override LinkChangeAction CreateLinkDeletionAction(string sourceItemUri, string targetArtifactUrl, string linkTypeReferenceName) { ClearQuestRecordArtifactHandler handler = new ClearQuestRecordArtifactHandler(); IArtifact srcArtifact; IArtifact tgtArtifact; if (!handler.TryCreateArtifactFromId(s_sourceArtifactType, sourceItemUri, out srcArtifact) || !handler.TryCreateArtifactFromId(s_targetArtifactType, targetArtifactUrl, out tgtArtifact)) { return(null); } string dispName; if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(srcArtifact, out dispName)) { return(null); } ILink link = new ArtifactLink(dispName, srcArtifact, tgtArtifact, string.Empty, this); LinkChangeAction action = new LinkChangeAction(WellKnownChangeActionId.Delete, link, LinkChangeAction.LinkChangeActionStatus.Created, false); return(action); }
private void UpdateLink(LinkChangeAction action, bool linkExistAfterUpdate) { string itemId = action.Link.SourceArtifact.Uri; string relatedArtifact = action.Link.TargetArtifact.Uri; string linkType = action.Link.LinkType.ReferenceName; if (!action.Link.LinkType.GetsActionsFromLinkChangeHistory) { var rtMigrationSource = RuntimeMigrationSource; var queryByItem = QueryByItem(itemId); var relationshipQuery = from r in queryByItem where r.RelatedArtifactId.Equals(relatedArtifact) && r.Relationship.Equals(linkType) select r; Debug.Assert(relationshipQuery.Count() <= 1, "More than two identical related artifacts relationship exist"); RTRelatedArtifactsRecords record; if (relationshipQuery.Count() == 0) { record = RTRelatedArtifactsRecords.CreateRTRelatedArtifactsRecords( 0, itemId, linkType, relatedArtifact, linkExistAfterUpdate); record.MigrationSource = m_rtMigrationSource; } else { record = relationshipQuery.First(); record.RelationshipExistsOnServer = linkExistAfterUpdate; } record.OtherProperty = action.Link.IsLocked ? (int)WorkItemLinkStore.LinkLockStatus.Locked : (int)WorkItemLinkStore.LinkLockStatus.Unlocked; } }
private int GetLowerWorkItemId(LinkChangeAction action) { int sourceId = int.Parse(action.Link.SourceArtifactId); int targetId = int.Parse(TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri)); return(Math.Min(sourceId, targetId)); }
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); }
private static string CreateScopeHint( Exception linkSubmissionException, LinkChangeAction action) { string sourceItem; string targetItem; string linkType; ParseException(linkSubmissionException, action, out sourceItem, out targetItem, out linkType); return(string.Format("/{0}/{1}/{2}", linkType, sourceItem, targetItem)); }
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); }
public static MigrationConflict CreateConflict( LinkChangeAction conflictedAction, Exception linkSubmissionException, NonCyclicReferenceClosure linkReferenceClosure) { string scopeHint = CreateScopeHint(linkSubmissionException, conflictedAction); string conflictDetails = CreateConflictDetails(linkSubmissionException, conflictedAction, linkReferenceClosure); MigrationConflict conflict = new MigrationConflict(new TFSCyclicLinkConflictType(), MigrationConflict.Status.Unresolved, conflictDetails, scopeHint); conflict.ConflictedLinkChangeAction = conflictedAction; return(conflict); }
private static string CreateConflictDetails( Exception linkSubmissionException, LinkChangeAction action, NonCyclicReferenceClosure linkReferenceClosure) { string sourceItem; string targetItem; string linkType; ParseException(linkSubmissionException, action, out sourceItem, out targetItem, out linkType); return(CyclicLinkConflictDetails.CreateConflictDetails(sourceItem, targetItem, linkType, linkReferenceClosure)); }
public static MigrationConflict CreateConflict( LinkChangeAction conflictedAction, Exception linkSubmissionException) { string scopeHint = null; string conflictDetails = null; ParseExceptionMessage(linkSubmissionException, conflictedAction, out scopeHint, out conflictDetails); MigrationConflict conflict = new MigrationConflict(new TFSMulitpleParentLinkConflictType(), MigrationConflict.Status.Unresolved, conflictDetails, scopeHint); conflict.ConflictedLinkChangeAction = conflictedAction; return(conflict); }
/// <summary> /// Creates the scope hint of this type of conflict. /// /SessionGroupId/LinkTypeReferenceName/InternalLinkChangeActionId /// </summary> /// <param name="sessionGroupId"></param> /// <param name="linkChangeAction"></param> /// <returns></returns> public static string CreateScopeHint( Guid sessionGroupId, LinkChangeAction linkChangeAction) { Debug.Assert(linkChangeAction.InternalId != LinkChangeAction.INVALID_INTERNAL_ID); Debug.Assert(!sessionGroupId.Equals(Guid.Empty)); return(string.Format( BasicPathScopeInterpreter.PathSeparator + "{0}" + BasicPathScopeInterpreter.PathSeparator + "{1}" + BasicPathScopeInterpreter.PathSeparator + "{2}", sessionGroupId.ToString(), linkChangeAction.Link.LinkType.ReferenceName, linkChangeAction.InternalId)); }
public bool UpdateTfs(TfsUpdateDocument updateDoc, LinkChangeAction linkChangeAction) { if (null == updateDoc) { throw new ArgumentNullException("updateDoc"); } if (null == linkChangeAction) { throw new ArgumentNullException("linkChangeAction"); } if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(REFERENCE_NAME)) { throw new ArgumentException("Link type mismatch."); } string uri = linkChangeAction.Link.TargetArtifact.Uri; string comment = linkChangeAction.Link.Comment; if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { updateDoc.AddExternalLink(LinkingConstants.VcFileLinkType, uri, comment); } else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { Debug.Assert(updateDoc.WorkItem != null, "WorkItem is null in updateDoc"); int?extId = ExtractFileLinkInfoExtId(updateDoc.WorkItem, uri); if (extId.HasValue) { updateDoc.DeleteExternalLink(extId.Value); } else { TraceManager.TraceInformation("Deleting link {0}-to-{1} failed - cannot find linked target artifact.", linkChangeAction.Link.SourceArtifactId, linkChangeAction.Link.TargetArtifact.Uri); return(false); } } else { throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction); } return(true); }
private static void ParseExceptionMessage( Exception linkSubmissionException, LinkChangeAction action, out string scopeHint, out string conflictDetails) { Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); string sourceItem = action.Link.SourceArtifactId; string targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); string linkType = action.Link.LinkType.ReferenceName; scopeHint = string.Format("/{0}/{1}/{2}", linkType, sourceItem, targetItem); conflictDetails = InvalidWorkItemLinkDetails.CreateConflictDetails(sourceItem, targetItem, linkType); }
public bool UpdateTfs(TfsUpdateDocument updateDoc, LinkChangeAction linkChangeAction) { if (null == updateDoc) { throw new ArgumentNullException("updateDoc"); } if (null == linkChangeAction) { throw new ArgumentNullException("linkChangeAction"); } if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(ReferenceName)) { throw new ArgumentException("Link type mismatch."); } string targetId = TfsWorkItemHandler.IdFromUri(linkChangeAction.Link.TargetArtifact.Uri); string sourceId = TfsWorkItemHandler.IdFromUri(linkChangeAction.Link.SourceArtifact.Uri); int linkTypeId = WorkItemLinkTypeId(ReferenceName, true); string comment = linkChangeAction.Link.Comment ?? string.Empty; var tfs2010UpdateDoc = updateDoc as Tfs2010UpdateDocument; Debug.Assert(null != tfs2010UpdateDoc); if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { tfs2010UpdateDoc.AddWorkItemLink(sourceId, targetId, linkTypeId, comment, linkChangeAction.Link.IsLocked); } else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Edit)) { tfs2010UpdateDoc.UpdateWorkItemLink(sourceId, targetId, linkTypeId, comment, linkChangeAction.Link.IsLocked); } else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { tfs2010UpdateDoc.RemoveWorkItemLink(sourceId, targetId, linkTypeId, comment); } else { throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction); } return(true); }
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); }
public bool UpdateTfs(TfsUpdateDocument updateDoc, LinkChangeAction linkChangeAction) { if (null == updateDoc) { throw new ArgumentNullException("updateDoc"); } if (null == linkChangeAction) { throw new ArgumentNullException("linkChangeAction"); } if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(REFERENCE_NAME)) { throw new ArgumentException("Link type mismatch."); } //if (!linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add)) //{ // Debug.Assert(false, "Unsupported action!"); // TraceManager.TraceError("Non-add action on external links is not supported."); //} string uri = linkChangeAction.Link.TargetArtifact.Uri; string comment = linkChangeAction.Link.Comment; if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { updateDoc.AddWorkItemLink(TfsWorkItemHandler.IdFromUri(uri), comment); } else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { updateDoc.RemoveWorkItemLink(TfsWorkItemHandler.IdFromUri(uri)); } else { throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction); } return(true); }
private static void ParseExceptionMessage( Exception linkSubmissionException, LinkChangeAction action, out string scopeHint, out string conflictDetails) { Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); Debug.Assert(!string.IsNullOrEmpty(linkSubmissionException.Message), "linkSubmissionException.Message is null or empty"); Debug.Assert( linkSubmissionException.Message.StartsWith(LinkAccessViolationMessage1, StringComparison.OrdinalIgnoreCase) || linkSubmissionException.Message.StartsWith(LinkAccessViolationMessage2, StringComparison.OrdinalIgnoreCase), string.Format("linkSubmissionException.Message does not start with '{0}' or '{1}'", LinkAccessViolationMessage1, LinkAccessViolationMessage2)); string sourceItem = action.Link.SourceArtifactId; string targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); string linkType = action.Link.LinkType.ReferenceName; scopeHint = string.Format("/{0}/{1}/{2}", linkType, sourceItem, targetItem); conflictDetails = InvalidWorkItemLinkDetails.CreateConflictDetails(sourceItem, targetItem, linkType); }
private static void ParseException( Exception linkSubmissionException, LinkChangeAction action, out string sourceItem, out string targetItem, out string linkType) { /* * Example Exception: * System.Web.Services.Protocols.SoapException * * Example Message * AddLink: The specified link type enforces noncircularity in its hierarchy. * The target work item is ancestor of the source work item and cannot be its child: %SourceID="960";%, %TargetID="962";%, %LinkType="2";% * ---> AddLink: The specified link type enforces noncircularity in its hierarchy. The target work item is ancestor of the source work item * and cannot be its child: %SourceID="960";%, %TargetID="962";%, %LinkType="2";% */ Debug.Assert(linkSubmissionException is System.Web.Services.Protocols.SoapException, "linkSubmissionException is not System.Web.Services.Protocols.SoapException"); sourceItem = action.Link.SourceArtifactId; targetItem = TfsWorkItemHandler.IdFromUri(action.Link.TargetArtifact.Uri); linkType = action.Link.LinkType.ReferenceName; }
private bool LinkChangeMatchesLinkAction(WorkItemLinkChange linkChange, LinkChangeAction linkChangeAction) { // bool actionIsAdd = (linkChangeAction.ChangeActionId == WellKnownChangeActionId.Add); if (// Don't match on Add/Delete against IsActive because GetWorkItemLinkChanges() combines add/delete and IsActive is just latest status: // actionIsAdd == linkChange.IsActive && string.Equals(linkChange.LinkType, linkChangeAction.Link.LinkType.ReferenceName, StringComparison.Ordinal)) { string linkActionTargetIdString = TfsWorkItemHandler.IdFromUri(linkChangeAction.Link.TargetArtifact.Uri); if (string.Equals(linkChange.SourceID.ToString(), linkChangeAction.Link.SourceArtifactId, StringComparison.OrdinalIgnoreCase) && string.Equals(linkChange.TargetID.ToString(), linkActionTargetIdString, StringComparison.OrdinalIgnoreCase)) { return(true); } if (string.Equals(linkChange.SourceID.ToString(), linkActionTargetIdString, StringComparison.OrdinalIgnoreCase) && string.Equals(linkChange.TargetID.ToString(), linkChangeAction.Link.SourceArtifactId, StringComparison.OrdinalIgnoreCase)) { return(true); } } return(false); }
private LinkChangeAction GetAddLinkChangeActionFromWorkItemLink(WorkItemLink workItemLink, LinkType linkType) { var sourceIdStr = workItemLink.SourceId.ToString(CultureInfo.InvariantCulture); var targetIdStr = workItemLink.TargetId.ToString(CultureInfo.InvariantCulture); var sourceArtifact = new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(sourceIdStr), WorkItemLinkTypeBase.s_sourceArtifactType); var targetArtifact = new ToolkitLinking.Artifact(TfsWorkItemHandler.UriFromId(targetIdStr), WorkItemLinkTypeBase.s_targetArtifactType); ToolkitLinking.ArtifactLink link; if (workItemLink.LinkTypeEnd.IsForwardLink) { link = new ToolkitLinking.ArtifactLink(sourceIdStr, sourceArtifact, targetArtifact, workItemLink.Comment, linkType, workItemLink.IsLocked); } else { link = new ToolkitLinking.ArtifactLink(targetIdStr, targetArtifact, sourceArtifact, workItemLink.Comment, linkType, workItemLink.IsLocked); } LinkChangeAction addLinkChangeAction = new LinkChangeAction(WellKnownChangeActionId.Add, link, LinkChangeAction.LinkChangeActionStatus.Created, false); return(addLinkChangeAction); }
private string GetLinkChangeActionDescription(LinkChangeAction linkChangeAction) { return(String.Format(CultureInfo.InvariantCulture, "link change action: {0} link of type {1} from '{2}' to '{3}'", linkChangeAction.ChangeActionId == WellKnownChangeActionId.Add ? "Add" : "Delete", linkChangeAction.Link.LinkType.ReferenceName, linkChangeAction.Link.SourceArtifact.Uri, linkChangeAction.Link.TargetArtifact.Uri)); }
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(); }
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); }
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); } }
/// <summary> /// This method is called when an attempt to add a link in the force sync case fails because a parent link already exists /// In this case we attempt to delete the existing parent link and retry the add link operation /// </summary> /// <param name="linkChangeAction">The LinkChangeAction object</param> /// <param name="updateDocumentThatFailed">The XmlDocument that was submitted to add the link that resulted in the error</param> /// <returns>True if successful at removing the existing parent and adding the new parent; false if not</returns> private bool DeleteExistingParentLinkToForceSyncAddLink(LinkChangeAction linkChangeAction, XmlDocument updateDocumentThatFailed) { // Get target work item ... string targetItem = TfsWorkItemHandler.IdFromUri(linkChangeAction.Link.TargetArtifact.Uri); WorkItem targetWorkItem = null; try { int targetWorkItemId = int.Parse(targetItem); targetWorkItem = base.WorkItemStore.GetWorkItem(targetWorkItemId); } catch (FormatException) { } catch (DeniedOrNotExistException) { } if (targetWorkItem != null) { // Delete its parent link ... string linkType = linkChangeAction.Link.LinkType.ReferenceName; WorkItemLink linkToRemove = null; foreach (WorkItemLink link in targetWorkItem.WorkItemLinks) { if (!link.LinkTypeEnd.IsForwardLink && string.Equals(link.LinkTypeEnd.LinkType.ReferenceName, linkType)) { linkToRemove = link; break; } } if (linkToRemove != null) { try { // Create a delete LinkChangeAction by copying from the add LinkChangeAction and // changing the SourceId which is the parent in the add parent link case. LinkChangeAction deletelinkChangeAction = new LinkChangeAction(WellKnownChangeActionId.Delete, linkChangeAction.Link, linkChangeAction.Status, false); deletelinkChangeAction.Link.SourceArtifact.Uri = TfsWorkItemHandler.UriFromId(linkToRemove.TargetId.ToString()); TfsUpdateDocument tfsUpdateDocument = InitializeUpdateDocument(); var handler = deletelinkChangeAction.Link.LinkType as ILinkHandler; Debug.Assert(null != handler); handler.UpdateTfs(tfsUpdateDocument, deletelinkChangeAction); XmlDocument[] xmlUpdateDocuments = new XmlDocument[] { tfsUpdateDocument.UpdateDocument }; UpdateResult[] deleteExistingParentResults = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, xmlUpdateDocuments); Debug.Assert(deleteExistingParentResults.Length == 1); if (deleteExistingParentResults[0].Exception != null) { throw deleteExistingParentResults[0].Exception; } } catch (Exception ex) { TraceManager.TraceWarning(String.Format(CultureInfo.InvariantCulture, "An exception occurred while trying to remove the parent link to force sync a link change to target work item {0}: {1}", targetWorkItem.Id, ex.ToString())); targetWorkItem = null; } if (targetWorkItem != null) { // Retry the operation XmlDocument[] retryDocuments = new XmlDocument[1] { updateDocumentThatFailed }; UpdateResult[] retryResults = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, retryDocuments); if (retryResults.Length != retryDocuments.Length) { throw new SynchronizationEngineException("Wrong number of link update results."); } if (retryResults[0].Exception == null) { // Successfully retried after removing existing parent; don't create conflict return(true); } else { TraceManager.TraceWarning(String.Format(CultureInfo.InvariantCulture, "An exception occurred while trying to force sync a link change to target work item {0}: {1}", targetWorkItem.Id, retryResults[0].Exception.ToString())); } } } } return(false); }
public bool Update(ClearQuestMigrationContext migrationContext, ClearQuestOleServer.Session session, ClearQuestOleServer.OAdEntity hostRecord, LinkChangeAction linkChangeAction) { // this link type is fabricated. Do nothing for submission. linkChangeAction.Status = LinkChangeAction.LinkChangeActionStatus.Completed; return(true); }
public bool Update( ClearQuestMigrationContext migrationContext, Session cqSession, OAdEntity hostRecord, LinkChangeAction linkChangeAction) { if (null == linkChangeAction) { throw new ArgumentNullException("linkChangeAction"); } if (!linkChangeAction.Link.LinkType.ReferenceName.Equals(REFERENCE_NAME)) { throw new ArgumentException("Link type mismatch."); } string childRecEntityDefName; if (!ClearQuestRecordArtifactHandler.TryExtractRecordDefName(linkChangeAction.Link.TargetArtifact, out childRecEntityDefName)) { return(false); } string childRecDispName; if (!ClearQuestRecordArtifactHandler.TryExtractRecordDispName(linkChangeAction.Link.TargetArtifact, out childRecDispName)) { return(false); } OAdEntity childEntity = CQWrapper.GetEntity(cqSession, childRecEntityDefName, childRecDispName); if (null == childEntity) { return(false); } // check if hostRecord already has a duplicate of this childRecord bool duplicateAlreadyExist = HasDuplicateRecord(hostRecord, childRecEntityDefName, childRecDispName); // find out the child entity's current state // find the current state string childEntityDefName = CQWrapper.GetEntityDefName(childEntity); OAdFieldInfo aFldInfo = CQWrapper.GetEntityFieldValue(childEntity, migrationContext.GetStateField(childEntityDefName)); string srcState = CQWrapper.GetFieldValue(aFldInfo); OAdEntityDef childEntityDef = CQWrapper.GetEntityDef(cqSession, childEntityDefName); if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Add)) { if (duplicateAlreadyExist) { // [teyang] TODO return(false); } string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState( childEntityDef, srcState, CQConstants.ACTION_DUPLICATE); string changeActionName = string.Empty; if (changeActionNames.Length == 0) { // [teyang] TODO conflict } else if (changeActionNames.Length > 1) { // [teyang] TODO conflict } else { changeActionName = changeActionNames[0]; } if (!string.IsNullOrEmpty(changeActionName)) { CQWrapper.MarkEntityAsDuplicate(cqSession, childEntity, hostRecord, changeActionName); string retVal = CQWrapper.Validate(childEntity); if (string.IsNullOrEmpty(retVal)) { // [teyang] TODO conflict } retVal = CQWrapper.Commmit(childEntity); if (string.IsNullOrEmpty(retVal)) { // [teyang] TODO conflict } } } else if (linkChangeAction.ChangeActionId.Equals(WellKnownChangeActionId.Delete)) { if (!duplicateAlreadyExist) { // [teyang] TODO return(false); } string[] changeActionNames = CQUtilityMethods.FindAllActionNameByTypeAndSourceState( childEntityDef, srcState, CQConstants.ACTION_UNDUPLICATE); string changeActionName = string.Empty; if (changeActionNames.Length == 0) { // [teyang] TODO conflict } else if (changeActionNames.Length > 1) { // [teyang] TODO conflict } else { changeActionName = changeActionNames[0]; } if (!string.IsNullOrEmpty(changeActionName)) { CQWrapper.UnmarkEntityAsDuplicate(cqSession, childEntity, changeActionName); string retVal = CQWrapper.Validate(childEntity); if (string.IsNullOrEmpty(retVal)) { // [teyang] TODO conflict } retVal = CQWrapper.Commmit(childEntity); if (string.IsNullOrEmpty(retVal)) { // [teyang] TODO conflict } } } else { //throw new MigrationException(TfsWITAdapterResources.ErrorUnsupportedChangeAction); } return(true); }
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); }