示例#1
0
        /// <summary>
        /// Create a basic action.
        /// </summary>
        /// <param name="changeItem">The actual change</param>
        /// <param name="group">The change group that is the container for the current changes</param>
        /// <param name="actionId">The change action id that describes the change type</param>
        /// <returns></returns>
        private IMigrationAction createMigrationAction(Change changeItem, string fromPath, ChangeGroup group, Guid actionId)
        {
            IMigrationAction action = group.CreateAction(
                actionId,
                new SubversionMigrationItem(changeItem),
                fromPath,
                changeItem.Path,
                null,
                null,
                changeItem.ItemType.ReferenceName,
                null);

            return(action);
        }
示例#2
0
 private void createRelativeMigrationAction(ChangeGroup changeGroup, Guid actionId, String relatedBranchLocalPath, String localPath, Boolean isDirectory)
 {
     IMigrationAction action = changeGroup.CreateAction(
         actionId,
         new TfsFileSystemMigrationItem(localPath, isDirectory),
         relatedBranchLocalPath,
         localPath,
         "T",
         "T",
         isDirectory ? WellKnownContentType.VersionControlledFolder.ReferenceName
                     : WellKnownContentType.VersionControlledFile.ReferenceName,
         null,
         m_contentConflictDetectionOnly);
 }
示例#3
0
 private void createMigrationAction(ChangeGroup changeGroup, Guid actionId, string localPath, bool isDirectory)
 {
     IMigrationAction action = changeGroup.CreateAction(
         actionId,
         new TfsFileSystemMigrationItem(localPath, isDirectory),
         null,
         localPath,
         null,
         null,
         isDirectory ? WellKnownContentType.VersionControlledFolder.ReferenceName
                     : WellKnownContentType.VersionControlledFile.ReferenceName,
         null,
         m_contentConflictDetectionOnly);
 }
示例#4
0
        private void createRenameMigrationAction(ChangeGroup changeGroup, string localPathFrom, string localPath, bool isDirectory)
        {
            IMigrationAction action = changeGroup.CreateAction(
                WellKnownChangeActionId.Rename,
                new TfsFileSystemMigrationItem(localPath, isDirectory),
                localPathFrom,
                localPath,
                null,
                null,
                isDirectory ? WellKnownContentType.VersionControlledFolder.ReferenceName
                            : WellKnownContentType.VersionControlledFile.ReferenceName,
                null,
                m_contentConflictDetectionOnly);

            // For rename of file, also add an Edit action.
            if (!isDirectory)
            {
                createMigrationAction(changeGroup, WellKnownChangeActionId.Edit, localPath, false);
            }
        }
        /// <summary>
        /// Basic action handler that copy all fields of given action
        /// </summary>
        /// <param name="action"></param>
        /// <param name="group"></param>
        public override void BasicActionHandler(MigrationAction action, ChangeGroup group)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            if (group == null)
            {
                throw new ArgumentNullException("group");
            }

            group.CreateAction(action.Action,
                               action.SourceItem,
                               action.FromPath,
                               action.Path,
                               action.Version,
                               action.MergeVersionTo,
                               action.ItemTypeReferenceName,
                               action.MigrationActionDescription);
        }
        private void AddOrcasCompatibleWITD(ChangeGroup group)
        {
            Project     p = m_migrationSource.WorkItemStore.WorkItemStore.Projects[m_migrationSource.WorkItemStore.Core.Config.Project];
            XmlDocument workItemTypesDoc = m_migrationSource.WorkItemStore.GetWorkItemTypes(p);

            byte[] newDocHash  = new byte[0];
            bool   hashMatched = m_md5Utility.CompareDocHash(workItemTypesDoc, m_witdDocMD5, ref newDocHash);

            if (!hashMatched)
            {
                group.CreateAction(
                    WellKnownChangeActionId.SyncContext,
                    new WorkItemContextSyncMigrationItem(WellKnownContentType.Tfs2008WorkItemFieldMetadata),
                    WellKnownContentType.Tfs2008WorkItemFieldMetadata.FriendlyName,
                    "",
                    "0",
                    "",
                    WellKnownContentType.Tfs2008WorkItemFieldMetadata.ReferenceName,
                    workItemTypesDoc);
                m_md5Utility.UpdateDocHash(ref m_witdDocMD5, newDocHash);
            }
        }
