/// <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); }
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); }
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); }
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); } }
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); } }
/// <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); } } } }
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); } }
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); } }
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); } }
/// <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; }
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); } }
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; }