Example #1
0
        private RTSession FindSessionForConflictedAction(
            MigrationConflict conflict,
            RuntimeEntityModel context)
        {
            // figure out which session the conflicted change action belongs to
            Guid sessionId = Guid.Empty;

            if (conflict.ConflictedChangeAction.ChangeGroup == null)
            {
                RTChangeGroup rtChangeGroup = FindChangeGroupForConflictedAction(conflict, context);
                if (null != rtChangeGroup)
                {
                    sessionId = rtChangeGroup.SessionUniqueId;
                }
            }
            else
            {
                sessionId = conflict.ConflictedChangeAction.ChangeGroup.SessionId;
            }

            if (sessionId.Equals(Guid.Empty))
            {
                Debug.Assert(false, "cannot find session for the conflicted action");
                return(null);
            }

            var sessionQuery = context.RTSessionSet.Where(s => s.SessionUniqueId.Equals(sessionId));

            if (sessionQuery.Count() > 0)
            {
                return(sessionQuery.First());
            }
            else
            {
                return(null);
            }
        }
        public InvalidFieldConflictTypeDetails GetConflictDetails(MigrationConflict conflict)
        {
            if (!conflict.ConflictType.ReferenceName.Equals(this.ReferenceName))
            {
                throw new InvalidOperationException();
            }

            if (string.IsNullOrEmpty(conflict.ConflictDetails))
            {
                throw new ArgumentNullException("conflict.ConflictDetails");
            }

            try
            {
                // V2 conflict details, i.e. using property bag
                return(new InvalidFieldConflictTypeDetails(conflict.ConflictDetailsProperties));
            }
            catch (Exception)
            {
                GenericSerializer <InvalidFieldConflictTypeDetails> serializer =
                    new GenericSerializer <InvalidFieldConflictTypeDetails>();
                return(serializer.Deserialize(conflict.ConflictDetails));
            }
        }
        public ConflictResolutionResult Resolve(IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions)
        {
            actions = null;

            if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName))
            {
                return(new ConflictResolutionResult(true, ConflictResolutionType.Other));
            }
            else if (rule.ActionRefNameGuid.Equals(new WITUnmappedWITConflictUpdateWITMappingAction().ReferenceName))
            {
                return(ResolveByUsingWITMapping(conflict, rule));
            }
            else if (rule.ActionRefNameGuid.Equals(new WITUnmappedWITConflictExcludeWITInSessionFilter().ReferenceName) ||
                     rule.ActionRefNameGuid.Equals(new SkipConflictedActionResolutionAction().ReferenceName))
            {
                conflict.ConflictedChangeAction.ChangeGroup.Status = ChangeStatus.Skipped;
                conflict.ConflictedChangeAction.State = ActionState.Skipped;
                return(new ConflictResolutionResult(true, ConflictResolutionType.SkipConflictedChangeAction));
            }
            else
            {
                return(new ConflictResolutionResult(false, ConflictResolutionType.Other));
            }
        }
Example #4
0
        private ConflictResolutionResult ResolveByValueMap(MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions)
        {
            actions = null;

            ClearQuestInvalidFieldValueConflictType conflictType = conflict.ConflictType as ClearQuestInvalidFieldValueConflictType;

            if (null == conflictType)
            {
                throw new InvalidOperationException();
            }

            string mapFromValue    = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_MapFromValue];
            string mapToValue      = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_MapToValue];
            string targetFieldName = rule.DataFieldDictionary[UseValueMapConflictResolutionAction.ActionDataKey_TargetFieldName];

            //
            // apply value map to the Action's Description document
            //
            XmlDocument desc   = conflict.ConflictedChangeAction.MigrationActionDescription;
            XmlNode     column = desc.SelectSingleNode(string.Format(
                                                           @"/WorkItemChanges/Columns/Column[@ReferenceName=""{0}""]", targetFieldName));

            if (column == null)
            {
                // defer to migration time to resolve the conflict, mark it as resolved for now
                return(new ConflictResolutionResult(true, ConflictResolutionType.Other));
            }
            else if (!mapFromValue.Equals(column.FirstChild.InnerText, StringComparison.InvariantCulture))
            {
                return(new ConflictResolutionResult(false, ConflictResolutionType.Other));
            }
            column.FirstChild.InnerText = mapToValue;

            //note: changes to "MigrationConflict conflict" is saved by the conflict manager automatically
            return(new ConflictResolutionResult(true, ConflictResolutionType.UpdatedConflictedChangeAction));
        }
        public virtual ConflictResolutionResult Resolve(IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions)
        {
            actions = null;

            if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName))
            {
                return(ManualResolve(conflict, rule, out actions));
            }

            return(new ConflictResolutionResult(false, ConflictResolutionType.Other));
        }
Example #6
0
        /// <summary>
        /// Try to process the change group, assuming it contains context sync instructions.
        /// </summary>
        /// <param name="nextChangeGroup"></param>
        /// <returns>true if the change group is a context sync group and it has been processed (either successfully or not)</returns>
        /// <exception cref="MigrationUnresolvedConflictException"></exception>
        /// <remarks>
        /// If sync succeeds, the change group will be marked as 'Completed'; otherwise, a conflict
        /// will be raised and we do not expect it to be auto-resolved.
        /// </remarks>
        private bool TryProcessContextSyncChangeGroup(ChangeGroup changeGroup)
        {
            // context sync steps must be strictly ordered, although they may not come in expected order
            // the following logic sorts them
            bool foundSyncContextAction = true;

            MigrationAction[] contextSyncActions = new MigrationAction[6];
            foreach (MigrationAction action in changeGroup.Actions)
            {
                if (action.Action.Equals(WellKnownChangeActionId.SyncContext))
                {
                    Debug.Assert(!string.IsNullOrEmpty(action.FromPath));
                    if (action.ItemTypeReferenceName.Equals(WellKnownContentType.UserGroupList.ReferenceName))
                    {
                        contextSyncActions[0] = action;
                    }
                    else if (action.ItemTypeReferenceName.Equals(WellKnownContentType.ValueListCollection.ReferenceName))
                    {
                        contextSyncActions[1] = action;
                    }
                    else if (action.ItemTypeReferenceName.Equals(WellKnownContentType.Tfs2005WorkItemFieldMetadata.ReferenceName) ||
                             action.ItemTypeReferenceName.Equals(WellKnownContentType.Tfs2008WorkItemFieldMetadata.ReferenceName))
                    {
                        contextSyncActions[2] = action;
                    }
                    else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsAreaPathsContentTypeRefName))
                    {
                        contextSyncActions[3] = action;
                    }
                    else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsIterationPathsContentTypeRefName))
                    {
                        contextSyncActions[4] = action;
                    }
                    else if (action.ItemTypeReferenceName.Equals(TfsConstants.TfsCSSNodeChangesContentTypeRefName))
                    {
                        contextSyncActions[5] = action;
                    }
                }
                else
                {
                    foundSyncContextAction = false;
                    break;
                }
            }

            if (!foundSyncContextAction)
            {
                return(false);
            }

            IMigrationAction currSyncAction = null;

            try
            {
                if (contextSyncActions[0] != null)
                {
                    currSyncAction = contextSyncActions[0];
                    SyncUserAccount(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy);
                }

                if (contextSyncActions[1] != null)
                {
                    currSyncAction = contextSyncActions[1];
                    SyncGlobalList(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy);
                }

                if (contextSyncActions[2] != null)
                {
                    currSyncAction = contextSyncActions[2];
                    SyncWorkItemTypeDefinition(currSyncAction.MigrationActionDescription,
                                               m_witMetadataSyncPolicy);
                }

                if (contextSyncActions[3] != null && !m_migrationSource.WorkItemStore.Core.DisableAreaPathAutoCreation)
                {
                    // keep for backward compatibility only (replaced by SyncCSSNodeChanges)
                    currSyncAction = contextSyncActions[3];
                    SyncAreaPaths(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy);
                }

                if (contextSyncActions[4] != null && !m_migrationSource.WorkItemStore.Core.DisableIterationPathAutoCreation)
                {
                    // keep for backward compatibility only (replaced by SyncCSSNodeChanges)
                    currSyncAction = contextSyncActions[4];
                    SyncIterationPaths(currSyncAction.MigrationActionDescription, m_witMetadataSyncPolicy);
                }

                if (contextSyncActions[5] != null)
                {
                    currSyncAction = contextSyncActions[5];
                    SyncCSSNodeChanges(
                        currSyncAction.MigrationActionDescription,
                        m_migrationSource.WorkItemStore.Core.DisableAreaPathAutoCreation,
                        m_migrationSource.WorkItemStore.Core.DisableIterationPathAutoCreation);
                }

                changeGroup.Status = ChangeStatus.Complete;
                changeGroup.Save();

                return(true);
            }
            catch (Exception ex)
            {
                if (!(ex is MigrationUnresolvedConflictException))
                {
                    TraceManager.TraceError(ex.ToString());

                    // backlog the conflict context sync action/group
                    MigrationConflict genericeConflict = InvalidSubmissionConflictType.CreateConflict(
                        currSyncAction, ex, currSyncAction.ChangeGroup.Name, currSyncAction.ChangeGroup.Name);
                    var conflictManager = m_conflictManagementService.GetService(typeof(ConflictManager)) as ConflictManager;
                    Debug.Assert(null != conflictManager);
                    List <MigrationAction>   resolutionActions;
                    ConflictResolutionResult resolveRslt =
                        conflictManager.TryResolveNewConflict(conflictManager.SourceId, genericeConflict, out resolutionActions);
                    Debug.Assert(!resolveRslt.Resolved);
                    return(true);
                }
                else
                {
                    throw;
                }
            }
        }