示例#7
0
        private void ProcessFolderBranch(Change change, ChangeGroup group)
        {
            var        sourceBaseUri      = change.CopyFromFullServerPath;
            var        destinationBaseUri = change.FullServerPath;
            var        repositoryUri      = new Uri(change.Changeset.Repository);
            Repository repository         = Repository.GetRepository(repositoryUri);

            //We have to query the list of all files based on the branch source.
            //Subversion only pends one recursive branch action rather than a action for all files
            //Therefore we have to resolve this list manually

            var items = repository.GetItems(change.CopyFromFullServerPath, change.CopyFromRevision, true);

            //pend an action for every single item
            //We do not have to handle the root folder individually since it is one item in the collection already
            //we do not have to cover the branch | edit case either because there is an additional record in the changelist alredy
            foreach (var sourceItem in items)
            {
                var destinationUri = PathUtils.RebaseUri(new Uri(sourceItem.FullServerPath),
                                                         new Uri(sourceBaseUri),
                                                         new Uri(destinationBaseUri));

                var destinationPath = PathUtils.ExtractPath(repositoryUri, destinationUri);

                var migrationItem = new SubversionMigrationItem(repositoryUri,
                                                                destinationUri,
                                                                change.Changeset.Revision,
                                                                sourceItem.ItemType);

                group.CreateAction(WellKnownChangeActionId.Branch,
                                   migrationItem,
                                   sourceItem.Path,
                                   destinationPath.OriginalString,
                                   change.CopyFromRevision.ToString(),
                                   null,
                                   change.ItemType.ReferenceName,
                                   null);
            }
        }
        private void AddUserGroup(ChangeGroup group)
        {
            Project p = m_migrationSource.WorkItemStore.WorkItemStore.Projects[m_migrationSource.WorkItemStore.Core.Config.Project];

            XmlDocument groupsDoc = new XmlDocument();
            XmlElement  root      = groupsDoc.CreateElement("UserGroups");

            groupsDoc.AppendChild(root);
            XmlElement globGroupNode = groupsDoc.CreateElement("GlobalGroups");

            root.AppendChild(globGroupNode);
            XmlElement projGroupNode = groupsDoc.CreateElement("ProjectGroups");

            root.AppendChild(projGroupNode);

            Identity[] globalGroups = m_migrationSource.WorkItemStore.GetGlobalGroups(p);
            AddToGroupsDoc(groupsDoc, globGroupNode, globalGroups);

            Identity[] projectGroups = m_migrationSource.WorkItemStore.GetProjectGroups(p);
            AddToGroupsDoc(groupsDoc, projGroupNode, projectGroups);

            byte[] newDocHash  = new byte[0];
            bool   hashMatched = m_md5Utility.CompareDocHash(groupsDoc, m_userAccountsDocMD5, ref newDocHash);

            if (!hashMatched)
            {
                group.CreateAction(
                    WellKnownChangeActionId.SyncContext,
                    new WorkItemContextSyncMigrationItem(WellKnownContentType.UserGroupList),
                    WellKnownContentType.UserGroupList.FriendlyName,
                    "",
                    "0",
                    "",
                    WellKnownContentType.UserGroupList.ReferenceName,
                    groupsDoc);
                m_md5Utility.UpdateDocHash(ref m_userAccountsDocMD5, newDocHash);
            }
        }
