Esempio n. 1
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 8
0
        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));
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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));
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        /// <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));
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
        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);
        }
Esempio n. 18
0
        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);
        }
Esempio n. 20
0
        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);
        }
Esempio n. 22
0
        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();
        }
Esempio n. 25
0
        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);
        }
Esempio n. 26
0
        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);
            }
        }
Esempio n. 27
0
        /// <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);
        }