Example #7
0
        public override System.Collections.ObjectModel.ReadOnlyCollection <LinkChangeGroup> GenerateNextLinkDeltaSlice(
            LinkService linkService,
            int maxDeltaSliceSize)
        {
            try
            {
                var linkChangeGroups = new List <LinkChangeGroup>();

                if (null == ExtractLinkChangeActionsCallback)
                {
                    return(linkChangeGroups.AsReadOnly());
                }

                // load main Highwater Mark
                m_hwmLink.Reload();
                DateTime hwmLinkValue = m_hwmLink.Value;
                // search back 60 seconds to deal with potential WIT race condition
                if (!hwmLinkValue.Equals(default(DateTime)))
                {
                    hwmLinkValue = hwmLinkValue.AddSeconds(-60);
                }
                string hwmLinkValueStr = hwmLinkValue.ToString(CultureInfo.InvariantCulture);

                // load Work Items for extracting links
                string sourceId  = m_migrationSource.UniqueId;
                string storeName = m_migrationSource.WorkItemStore.StoreName;

                // Get items based on primary Highwater Mark
                TraceManager.TraceInformation(TfsWITAdapterResources.GettingModifiedItems, sourceId, storeName);
                IEnumerable <TfsMigrationWorkItem> items = m_migrationSource.WorkItemStore.GetItems(ref hwmLinkValueStr);
                TraceManager.TraceInformation(TfsWITAdapterResources.ReceivedModifiedItems, sourceId, storeName);

                // Record the updated HWM value
                DateTime wiqlExecutionTime = Convert.ToDateTime(hwmLinkValueStr, CultureInfo.InvariantCulture);

                // store to be used to analyze deleted links
                WorkItemLinkStore store = new WorkItemLinkStore(new Guid(sourceId));

                // extract links
                DateTime lastWorkITemUpdateTime = DateTime.MinValue;
                var      inMaxDeltaSliceSize    = maxDeltaSliceSize;
                foreach (TfsMigrationWorkItem tfsMigrationWorkItem in items)
                {
                    if (tfsMigrationWorkItem.WorkItem == null)
                    {
                        continue;
                    }

                    TraceManager.TraceInformation("Generating linking delta for Work Item: {0}", tfsMigrationWorkItem.WorkItem.Id.ToString());
                    var detectedLinkChangeGroups = new List <LinkChangeGroup>();
                    ExtractLinkChangeActionsCallback(tfsMigrationWorkItem, detectedLinkChangeGroups, store);

                    if (detectedLinkChangeGroups.Count == 0)
                    {
                        TraceManager.TraceInformation("Number of links: {0}", 0);
                        continue;
                    }

                    Dictionary <string, LinkChangeGroup> perWorkItemConsolidatedLinkChangeGroup = new Dictionary <string, LinkChangeGroup>();
                    for (int i = 0; i < detectedLinkChangeGroups.Count; ++i)
                    {
                        foreach (LinkChangeAction action in detectedLinkChangeGroups[i].Actions)
                        {
                            if (!perWorkItemConsolidatedLinkChangeGroup.ContainsKey(action.Link.SourceArtifact.Uri))
                            {
                                var linkChangeGroup = new LinkChangeGroup(
                                    action.Link.SourceArtifactId, LinkChangeGroup.LinkChangeGroupStatus.Created, false);
                                perWorkItemConsolidatedLinkChangeGroup.Add(action.Link.SourceArtifact.Uri, linkChangeGroup);
                            }
                            perWorkItemConsolidatedLinkChangeGroup[action.Link.SourceArtifact.Uri].AddChangeAction(action);
                        }
                    }

                    // always make sure that the currently analyzed work item has a link change group to represent it
                    // even though the group can be empty
                    if (!perWorkItemConsolidatedLinkChangeGroup.ContainsKey(tfsMigrationWorkItem.Uri))
                    {
                        perWorkItemConsolidatedLinkChangeGroup.Add(
                            tfsMigrationWorkItem.Uri,
                            new LinkChangeGroup(TfsWorkItemHandler.IdFromUri(tfsMigrationWorkItem.Uri), LinkChangeGroup.LinkChangeGroupStatus.Created, false));
                    }


                    foreach (var workItemLinkGroup in perWorkItemConsolidatedLinkChangeGroup)
                    {
                        string workItemIdStr = TfsWorkItemHandler.IdFromUri(workItemLinkGroup.Key);
                        TraceManager.TraceInformation("Detected {0} links for Work Item '{1}'",
                                                      workItemLinkGroup.Value.Actions.Count, workItemIdStr);

                        if (workItemLinkGroup.Key.Equals(tfsMigrationWorkItem.Uri, StringComparison.OrdinalIgnoreCase))
                        {
                            // VERY IMPORTANT: use the RelatedArtifactsStore to detect link deletion
                            store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecords(
                                workItemLinkGroup.Key, workItemLinkGroup.Value, this);
                        }
                        else
                        {
                            store.UpdatePerItemLinkChangeGroupsByCheckingRelatedItemRecordsWithoutImplicitDelete(
                                workItemLinkGroup.Key, workItemLinkGroup.Value, this);
                        }

                        if (workItemLinkGroup.Value.Actions.Count > 0)
                        {
                            linkChangeGroups.Add(workItemLinkGroup.Value);
                        }
                        maxDeltaSliceSize -= workItemLinkGroup.Value.Actions.Count;

                        if (maxDeltaSliceSize <= 0)
                        {
                            // size limit reached - persist groups to DB
                            linkService.AddChangeGroups(linkChangeGroups);
                            linkChangeGroups.Clear();
                            maxDeltaSliceSize = inMaxDeltaSliceSize;
                        }
                    }

                    DateTime lastRevChangedDate = tfsMigrationWorkItem.WorkItem.ChangedDate;

                    if (lastWorkITemUpdateTime.CompareTo(lastRevChangedDate) <= 0)
                    {
                        lastWorkITemUpdateTime = lastRevChangedDate;
                    }
                }

                // persist remaining groups to DB
                linkService.AddChangeGroups(linkChangeGroups);

                // clean up the returned link change group collection
                // when the caller (toolkit) receives an empty collection, it understands there is no more
                // delta to generate for the moment, and proceeds to next phase
                linkChangeGroups.Clear();

                // update primary Highwater Mark
                //m_hwmLink.Update(newHwmLinkValue);

                string newHwmValueStr = hwmLinkValueStr;
                if (lastWorkITemUpdateTime.Equals(DateTime.MinValue))
                {
                    // no changes in this sync cycle, record the wiql query execution time
                    m_hwmLink.Update(wiqlExecutionTime);
                }
                else
                {
                    // hwm is recorded in UTC, so does the WIQL query asof time
                    lastWorkITemUpdateTime = lastWorkITemUpdateTime.ToUniversalTime();

                    if (lastWorkITemUpdateTime.CompareTo(wiqlExecutionTime) <= 0)
                    {
                        // last work item rev time is earlier than wiql query execution time, use it as hwm
                        m_hwmLink.Update(lastWorkITemUpdateTime);
                        newHwmValueStr = lastWorkITemUpdateTime.ToString();
                    }
                    else
                    {
                        m_hwmLink.Update(wiqlExecutionTime);
                    }
                }
                TraceManager.TraceInformation("Persisted WIT linking HWM: {0}", Toolkit.Constants.HwmDeltaLink);
                TraceManager.TraceInformation(TfsWITAdapterResources.UpdatedHighWatermark, newHwmValueStr);

                return(linkChangeGroups.AsReadOnly());
            }
            catch (Exception exception)
            {
                MigrationConflict genericeConflict = WitGeneralConflictType.CreateConflict(exception);
                var conflictManager = m_conflictManager.GetService(typeof(ConflictManager)) as ConflictManager;
                Debug.Assert(null != conflictManager);
                List <MigrationAction>   resolutionActions;
                ConflictResolutionResult resolveRslt =
                    conflictManager.TryResolveNewConflict(conflictManager.SourceId, genericeConflict, out resolutionActions);
                Debug.Assert(!resolveRslt.Resolved);
                return(new List <LinkChangeGroup>().AsReadOnly());
            }
        }
        private bool SubmitBatchedAddOrDeleteLinkChanges(
            List <XmlDocument> updateDocuments,
            Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap,
            ITranslationService translationService,
            ConfigurationService configService,
            ConflictManager conflictManager)
        {
            bool succeeded = true;

            UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray());
            if (results.Length != updateDocuments.Count)
            {
                throw new SynchronizationEngineException("Wrong number of link update results.");
            }

            // Collect list of successful LinkChangeActions (for LinkTypes with GetsActionsFromLinkChangeHistory true) to pass to SetServerLinkChangeIds()
            List <LinkChangeAction> actionsNeedingServerLinkIdSet = new List <LinkChangeAction>();

            for (int i = 0; i < results.Length; ++i)
            {
                UpdateResult rslt = results[i];

                if (rslt.Exception != null)
                {
                    if (rslt.Exception.Message.Contains("The specified link already exists"))
                    {
                        // it is ok to eat this exception

                        // mark the change action completed so it is not retried later
                        LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i];
                        action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped;

                        TraceManager.TraceInformation("Tried to add a link that already exists so skipping it: " + GetLinkChangeActionDescription(action));

                        System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException;
                        if (soapException != null)
                        {
                            TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml);
                        }
                    }
                    else if (updateDocIndexToLinkChangeActionMap[i].ChangeActionId == WellKnownChangeActionId.Delete && rslt.Exception.Message.Contains("This specified link does not exist"))
                    {
                        // it is ok to eat this exception and skip the action

                        // mark the change action completed so it is not retried later
                        LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i];
                        action.Status = LinkChangeAction.LinkChangeActionStatus.Skipped;

                        TraceManager.TraceInformation("Tried to delete a link that does not exist so skipping it: " + GetLinkChangeActionDescription(action));

                        System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException;
                        if (soapException != null)
                        {
                            TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml);
                        }
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSMulitpleParentLinkConflictType.SingleParentViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        MigrationConflict conflict = TFSMulitpleParentLinkConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                            succeeded = false;
                        }
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSCyclicLinkConflictType.CircularityLinkHierarchyViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider;
                        Debug.Assert(null != linkProvider, "linkProvider is NULL");

                        LinkChangeAction          conflictedAction = updateDocIndexToLinkChangeActionMap[i];
                        NonCyclicReferenceClosure linkRefClosure   =
                            linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact);

                        MigrationConflict conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                            succeeded = false;
                        }
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSModifyLockedWorkItemLinkConflictType.ModifyLockedWorkItemLinkViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        MigrationConflict conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                        }
                        // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                        succeeded = false;
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             (rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage1, StringComparison.OrdinalIgnoreCase) ||
                              rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage2, StringComparison.OrdinalIgnoreCase)))
                    {
                        MigrationConflict conflict = TFSLinkAccessViolationConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                        }
                        // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                        succeeded = false;
                    }
                    else
                    {
                        LinkChangeAction action = updateDocIndexToLinkChangeActionMap[i];
                        // TODO
                        // Try resolve conflict and push to backlog if resolution fails
                        action.IsConflicted = true;

                        TraceManager.TraceError(String.Format(CultureInfo.InvariantCulture,
                                                              "Exception processing {0}: {1}", GetLinkChangeActionDescription(action), rslt.Exception.ToString()));
                        succeeded = false;
                    }
                }
                else // rslt.Exception == null
                {
                    LinkChangeAction successfulAction = updateDocIndexToLinkChangeActionMap[i];
                    MarkLinkChangeActionCompleted(successfulAction);

                    TraceManager.TraceVerbose("Successful " + GetLinkChangeActionDescription(successfulAction));

                    List <LinkChangeAction> updatedActions = new List <LinkChangeAction>();
                    updatedActions.Add(successfulAction);

                    if (successfulAction.Link.LinkType.GetsActionsFromLinkChangeHistory)
                    {
                        actionsNeedingServerLinkIdSet.Add(successfulAction);
                    }

                    UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions);
                }
            }

            SetServerLinkChangeIds(actionsNeedingServerLinkIdSet);

            return(succeeded);
        }