示例#9
0
        /// <summary>
        /// This method allows the implementing class to add file property metadata for any files
        /// that are added or changed during a migration/sync session.
        /// </summary>
        /// <param name="serviceContainer">A service container that provides access to services provided by the
        /// TFS Integration Platform Toolkit</param>
        /// <param name="changeGroup">The change group being migrated for file property metadata can be generated
        /// by adding FileProperty change actions to the ChangeGroup</param>
        private void AddFilePropertiesToChangeGroup(IServiceContainer serviceContainer, ChangeGroup changeGroup)
        {
            ChangeGroupService changeGroupService = (ChangeGroupService)serviceContainer.GetService(typeof(ChangeGroupService));

            // This FilePropertiesAnalysisAddin adds two single properties to each item:
            //      The change group identifier from the source from which is was migrated
            //      The owner of the change group
            FileMetadataProperties fileProperties = new FileMetadataProperties();

            fileProperties.Add(FilePropertiesAnalysisAddinResources.SourceChangeGroupIdKey, changeGroup.Name);
            fileProperties.Add(FilePropertiesAnalysisAddinResources.SourceChangeGroupOwnerKey, changeGroup.Owner);
            XmlDocument filePropertiesXmlDoc = fileProperties.ToXmlDocument();

            IMigrationAction[] currentActions = new IMigrationAction[changeGroup.Actions.Count];
            changeGroup.Actions.CopyTo(currentActions, 0);
            foreach (IMigrationAction action in currentActions)
            {
                if (string.Equals(action.ItemTypeReferenceName, WellKnownContentType.VersionControlledFile.ReferenceName, StringComparison.Ordinal) ||
                    string.Equals(action.ItemTypeReferenceName, WellKnownContentType.VersionControlledFolder.ReferenceName, StringComparison.Ordinal))
                {
                    if (action.Action == WellKnownChangeActionId.Add ||
                        action.Action == WellKnownChangeActionId.Edit ||
                        action.Action == WellKnownChangeActionId.Rename ||
                        action.Action == WellKnownChangeActionId.Undelete)
                    {
                        IMigrationAction addFilePropertiesAction = changeGroup.CreateAction(
                            WellKnownChangeActionId.AddFileProperties,
                            action.SourceItem,
                            action.FromPath,
                            action.Path,
                            action.Version,
                            null,
                            action.ItemTypeReferenceName,
                            filePropertiesXmlDoc);
                    }
                }
            }
        }
示例#10
0
        private void ProcessFileBranch(Change change, ChangeGroup group)
        {
            //Remark: We do not really check wether the revision exists. We assume that the
            //source repository is consistent. If the revision does not exists though,
            //the destinatino adapter will have an issue to execute the branch and will
            //therefore rise and proper exception. Therefore this issue will be handleded during
            //the migration

            group.CreateAction(WellKnownChangeActionId.Branch,
                               new SubversionMigrationItem(change),
                               change.CopyFromPath,
                               change.Path,
                               change.CopyFromRevision.ToString(),
                               null,
                               change.ItemType.ReferenceName,
                               null);

            //we have to check wether the file has been modified. If this is the case we have to pend an aditional edit
            if (HasContentChanges(change))
            {
                createMigrationAction(change, change.Path, group, WellKnownChangeActionId.Edit);
            }
        }
示例#11
0
        internal ChangeGroup GetChangeGroupForLatestAttachments(ChangeGroupService changeGroupService)
        {
            List <TfsMigrationFileAttachment> files = new List <TfsMigrationFileAttachment>();

            if (WorkItem.Attachments.Count == 0)
            {
                return(null);
            }
            else
            {
                foreach (Attachment attachment in WorkItem.Attachments)
                {
                    files.Add(new TfsMigrationFileAttachment(attachment, m_core.TfsTPC.Uri.AbsoluteUri));
                }

                Guid        changeActionId = WellKnownChangeActionId.AddAttachment;
                ChangeGroup changeGroup    = changeGroupService.CreateChangeGroupForDeltaTable(
                    string.Format("{0}:{1}", WorkItem.Id, "Attachments"));
                foreach (TfsMigrationFileAttachment attachmentFile in files)
                {
                    XmlDocument migrationActionDetails = CreateAttachmentDescriptionDoc(attachmentFile, WorkItem.Rev.ToString());
                    changeGroup.CreateAction(
                        changeActionId,
                        attachmentFile,
                        WorkItem.Id.ToString(),
                        "",
                        "0",
                        "",
                        WellKnownContentType.WorkItem.ReferenceName,
                        migrationActionDetails);
                    TraceManager.TraceVerbose(String.Format("Generating AddAttachment change action: Work Item: {0}, Attachment File: {1}",
                                                            WorkItem.Id.ToString(), attachmentFile.Name));
                }

                return(changeGroup);
            }
        }
示例#12
0
        private void generateDeltaTableForSnapshot(List <string> paths, int snapshotChangeset)
        {
            List <string> pathsToGet          = new List <string>();
            VersionSpec   snapshotVersionSpec = new ChangesetVersionSpec(snapshotChangeset);

            foreach (string mappingPath in paths)
            {
                // Always query at one level down the mapping
                ItemSet itemSet = m_tfsClient.GetItems(mappingPath, snapshotVersionSpec, RecursionType.OneLevel);
                Item[]  items   = itemSet.Items;
                foreach (Item childItem in items)
                {
                    // Avoid the item itself.
                    if (!VersionControlPath.Equals(childItem.ServerItem, mappingPath))
                    {
                        pathsToGet.Add(childItem.ServerItem);
                    }
                }
            }

            int         countDownToCreateNewChangeGroup = m_snapshotCheckinBatchSize;
            ChangeGroup batchGroup = createChangeGroupForSnapshot(snapshotChangeset, snapshotChangeset);

            foreach (string path in pathsToGet)
            {
                TraceManager.TraceInformation("Getting snapshot at changeset: {0}, path: {1}", snapshotChangeset, path);
                ItemSet itemSet = m_tfsClient.GetItems(path, snapshotVersionSpec, RecursionType.Full);
                Item[]  items   = itemSet.Items;
                itemSet = null;
                TraceManager.TraceInformation("Snapshot contains {0} items", items.Length);
                for (int i = 0; i < items.Length; i++)
                {
                    if (FindMappedPath(items[i].ServerItem) != null)
                    {
                        countDownToCreateNewChangeGroup--;
                        if (countDownToCreateNewChangeGroup == 0)
                        {
                            TraceManager.TraceInformation("Saving {0} change actions", m_snapshotCheckinBatchSize);
                            batchGroup.Save();

                            batchGroup.Actions.Clear();
                            batchGroup = null;

                            batchGroup = createChangeGroupForSnapshot(snapshotChangeset, snapshotChangeset);
                            countDownToCreateNewChangeGroup = m_snapshotCheckinBatchSize;
                            TraceManager.TraceInformation("Saved {0} change actions", snapshotChangeset);
                        }
                        batchGroup.CreateAction(
                            WellKnownChangeActionId.Add,
                            new TfsMigrationItem(items[i]),
                            null,
                            items[i].ServerItem,
                            null,
                            null,
                            TfsAnalysisAlgorithms.convertContentType(items[i].ItemType),
                            null);
                    }
                    items[i] = null; // Dispose this object to reduce memory consumption.
                }
            }

            if (batchGroup.Actions.Count > 0)
            {
                int numRemainingItems = batchGroup.Actions.Count;
                TraceManager.TraceInformation("Saving {0} change actions", numRemainingItems);
                batchGroup.Save();
                TraceManager.TraceInformation("Saved {0} change actions", numRemainingItems);
            }
        }