Example #9
0
        public ConflictResolutionResult Resolve(System.ComponentModel.Design.IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions)
        {
            actions = null;

            if (rule.ActionRefNameGuid.Equals(new ManualConflictResolutionAction().ReferenceName))
            {
                return(ManualResolve(conflict, rule, out actions));
            }
            else if (rule.ActionRefNameGuid.Equals(new SkipConflictedActionResolutionAction().ReferenceName))
            {
                return(SkipConflictedAction(conflict, rule, out actions));
            }

            return(new ConflictResolutionResult(false, ConflictResolutionType.Other));
        }
        private void AddRecord(IMigrationAction action, ConversionResult convRslt)
        {
            string    recordType = UtilityMethods.ExtractRecordType(action);
            OAdEntity newRecord  = CQWrapper.BuildEntity(m_userSession, recordType);

            string        validationRsltString = string.Empty;
            List <string> processedFields      = new List <string>();

            #region add new record with MANDATORY field values

            if (!SetMandatoryFields(action, ref newRecord, out processedFields))
            {
                return;
            }

            bool unResolvedConflictExists = false;
            bool validationErrorExists    = false;
            validationRsltString = CQWrapper.Validate(newRecord);
            if (!string.IsNullOrEmpty(validationRsltString))
            {
                validationErrorExists = true;
                IEnumerable <CQTextParser.RecordValidationResult> validationResults;
                if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults))
                {
                    foreach (CQTextParser.RecordValidationResult rslt in validationResults)
                    {
                        MigrationConflict      conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                        List <MigrationAction> actions;
                        var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            unResolvedConflictExists = true;
                            break;
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException(validationRsltString);
                }
            }

            if (unResolvedConflictExists)
            {
                return;
            }
            else if (validationErrorExists)
            {
                // All conflicts are resolved. Try re-applying the changes
                newRecord.Revert();

                SetRecordEditable(newRecord);

                if (!SetMandatoryFields(action, ref newRecord, out processedFields))
                {
                    return;
                }
                else
                {
                    validationRsltString = CQWrapper.Validate(newRecord);
                    if (!string.IsNullOrEmpty(validationRsltString))
                    {
                        IEnumerable <CQTextParser.RecordValidationResult> validationResults;
                        if (CQTextParser.RecordValidationTextParser.TryParse(validationRsltString, out validationResults) &&
                            validationResults.Count() > 0)
                        {
                            CQTextParser.RecordValidationResult rslt = validationResults.First();
                            MigrationConflict conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                            m_conflictManagerService.BacklogUnresolvedConflict(m_conflictManagerService.SourceId, conflict, false);
                            return;
                        }
                        else
                        {
                            throw new InvalidOperationException(validationRsltString);
                        }
                    }
                }
            }


            validationRsltString = CQWrapper.Commmit(newRecord);
            if (!string.IsNullOrEmpty(validationRsltString))
            {
                // [teyang] TODO: invalid update conflict handling
                throw new InvalidOperationException(validationRsltString);
            }

            string newRecordDisplayName = CQWrapper.GetEntityDisplayName(newRecord);
            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            UpdateConversionHistory(action, newRecordDisplayName, ClearQuestRecordItem.NewRecordVersion, convRslt);
            #endregion

            #region update the new record with remaining field values
            ModifyRecordContent(newRecord, action, convRslt, processedFields);
            #endregion
        }
Example #11
0
 private ConflictResolutionResult ResolveByIncreasingMaxAttchSetting(MigrationConflict conflict, ConflictResolutionRule rule)
 {
     throw new NotImplementedException();
 }
Example #12
0
 public bool CanResolve(MigrationConflict conflict, ConflictResolutionRule rule)
 {
     return(ConflictTypeHandled.ScopeInterpreter.IsInScope(conflict.ScopeHint, rule.ApplicabilityScope));
 }
        private ConflictResolutionResult ResolveBySubmitMissingChanges(
            IServiceContainer serviceContainer,
            MigrationConflict conflict,
            ConflictResolutionRule rule,
            out List <MigrationAction> actions)
        {
            actions = null;
            var retVal = new ConflictResolutionResult(false, ConflictResolutionType.Other);

            WITTranslationService translationService = serviceContainer.GetService(typeof(ITranslationService)) as WITTranslationService;

            Debug.Assert(null != translationService, "translationService is not initialized or not a wit translation service");

            using (RuntimeEntityModel context = RuntimeEntityModel.CreateInstance())
            {
                RTSessionGroup rtSessionGroup = FindSessionGroupForConflictedAction(conflict, context);
                if (null == rtSessionGroup)
                {
                    return(retVal);
                }

                BM.BusinessModelManager bmm = new BM.BusinessModelManager();
                BM.Configuration        sessionGroupConfig = bmm.LoadConfiguration(rtSessionGroup.GroupUniqueId);

                // find target-side migration source config
                var  parentChangeGroup       = FindChangeGroupForConflictedAction(conflict, context);
                Guid targetMigrationSourceId = parentChangeGroup.SourceUniqueId;
                BM.MigrationSource targetMigrationSourceConfig = sessionGroupConfig.SessionGroup.MigrationSources[targetMigrationSourceId];
                if (null == targetMigrationSourceConfig)
                {
                    return(retVal);
                }

                // find source-side migration source config
                RTSession  rtSession     = FindSessionForConflictedAction(conflict, context);
                BM.Session parentSession = null;
                foreach (BM.Session s in sessionGroupConfig.SessionGroup.Sessions.Session)
                {
                    if (new Guid(s.SessionUniqueId).Equals(rtSession.SessionUniqueId))
                    {
                        parentSession = s;
                        break;
                    }
                }
                if (parentSession == null)
                {
                    return(retVal);
                }
                Guid sourceMigrationSourceId = ((new Guid(parentSession.LeftMigrationSourceUniqueId)).Equals(targetMigrationSourceId))
                    ? new Guid(parentSession.RightMigrationSourceUniqueId) : new Guid(parentSession.LeftMigrationSourceUniqueId);
                BM.MigrationSource sourceMigrationSourceConfig = sessionGroupConfig.SessionGroup.MigrationSources[sourceMigrationSourceId];
                if (null == sourceMigrationSourceConfig)
                {
                    return(retVal);
                }

                string sourceServerUrl   = sourceMigrationSourceConfig.ServerUrl;
                string sourceTeamProject = sourceMigrationSourceConfig.SourceIdentifier;
                string targetServerUrl   = targetMigrationSourceConfig.ServerUrl;
                string targetTeamProject = targetMigrationSourceConfig.SourceIdentifier;

                string srcWorkItemIdStr = TfsMigrationWorkItemStore.GetSourceWorkItemId(conflict.ConflictedChangeAction);
                Debug.Assert(!string.IsNullOrEmpty(srcWorkItemIdStr), "srcWorkItemId is null or empty");
                int srcWorkItemId;
                if (!int.TryParse(srcWorkItemIdStr, out srcWorkItemId))
                {
                    return(retVal);
                }

                string srcRevRanges    = rule.DataFieldDictionary[HistoryNotFoundSubmitMissingChangesAction.DATAKEY_REVISION_RANGE];
                int[]  sourceRevToSync = new int[0];
                if (string.IsNullOrEmpty(srcRevRanges))
                {
                    sourceRevToSync = ExtractMissingRevs(conflict.ConflictedChangeAction);
                }
                else
                {
                    if (!IntegerRange.TryParseRangeString(srcRevRanges, out sourceRevToSync))
                    {
                        return(retVal);
                    }
                }
                if (sourceRevToSync.Length == 0)
                {
                    return(retVal);
                }

                try
                {
                    // compute delta from source side
                    TfsWITAnalysisProvider analysisProvider = new TfsWITAnalysisProvider(sourceServerUrl, sourceTeamProject);
                    WorkItem sourceWorkItem = analysisProvider.GetWorkItem(srcWorkItemId);

                    Hist.MigrationAction[] sourceRevDetails = new Hist.MigrationAction[sourceRevToSync.Length];
                    for (int revIndex = 0; revIndex < sourceRevToSync.Length; ++revIndex)
                    {
                        var details = new TfsWITRecordDetails(sourceWorkItem, sourceRevToSync[revIndex]);
                        SanitizeDetails(details);
                        translationService.MapWorkItemTypeFieldValues(
                            sourceWorkItem.Id.ToString(), details.DetailsDocument, sourceMigrationSourceId);

                        TfsConstants.ChangeActionId actionId = (sourceRevToSync[revIndex] == 1 ? TfsConstants.ChangeActionId.Add : TfsConstants.ChangeActionId.Edit);
                        sourceRevDetails[revIndex] = new Hist.MigrationAction(sourceWorkItem.Id.ToString(), details, actionId);
                    }

                    // migrate to target side
                    TfsWITMigrationProvider migrationProvider = new TfsWITMigrationProvider(targetServerUrl, targetTeamProject, string.Empty);
                    Hist.ConversionResult   conversionResult  = migrationProvider.ProcessChangeGroup(sourceRevDetails);

                    // update conversion history
                    ConversionResult convRslt = new ConversionResult(sourceMigrationSourceId, targetMigrationSourceId);
                    convRslt.ChangeId           = HistoryNotFoundResolutionChangeId;
                    convRslt.ContinueProcessing = true;

                    foreach (var itemConvHist in conversionResult.ItemConversionHistory)
                    {
                        convRslt.ItemConversionHistory.Add(new ItemConversionHistory(
                                                               itemConvHist.SourceItemId, itemConvHist.SourceItemVersion, itemConvHist.TargetItemId, itemConvHist.TargetItemVersion));
                    }

                    parentChangeGroup.SessionRunReference.Load();
                    int sessionRunId = parentChangeGroup.SessionRun.Id;
                    convRslt.Save(sessionRunId, sourceMigrationSourceId);
                }
                catch (Exception ex)
                {
                    TraceManager.TraceException(ex);
                    retVal.Comment = ex.ToString();
                    return(retVal);
                }
            }

            retVal.Resolved = true;
            return(retVal);
        }
        /// <summary>
        /// Try handling an exception
        /// </summary>
        /// <param name="e"></param>
        /// <param name="conflictManager"></param>
        /// <returns>The decision returned is either RoutedAsError or RaisedAsRuntimeConflict</returns>
        public ErrorHandlingResult TryHandleException(Exception e, ConflictManager conflictManager)
        {
            bool conflictManagementIsEnabled = (null != conflictManager);
            bool anErrorRouterIsFound        = false;
            bool exceptionIsRoutedAsError    = false;

            foreach (ErrorRouter errRouter in m_errRegService.RegisteredRouters)
            {
                ErrorHandlingResult rslt = errRouter.TryRouteError(e, this.m_routingChannels.AsReadOnly());
                switch (rslt.Decision)
                {
                case ErrorHandlingResult.RoutingDecision.RaisedAsRuntimeConflict:
                    anErrorRouterIsFound     = true;
                    exceptionIsRoutedAsError = true;
                    break;

                case ErrorHandlingResult.RoutingDecision.PolicyConditionIsNotMet:
                    anErrorRouterIsFound = true;
                    break;

                case ErrorHandlingResult.RoutingDecision.RoutedAsError:
                    return(rslt);

                default:
                    break;
                }

                if (anErrorRouterIsFound || exceptionIsRoutedAsError)
                {
                    break;
                }
            }

            if (exceptionIsRoutedAsError)
            {
                return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RoutedAsError));
            }

            if (conflictManagementIsEnabled)
            {
                MigrationConflict      conflict = GenericConflictType.CreateConflict(e);
                List <MigrationAction> actions;
                conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RaisedAsRuntimeConflict));
            }

            else if (anErrorRouterIsFound)
            {
                // no conflict manager to log the runtime conflict
                throw new MissingErrorRouterException(
                          "Runtime error does not meet the error routine policy and there is no conflict manager to log a conflict.",
                          e);
            }
            else
            {
                // no conflict manager is present to raise the error as a runtime conflict
                // - default to report as an error
                foreach (IErrorRoutingChannel channel in m_routingChannels)
                {
                    channel.RouteError(e);
                }
                return(new ErrorHandlingResult(ErrorHandlingResult.RoutingDecision.RoutedAsError));
            }
        }