示例#13
0
        /// <summary>
        /// Create a changegroup that contains all change actions needed to bring a migration target to the specificed snapshot
        /// </summary>
        /// <param name="changeGroupName">The change group name of the snapshot</param>
        private void generateSnapshotForVCSession()
        {
            foreach (var setting in ConfigurationService.VcCustomSetting.Settings.Setting)
            {
                if (setting.SettingKey == "SnapshotStartPoint")
                {
                    m_sessionLevelSnapshotChangeset = parseSnapShotStartPoint(setting.SettingValue);
                }
                else if (setting.SettingKey == "SnapshotBatchSize")
                {
                    try
                    {
                        m_snapshotCheckinBatchSize = int.Parse(setting.SettingValue);
                    }
                    catch (Exception)
                    {
                        // wrong format, use the default batch size
                    }
                }
            }

            m_hwmDelta.Reload();
            if (m_hwmDelta.Value >= m_sessionLevelSnapshotChangeset)
            {
                // We've already passed snapshot changeset Id, just return.
                m_sessionlevelSnapshotCompleted = true;
                return;
            }

            VersionSpec   snapshotVersionSpec = new ChangesetVersionSpec(m_sessionLevelSnapshotChangeset);
            List <string> pathsToGet          = new List <string>();

            foreach (MappingEntry mappingEntry in ConfigurationService.Filters)
            {
                if (mappingEntry.Cloak)
                {
                    continue;
                }

                // Always query at one level down the mapping
                ItemSet itemSet = m_tfsClient.GetItems(mappingEntry.Path, snapshotVersionSpec, RecursionType.OneLevel);
                Item[]  items   = itemSet.Items;
                foreach (Item childItem in items)
                {
                    // Avoid the item itself.
                    if (!VersionControlPath.Equals(childItem.ServerItem, mappingEntry.Path))
                    {
                        pathsToGet.Add(childItem.ServerItem);
                    }
                }
            }

            int         countDownToCreateNewChangeGroup = m_snapshotCheckinBatchSize;
            int         batchExecutionOrder             = m_sessionLevelSnapshotChangeset;
            ChangeGroup batchGroup = createChangeGroupForSnapshot(m_sessionLevelSnapshotChangeset, batchExecutionOrder);

            foreach (string path in pathsToGet)
            {
                TraceManager.TraceInformation("Getting snapshot at changeset: {0}, path: {1}", m_sessionLevelSnapshotChangeset, path);
                ItemSet itemSet = m_tfsClient.GetItems(path, snapshotVersionSpec, RecursionType.Full);
                Item[]  items   = itemSet.Items;
                itemSet = null;
                TraceManager.TraceInformation("Snapshot contains {0} items", items.Length);
                for (int i = 0; i < items.Length; i++)
                {
                    // We want to include the situation where a snapshot on a path is the same as the snapshot of the VC session.
                    // In this situation, we want to include the item in the session snapshot changeset.
                    // So we use changesetId + 1 as the reference changeset id.
                    if (IsPathMapped(items[i].ServerItem, m_sessionLevelSnapshotChangeset + 1) == MappingResult.Mapped)
                    {
                        countDownToCreateNewChangeGroup--;
                        if (countDownToCreateNewChangeGroup == 0)
                        {
                            TraceManager.TraceInformation("Saving {0} change actions", m_snapshotCheckinBatchSize);
                            batchGroup.Save();

                            batchGroup.Actions.Clear();
                            batchGroup = null;

                            batchExecutionOrder--;
                            batchGroup = createChangeGroupForSnapshot(m_sessionLevelSnapshotChangeset, batchExecutionOrder);
                            countDownToCreateNewChangeGroup = m_snapshotCheckinBatchSize;
                            TraceManager.TraceInformation("Saved {0} change actions", m_snapshotCheckinBatchSize);
                        }
                        batchGroup.CreateAction(
                            WellKnownChangeActionId.Add,
                            new TfsMigrationItem(items[i]),
                            null,
                            items[i].ServerItem,
                            null,
                            null,
                            TfsAnalysisAlgorithms.convertContentType(items[i].ItemType),
                            null);
                    }
                    items[i] = null; // Dispose this object to reduce memory consumption.
                }
            }

            if (batchGroup.Actions.Count > 0)
            {
                int numRemainingItems = batchGroup.Actions.Count;
                TraceManager.TraceInformation("Saving {0} change actions", numRemainingItems);
                batchGroup.Save();
                TraceManager.TraceInformation("Saved {0} change actions", numRemainingItems);
            }

            m_hwmDelta.Update(m_sessionLevelSnapshotChangeset);
            m_changeGroupService.PromoteDeltaToPending();
            m_sessionlevelSnapshotCompleted = true;
        }
示例#14
0
        internal void ComputeFieldDelta(
            ChangeGroupService changeGroupService,
            DateTime waterMarkChangeStartTime,
            FieldValueComparer tfsValueComparer,
            ITranslationService translationService,
            ConfigurationService configService,
            List <ChangeGroup> groups,
            IsWorkItemRevisionProcessed processedRevCallBack)
        {
            Guid sourceId = configService.SourceId;

            List <Revision> revsToBeSynced = FindUnsyncedRevisions(waterMarkChangeStartTime,
                                                                   translationService,
                                                                   sourceId,
                                                                   processedRevCallBack);

            Dictionary <int, object> fieldValueBaseline = new Dictionary <int, object>();

            TryEstablishFieldValueBaseline(fieldValueBaseline, revsToBeSynced);

            foreach (Revision rev in revsToBeSynced)
            {
                // get basic revision info: revision#, author#, and change time
                int    revIndex = (int)rev.Fields[CoreField.Rev].Value;
                string author   = (string)rev.Fields[CoreField.ChangedBy].Value;
                if (string.IsNullOrEmpty(author))
                {
                    author = (string)rev.Fields[CoreField.AuthorizedAs].Value;
                }
                DateTime changedDate = (DateTime)rev.Fields[CoreField.ChangedDate].Value;

                List <Field> fieldForSync   = new List <Field>();
                List <Field> skippingFields = new List <Field>();
                foreach (Field f in rev.Fields)
                {
                    // filter out System.History with empty new value
                    if (TFStringComparer.FieldName.Equals(f.ReferenceName, CoreFieldReferenceNames.History))
                    {
                        if (string.IsNullOrEmpty(f.Value as string))
                        {
                            continue;
                        }
                    }

                    if (MustTakeField(f.FieldDefinition))
                    {
                        // find out fields that changed in this revision
                        object oldValue;
                        fieldValueBaseline.TryGetValue(f.Id, out oldValue);
                        //***Note: When it is a new work item (unmatched on the other side),
                        //         we need to always include fields
                        if ((null != f.Value && (!tfsValueComparer.Equals(oldValue, f.Value) || revIndex == 1)) ||
                            (null == f.Value && null != oldValue && revIndex != 1))
                        {
                            fieldForSync.Add(f);
                            fieldValueBaseline[f.Id] = f.Value;
                        }
                        else if (IsReferencedField(f, configService))
                        {
                            skippingFields.Add(f);
                        }
                    }
                    else if (IsReferencedField(f, configService))
                    {
                        skippingFields.Add(f);
                    }
                }

                if (fieldForSync.Count == 0)
                {
                    continue;
                }

                XmlDocument migrationActionDetails = CreateFieldRevisionDescriptionDoc(
                    revIndex, author, changedDate, fieldForSync, skippingFields);

                Guid changeActionId = revIndex == 1 ?
                                      WellKnownChangeActionId.Add : WellKnownChangeActionId.Edit;

                /// TODO: consider batching revs of different workitems in one change group
                ChangeGroup changeGroup = changeGroupService.CreateChangeGroupForDeltaTable(
                    string.Format("{0}:{1}", WorkItem.Id, revIndex));
                IMigrationAction action = changeGroup.CreateAction(
                    changeActionId,
                    new TfsWITMigrationItem(WorkItem, revIndex),
                    WorkItem.Id.ToString(),
                    "",
                    revIndex.ToString(),
                    "",
                    WellKnownContentType.WorkItem.ReferenceName,
                    migrationActionDetails);

                groups.Add(changeGroup);
            }
        }