Example #15
0
        private bool SubmitBatchedAddOrDeleteLinkChanges(
            List <XmlDocument> updateDocuments,
            Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap,
            ITranslationService translationService,
            ConfigurationService configService,
            ConflictManager conflictManager)
        {
            bool succeeded = true;

            UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray());
            if (results.Length != updateDocuments.Count)
            {
                throw new SynchronizationEngineException("Wrong number of link update results.");
            }

            for (int i = 0; i < results.Length; ++i)
            {
                UpdateResult rslt = results[i];

                if (rslt.Exception != null)
                {
                    if (rslt.Exception.Message.Contains("The specified link already exists"))
                    {
                        // it is ok to eat this exception
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSMulitpleParentLinkConflictType.SingleParentViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        MigrationConflict conflict = TFSMulitpleParentLinkConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                            succeeded = false;
                        }
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSCyclicLinkConflictType.CircularityLinkHierarchyViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider;
                        Debug.Assert(null != linkProvider, "linkProvider is NULL");

                        LinkChangeAction          conflictedAction = updateDocIndexToLinkChangeActionMap[i];
                        NonCyclicReferenceClosure linkRefClosure   =
                            linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact);

                        MigrationConflict conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                            succeeded = false;
                        }
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             rslt.Exception.Message.StartsWith(
                                 TFSModifyLockedWorkItemLinkConflictType.ModifyLockedWorkItemLinkViolationMessage,
                                 StringComparison.OrdinalIgnoreCase))
                    {
                        MigrationConflict conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                        }
                        // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                        succeeded = false;
                    }
                    else if (rslt.Exception is System.Web.Services.Protocols.SoapException &&
                             null != rslt.Exception.Message &&
                             (rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage1, StringComparison.OrdinalIgnoreCase) ||
                              rslt.Exception.Message.StartsWith(TFSLinkAccessViolationConflictType.LinkAccessViolationMessage2, StringComparison.OrdinalIgnoreCase)))
                    {
                        MigrationConflict conflict = TFSLinkAccessViolationConflictType.CreateConflict(
                            updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                        List <MigrationAction> actions;
                        var resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                        }
                        // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                        succeeded = false;
                    }
                    else
                    {
                        TraceManager.TraceError(rslt.Exception.ToString());
                        succeeded = false;
                        // TODO
                        // Try resolve conflict and push to backlog if resolution fails
                        updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                    }
                }
                else
                {
                    foreach (LinkChangeAction action in updateDocIndexToLinkChangeActionMap.Values)
                    {
                        MarkLinkChangeActionCompleted(action);
                    }

                    List <LinkChangeAction> updatedActions = new List <LinkChangeAction>(updateDocIndexToLinkChangeActionMap.Values);
                    if (rslt.Exception == null)
                    {
                        UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions);
                    }
                    else if (rslt.Exception.Message.Contains("The specified link already exists"))
                    {
                        WorkItemLinkStore relatedArtifactsStore = new WorkItemLinkStore(configService.SourceId);
                        relatedArtifactsStore.UpdateSyncedLinks(updatedActions);
                    }
                }
            }
            return(succeeded);
        }