示例#15
0
        internal void ComputeAttachmentDelta(
            ChangeGroupService changeGroupService,
            DateTime waterMarkChangeStartTime,
            ITranslationService translationService,
            Guid sourceId,
            List <ChangeGroup> groups)
        {
            List <TfsMigrationFileAttachment> files = new List <TfsMigrationFileAttachment>();

            if (WorkItem.Attachments.Count > 0)
            {
                List <Revision> revsToBeSynced = FindUnsyncedRevisions(waterMarkChangeStartTime,
                                                                       translationService,
                                                                       sourceId,
                                                                       null);

                bool hasAttachmentChanges = false;
                foreach (Revision rev in revsToBeSynced)
                {
                    if (rev.Index == 0 &&
                        (int)rev.Fields[CoreField.AttachedFileCount].Value > 0)
                    {
                        hasAttachmentChanges = true;
                        break;
                    }

                    if (rev.Index > 0)
                    {
                        int      currAttchCount = (int)rev.Fields[CoreField.AttachedFileCount].Value;
                        Revision prevRev        = rev.WorkItem.Revisions[rev.Index - 1];
                        int      prevAttchCount = (int)prevRev.Fields[CoreField.AttachedFileCount].Value;
                        if (currAttchCount != prevAttchCount)
                        {
                            hasAttachmentChanges = true;
                            break;
                        }
                    }
                }

                if (!hasAttachmentChanges)
                {
                    return;
                }

                foreach (Attachment attachment in WorkItem.Attachments)
                {
                    if (attachment.AttachedTimeUtc <= waterMarkChangeStartTime ||
                        !attachment.IsSaved)
                    {
                        continue;
                    }
                    files.Add(new TfsMigrationFileAttachment(attachment));
                }
            }

            Guid        changeActionId = WellKnownChangeActionId.AddAttachment;
            ChangeGroup changeGroup    = changeGroupService.CreateChangeGroupForDeltaTable(
                string.Format("{0}:{1}", WorkItem.Id, "Attachments"));

            foreach (TfsMigrationFileAttachment attachmentFile in files)
            {
                XmlDocument migrationActionDetails = CreateAttachmentDescriptionDoc(attachmentFile, WorkItem.Rev.ToString());
                changeGroup.CreateAction(
                    changeActionId,
                    attachmentFile,
                    WorkItem.Id.ToString(),
                    "",
                    "0",
                    "",
                    WellKnownContentType.WorkItem.ReferenceName,
                    migrationActionDetails);
            }

            // VERY IMPORTANT: use the RelatedArtifactsStore to detect detailed attachment changes
            WorkItemAttachmentStore       store = new WorkItemAttachmentStore(sourceId);
            List <FileAttachmentMetadata> additionalAttachmentToDelete;

            store.UpdatePerItemAttachmentChangesByCheckingRelatedItemRecords(
                WorkItem.Id.ToString(), changeGroup, out additionalAttachmentToDelete);

            foreach (FileAttachmentMetadata attch in additionalAttachmentToDelete)
            {
                TfsMigrationFileAttachment attachmentFile = new TfsMigrationFileAttachment(attch);
                XmlDocument migrationActionDetails        = CreateAttachmentDescriptionDoc(attachmentFile, WorkItem.Rev.ToString());
                changeGroup.CreateAction(
                    WellKnownChangeActionId.DelAttachment,
                    attachmentFile,
                    WorkItem.Id.ToString(),
                    "",
                    "0",
                    "",
                    WellKnownContentType.WorkItem.ReferenceName,
                    migrationActionDetails);
            }

            groups.Add(changeGroup);
        }
        private void generateSnapshotForVCSession()
        {
            foreach (var setting in m_configurationService.VcCustomSetting.Settings.Setting)
            {
                if (setting.SettingKey == "SnapshotStartPoint")
                {
                    m_sessionLevelSnapshotTime = parseSnapShotStartPoint(setting.SettingValue);
                }
            }

            m_hwmDelta.Reload();
            if (m_hwmDelta.Value >= m_sessionLevelSnapshotTime)
            {
                // We've already passed snapshot changeset Id, just return.
                m_sessionlevelSnapshotCompleted = true;
                return;
            }

            ChangeGroup snapshotGroup = createChangeGroupForSnapshot(m_sessionLevelSnapshotTime, 0);

            m_clearCaseServer.SetConfigSpecForSnapshotStartPoint(m_sessionLevelSnapshotTime);

            try
            {
                foreach (MappingEntry mappingEntry in m_configurationService.Filters)
                {
                    if (mappingEntry.Cloak)
                    {
                        continue;
                    }
                    string localMappingPath = m_clearCaseServer.GetViewLocalPathFromServerPath(mappingEntry.Path);
                    foreach (string subDirectory in Directory.GetDirectories(localMappingPath, "*", SearchOption.AllDirectories))
                    {
                        string serverPath = m_clearCaseServer.GetServerPathFromViewLocalPath(subDirectory);
                        snapshotGroup.CreateAction(
                            WellKnownChangeActionId.Add,
                            new ClearCaseMigrationItem(
                                m_clearCaseServer.ViewName,
                                m_clearCaseServer.ApplicationClass.get_Element(serverPath).Version.ExtendedPath,
                                true),
                            null,
                            serverPath,
                            null,
                            null,
                            WellKnownContentType.VersionControlledFolder.ReferenceName,
                            null);
                    }
                    foreach (string subFile in Directory.GetFiles(localMappingPath, "*", SearchOption.AllDirectories))
                    {
                        string serverPath = m_clearCaseServer.GetServerPathFromViewLocalPath(subFile);
                        snapshotGroup.CreateAction(
                            WellKnownChangeActionId.Add,
                            new ClearCaseMigrationItem(
                                m_clearCaseServer.ViewName,
                                m_clearCaseServer.ApplicationClass.get_Element(serverPath).Version.ExtendedPath,
                                true),
                            null,
                            serverPath,
                            null,
                            null,
                            WellKnownContentType.VersionControlledFile.ReferenceName,
                            null);
                    }
                }
            }
            finally
            {
                m_clearCaseServer.ResetConfigSpec();
            }


            snapshotGroup.Save();
            m_hwmDelta.Update(m_sessionLevelSnapshotTime);
            m_changeGroupService.PromoteDeltaToPending();
            m_sessionlevelSnapshotCompleted = true;
        }