Example #16
0
        private bool SubmitBatchedAddOrDeleteLinkChanges(
            List <XmlDocument> updateDocuments,
            Dictionary <int, LinkChangeAction> updateDocIndexToLinkChangeActionMap,
            ITranslationService translationService,
            ConfigurationService configService,
            ConflictManager conflictManager)
        {
            bool succeeded = true;

            UpdateResult[] results = TfsBatchUpdateHelper.Submit(Core, WorkItemServer, updateDocuments.ToArray());
            if (results.Length != updateDocuments.Count)
            {
                throw new SynchronizationEngineException("Wrong number of link update results.");
            }

            // Collect list of successful LinkChangeActions (for LinkTypes with GetsActionsFromLinkChangeHistory true) to pass to SetServerLinkChangeIds()
            List <LinkChangeAction> actionsNeedingServerLinkIdSet = new List <LinkChangeAction>();

            for (int i = 0; i < results.Length; ++i)
            {
                if (results[i] == null)
                {
                    continue;
                }

                UpdateResult rslt = results[i];

                if (rslt.Exception != null)
                {
                    MigrationConflict        conflict       = null;
                    ConflictResolutionResult resolutionRslt = null;
                    List <MigrationAction>   actions;
                    bool createWitGeneralConflict = false;

                    System.Web.Services.Protocols.SoapException soapException = rslt.Exception as System.Web.Services.Protocols.SoapException;
                    if (soapException != null)
                    {
                        int?tfsErrorNumber = GetTfsErrorNumberFromSoapException(soapException);

                        if (tfsErrorNumber.HasValue)
                        {
                            LinkChangeAction linkChangeAction = updateDocIndexToLinkChangeActionMap[i];
                            switch (tfsErrorNumber)
                            {
                            case TfsConstants.TfsError_AddLink_LinkExists:
                            case TfsConstants.TfsError_DeleteLink_LinkNotFound:
                                // it is ok to eat these exception and skip the action

                                // mark the change action completed so it is not retried later
                                linkChangeAction.Status = LinkChangeAction.LinkChangeActionStatus.Skipped;

                                if (tfsErrorNumber == TfsConstants.TfsError_AddLink_LinkExists)
                                {
                                    TraceManager.TraceInformation("Tried to add a link that already exists so skipping it: " + GetLinkChangeActionDescription(linkChangeAction));
                                }
                                else
                                {
                                    TraceManager.TraceInformation("Tried to delete a link that does not exist so skipping it: " + GetLinkChangeActionDescription(linkChangeAction));
                                }

                                if (soapException.Detail != null)
                                {
                                    TraceManager.TraceVerbose("SoapException.Detail.InnerXml for ignored exception: " + soapException.Detail.InnerXml);
                                }
                                break;

                            case TfsConstants.TfsError_AddLink_TooManyParents:
                                if (linkChangeAction.Group.IsForcedSync)
                                {
                                    if (DeleteExistingParentLinkToForceSyncAddLink(linkChangeAction, updateDocuments[i]))
                                    {
                                        break;
                                    }
                                }

                                conflict = TFSMulitpleParentLinkConflictType.CreateConflict(
                                    updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                                resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                                if (!resolutionRslt.Resolved)
                                {
                                    updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                                    succeeded = false;
                                }

                                break;

                            case TfsConstants.TfsError_AddLink_Circular:
                            case TfsConstants.TfsError_AddLink_ChildIsAncestor:
                                ILinkProvider linkProvider = ServiceContainer.GetService(typeof(ILinkProvider)) as ILinkProvider;
                                Debug.Assert(null != linkProvider, "linkProvider is NULL");

                                LinkChangeAction          conflictedAction = updateDocIndexToLinkChangeActionMap[i];
                                NonCyclicReferenceClosure linkRefClosure   =
                                    linkProvider.CreateNonCyclicLinkReferenceClosure(conflictedAction.Link.LinkType, conflictedAction.Link.SourceArtifact);

                                conflict = TFSCyclicLinkConflictType.CreateConflict(conflictedAction, rslt.Exception, linkRefClosure);

                                resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                                if (!resolutionRslt.Resolved)
                                {
                                    updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                                    succeeded = false;
                                }
                                break;

                            case TfsConstants.TfsError_LinkAuthorizationFailedLinkLocked:
                                conflict = TFSModifyLockedWorkItemLinkConflictType.CreateConflict(
                                    updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                                resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                                if (!resolutionRslt.Resolved)
                                {
                                    updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                                }
                                // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                                succeeded = false;
                                break;

                            case TfsConstants.TfsError_LinkAuthorizationFailed:
                            case TfsConstants.TfsError_LinkAuthorizationFailedNotServiceAccount:
                                conflict = TFSLinkAccessViolationConflictType.CreateConflict(
                                    updateDocIndexToLinkChangeActionMap[i], rslt.Exception);

                                resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                                if (!resolutionRslt.Resolved)
                                {
                                    updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                                }
                                // returning "not succeeded" so that the caller keeps this change group in "ReadyForMigration" status
                                succeeded = false;
                                break;

                            default:
                                // TFS error doesn't match any that we explicitly handle
                                TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges:TFS error number in SoapException not explictly handled: {0}", tfsErrorNumber);
                                createWitGeneralConflict = true;
                                break;
                            }
                        }
                        else
                        {
                            TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges: Unable to get TFS error number from SoapException: {0}", soapException.ToString());
                            createWitGeneralConflict = true;
                        }
                    }
                    else // Exception is not SoapException
                    {
                        TraceManager.TraceError("SubmitBatchedAddOrDeleteLinkChanges: Exception returned is not SoapException: {0}", rslt.Exception.ToString());
                        createWitGeneralConflict = true;
                    }

                    if (createWitGeneralConflict)
                    {
                        conflict = WitGeneralConflictType.CreateConflict(rslt.Exception);

                        resolutionRslt = conflictManager.TryResolveNewConflict(conflictManager.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            updateDocIndexToLinkChangeActionMap[i].IsConflicted = true;
                            succeeded = false;
                        }
                    }
                }
                else // rslt.Exception == null
                {
                    LinkChangeAction successfulAction = updateDocIndexToLinkChangeActionMap[i];
                    MarkLinkChangeActionCompleted(successfulAction);

                    TraceManager.TraceVerbose("Successful " + GetLinkChangeActionDescription(successfulAction));

                    List <LinkChangeAction> updatedActions = new List <LinkChangeAction>();
                    updatedActions.Add(successfulAction);

                    if (successfulAction.Link.LinkType.GetsActionsFromLinkChangeHistory)
                    {
                        actionsNeedingServerLinkIdSet.Add(successfulAction);
                    }

                    UpdateLinkConversionHistory(configService, translationService, rslt, updatedActions);
                }
            }

            SetServerLinkChangeIds(actionsNeedingServerLinkIdSet);

            return(succeeded);
        }
 public ConflictResolutionResult Resolve(System.ComponentModel.Design.IServiceContainer serviceContainer, MigrationConflict conflict, ConflictResolutionRule rule, out List <MigrationAction> actions)
 {
     actions = null;
     return(new ConflictResolutionResult(false, ConflictResolutionType.Other));
 }
Example #18
0
        private void analyzeFolder(string rootPath, int versionToBeSynced, ChangeGroup changeGroup)
        {
            Dictionary <string, bool> localFileItems      = new Dictionary <string, bool>();
            Dictionary <string, bool> localDirectoryItems = new Dictionary <string, bool>();
            Dictionary <string, bool> addItems            = new Dictionary <string, bool>();
            Dictionary <string, bool> deleteItems         = new Dictionary <string, bool>();

            string destinationTfsRootPath = TranslationService.GetMappedPath(rootPath, m_configurationService.SourceId);

            if (Directory.Exists(rootPath))
            {
                foreach (string path in Directory.GetDirectories(rootPath, "*", SearchOption.AllDirectories))
                {
                    localDirectoryItems.Add(path, false);
                }
                localDirectoryItems.Add(rootPath, false);

                foreach (string path in Directory.GetFiles(rootPath, "*", SearchOption.AllDirectories))
                {
                    localFileItems.Add(path, false);
                }
            }
            else if (File.Exists(rootPath))
            {
                localFileItems.Add(rootPath, false);
            }
            else
            {
                MigrationConflict deleteAllConfirmationConflict = VCUserPromptConflictType.CreateConflict(
                    string.Format("After comparing the local system with TFS, the folder {0} and all its sub items will be deleted on TFS server. Please choose 'Delete' to continue with the delete; or retry the migration once the local file system is ready.",
                                  destinationTfsRootPath),
                    versionToBeSynced.ToString());
                List <MigrationAction>   retActions;
                ConflictResolutionResult resolutionResult =
                    m_conflictManagementService.TryResolveNewConflict(m_configurationService.SourceId, deleteAllConfirmationConflict, out retActions);
                if ((!resolutionResult.Resolved) || (resolutionResult.ResolutionType != ConflictResolutionType.SkipConflictedChangeAction))
                {
                    markChangeGroupAsObsolete(changeGroup);
                    throw new MigrationUnresolvedConflictException(deleteAllConfirmationConflict);
                }
            }

            // We need a related branch that should be treated as the source for branches and merges.
            // TODO: Right now we assume this is the first parent that we find.  There should be a way to configure this.
            List <String> parents        = m_branchConfiguration.GetRIList(rootPath);
            String        parentRootPath = (parents == null) ? null : parents[0];

            TfsFileSystemRelatedBranchView relatedBranchView = new TfsFileSystemRelatedBranchView(rootPath, parentRootPath);

            ItemSet tfsItemSet;

            tfsItemSet = m_destinationTfs.GetItems(destinationTfsRootPath,
                                                   new ChangesetVersionSpec(versionToBeSynced),
                                                   RecursionType.Full);

            foreach (Item item in tfsItemSet.Items)
            {
                string localPath = TranslationService.GetMappedPath(item.ServerItem, m_configurationService.MigrationPeer);
                if (item.ItemType == ItemType.File)
                {
                    if (localFileItems.ContainsKey(localPath))
                    {
                        localFileItems[localPath] = true;
                        // Consolidate the computation of MD5 hash in toolkit
                        if (!Utils.ContentsMatch(localPath, item.HashValue))
                        {
                            createMigrationAction(changeGroup, WellKnownChangeActionId.Edit, localPath, false);

                            // If the contents in the edited file match the contents of the related file in the source branch
                            // then we should pend a merge
                            String relatedBranchItem;
                            if (relatedBranchView.TryGetRelatedBranchItem(localPath, false, out relatedBranchItem) &&
                                Utils.ContentsMatch(localPath, relatedBranchItem))
                            {
                                createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Merge, relatedBranchItem, localPath, false);
                            }
                        }
                    }
                    else
                    {
                        deleteItems.Add(localPath, false);
                    }
                }
                else
                {
                    if (localDirectoryItems.ContainsKey(localPath))
                    {
                        localDirectoryItems[localPath] = true;
                    }
                    else
                    {
                        deleteItems.Add(localPath, true);
                    }
                }
            }

            // Now add all directory items exist only on local system.
            foreach (KeyValuePair <string, bool> localItem in localDirectoryItems)
            {
                if (!localItem.Value)
                {
                    String relatedBranchItem;
                    if (relatedBranchView.TryGetRelatedBranchItem(localItem.Key, true, out relatedBranchItem))
                    {
                        // Create the branch. Since we are dealing with folders we don't need to worry about
                        // pending edits for different content.
                        createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Branch, relatedBranchItem, localItem.Key, true);
                    }
                    else
                    {
                        addItems.Add(localItem.Key, true);
                    }
                }
            }

            // Now add all file items exist only on local system.
            foreach (KeyValuePair <string, bool> localItem in localFileItems)
            {
                if (!localItem.Value)
                {
                    String relatedBranchItem;
                    if (relatedBranchView.TryGetRelatedBranchItem(localItem.Key, false, out relatedBranchItem))
                    {
                        // Create the branch.
                        createRelativeMigrationAction(changeGroup, WellKnownChangeActionId.Branch, relatedBranchItem, localItem.Key, false);

                        // If the contents of the file we are branching from and our local item are different
                        // then we will need to pend an edit as well.
                        if (!Utils.ContentsMatch(localItem.Key, relatedBranchItem))
                        {
                            createMigrationAction(changeGroup, WellKnownChangeActionId.Edit, localItem.Key, false);
                        }
                    }
                    else
                    {
                        addItems.Add(localItem.Key, false);
                    }
                }
            }

            if ((deleteItems.Count > 0) && (!m_renameListUpdated))
            {
                m_renameList = GetRenameList();
            }
            List <string> deleteItemToBeRemoved = new List <string>();

            if (m_renameList != null && m_renameList.Count > 0)
            {
                foreach (string deleteItem in deleteItems.Keys)
                {
                    string ancestryPath = deleteItem;
                    while (!Path.Equals(rootPath, ancestryPath))
                    {
                        if (m_renameList.ContainsKey(ancestryPath))
                        {
                            string renameToAncestryPath = m_renameList[ancestryPath];
                            string renameToPath         = string.Concat(renameToAncestryPath, deleteItem.Substring(ancestryPath.Length));
                            if (addItems.ContainsKey(renameToPath))
                            {
                                createRenameMigrationAction(changeGroup, deleteItem, renameToPath, deleteItems[deleteItem]);
                                addItems.Remove(renameToPath);
                                deleteItemToBeRemoved.Add(deleteItem);
                                break;
                            }
                        }
                        ancestryPath = Path.GetDirectoryName(ancestryPath);
                    }
                }
            }

            foreach (string addItem in addItems.Keys)
            {
                createMigrationAction(changeGroup, WellKnownChangeActionId.Add, addItem, addItems[addItem]);
            }
            foreach (string deleteItem in deleteItems.Keys)
            {
                // We have already transferred this delete to a rename, just continue.
                if (deleteItemToBeRemoved.Contains(deleteItem))
                {
                    continue;
                }
                createMigrationAction(changeGroup, WellKnownChangeActionId.Delete, deleteItem, deleteItems[deleteItem]);
            }
        }
        private void ModifyRecordContent(
            OAdEntity entity,
            IMigrationAction action,
            ConversionResult convRslt,
            List <string> skipFields)
        {
            XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column");

            if (null == columns)
            {
                throw new MigrationException(ClearQuestResource.ClearQuest_Error_InvalidActionDescription, action.ActionId);
            }

            // get the record's display name for updating conversion history
            string recordDisplayName = CQWrapper.GetEntityDisplayName(entity);

            // *********
            // cache the current history count for all "history fields"
            // i.e. pairs of HistoryFieldName, count
            Dictionary <string, int> recordHistoryCountCache = new Dictionary <string, int>();

            BuildRecordHistoryCountCache(entity, recordHistoryCountCache);

            SetRecordEditable(entity);

            StringBuilder updateLog = new StringBuilder();

            PrintUpdateLogHeader(action, updateLog);

            string entityDefName = CQWrapper.GetEntityDefName(entity);
            string stateTransitionFieldDefName = m_migrationContext.GetStateField(entityDefName);

            string retVal;
            bool   recordIsUpdated = false;

            foreach (XmlNode columnData in columns)
            {
                string stringVal = columnData.FirstChild.InnerText;
                string fieldName = columnData.Attributes["ReferenceName"].Value;
                Debug.Assert(!string.IsNullOrEmpty(fieldName),
                             "Field ReferenceName is absent in the Migration Description");

                if (CQStringComparer.FieldName.Equals(fieldName, stateTransitionFieldDefName) ||
                    (null != skipFields && skipFields.Contains(fieldName, CQStringComparer.FieldName)))
                {
                    // skip or "State" field, as it has already been submitted in a separate history/revision
                    continue;
                }

                bool         setFieldValue     = false;
                OAdFieldInfo aFieldInfo        = CQWrapper.GetEntityFieldValue(entity, fieldName);
                int          fieldRequiredness = CQWrapper.GetRequiredness(aFieldInfo);
                switch (fieldRequiredness)
                {
                case CQConstants.MANDATORY:
                case CQConstants.OPTIONAL:
                    setFieldValue = true;
                    break;

                case CQConstants.READONLY:
                    // [teyang] TODO conflict handling
                    TraceManager.TraceWarning("Field {0} is READONLY", fieldName);
                    setFieldValue = false;
                    break;

                case CQConstants.USEHOOK:
                    // [teyang] TODO conflict handling
                    TraceManager.TraceWarning("Field {0} is USEHOOK", fieldName);
                    setFieldValue = false;
                    break;

                default:
                    throw new InvalidOperationException();
                }

                if (setFieldValue)
                {
                    int attempt1Count = 0;
                    if (!SetFieldValue(action, entity, fieldName, stringVal, ref attempt1Count))
                    {
                        return;
                    }
                    AddFieldToUpdateLog(fieldName, stringVal, updateLog);
                    recordIsUpdated = true;
                }
            }

            if (!recordIsUpdated)
            {
                // no update has been made to the record, mark this action to be skipped
                CQWrapper.Revert(entity);
                if (action.State == ActionState.Pending)
                {
                    action.State = ActionState.Skipped;
                }

                return;
            }

            AddLineToUpdateLog(updateLog);
            int attempt2Count = 0;

            if (!SetFieldValue(action, entity, NoteEntryFieldName, updateLog.ToString(), ref attempt2Count))
            {
                return;
            }

            retVal = CQWrapper.Validate(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                IEnumerable <Microsoft.TeamFoundation.Migration.ClearQuestAdapter.CQTextParser.RecordValidationResult> validationResults;
                if (CQTextParser.RecordValidationTextParser.TryParse(retVal, out validationResults))
                {
                    foreach (CQTextParser.RecordValidationResult rslt in validationResults)
                    {
                        MigrationConflict      conflict = ClearQuestInvalidFieldValueConflictType.CreateConflict(rslt, action);
                        List <MigrationAction> actions;
                        var resolutionRslt = m_conflictManagerService.TryResolveNewConflict(m_conflictManagerService.SourceId, conflict, out actions);
                        if (!resolutionRslt.Resolved)
                        {
                            action.ChangeGroup.ContainsBackloggedAction = true;
                            return;
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException(retVal);
                }
            }

            retVal = CQWrapper.Commmit(entity);
            if (!string.IsNullOrEmpty(retVal))
            {
                // [teyang] TODO: invalid update conflict handling
                throw new InvalidOperationException(retVal);
            }

            if (action.State == ActionState.Pending)
            {
                action.State = ActionState.Complete;
            }

            // *********
            // now comparing to the cache, so that we can clearly identify the item:version pairs
            // e.g. TargetCQRecordDisplayName : HistoryFieldName::LatestHistoryIndex
            Dictionary <string, int[]> updatedHistoryIndices = new Dictionary <string, int[]>();

            FindUpdatedHistoryIndices(entity, recordHistoryCountCache, updatedHistoryIndices);
            recordHistoryCountCache.Clear();

            foreach (string histFieldName in updatedHistoryIndices.Keys)
            {
                foreach (int histIndex in updatedHistoryIndices[histFieldName])
                {
                    UpdateConversionHistory(action,
                                            recordDisplayName,
                                            CQHistoryMigrationItem.CreateHistoryItemVersion(histFieldName, histIndex),
                                            convRslt);
                }
            }
        }
Example #20
0
 public bool CanResolve(MigrationConflict conflict, ConflictResolutionRule rule)
 {
     return(string.Equals(conflict.ScopeHint, rule.ApplicabilityScope, StringComparison.OrdinalIgnoreCase));
 }
        private bool SetFieldValue(
            IMigrationAction action,
            OAdEntity record,
            string fieldName,
            string stringVal,
            ref int numOfAttempts)
        {
            numOfAttempts++;

            OAdFieldInfo aFieldInfo         = CQWrapper.GetEntityFieldValue(record, fieldName);
            string       originalFieldValue = CQWrapper.GetFieldValue(aFieldInfo);

            // doing the real job: setting field value with CQ OM
            string cqRetVal = CQWrapper.SetFieldValue(record, fieldName, stringVal);

            // error handling
            if (!string.IsNullOrEmpty(cqRetVal))
            {
                MigrationConflict conflict = ClearQuestSetFieldValueConflictType.CreateConflict(
                    UtilityMethods.ExtractSourceWorkItemId(action),
                    UtilityMethods.ExtractSourceWorkItemRevision(action),
                    fieldName, stringVal, cqRetVal);
                List <MigrationAction> migrationActions;
                var resolutionResult = m_conflictManagerService.TryResolveNewConflict(
                    m_conflictManagerService.SourceId,
                    conflict,
                    out migrationActions);

                if (!resolutionResult.Resolved)
                {
                    // cannot resolve the conflict, move on to next MigrationAction
                    return(false);
                }
                else if (numOfAttempts <= 3)
                {
                    // not reached maximum set value attempts yet
                    if (resolutionResult.ResolutionType == ConflictResolutionType.UpdatedConflictedChangeAction)
                    {
                        XmlNode column = UtilityMethods.ExtractSingleFieldNodeFromMigrationDescription(
                            action.MigrationActionDescription, fieldName);

                        if (null == column)
                        {
                            // the field has been dropped during conflict resolution
                            // restore the "original" value
                            return(SetFieldValue(action, record, fieldName, originalFieldValue, ref numOfAttempts));
                        }
                        else
                        {
                            string newFieldValue = UtilityMethods.ExtractSingleFieldValue(column);
                            return(SetFieldValue(action, record, fieldName, stringVal, ref numOfAttempts));
                        }
                    }
                }
                else
                {
                    // reached max set value attempts WITH unresolved conflict
                    return(false);
                }
            }

            return(true);
        }