private WorkItem ReplayRevisions(List <RevisionItem> revisionsToMigrate, WorkItem sourceWorkItem, WorkItem targetWorkItem, Project destProject, WorkItemStoreContext sourceStore, int current, WorkItemStoreContext targetStore) { try { foreach (var revision in revisionsToMigrate) { var currentRevisionWorkItem = sourceStore.GetRevision(sourceWorkItem, revision.Number); TraceWriteLine(currentRevisionWorkItem, $" Processing Revision[{revision.Number}"); // Decide on WIT string destType = currentRevisionWorkItem.Type.Name; if (me.WorkItemTypeDefinitions.ContainsKey(destType)) { destType = me.WorkItemTypeDefinitions[destType].Map(currentRevisionWorkItem); } //If work item hasn't been created yet, create a shell if (targetWorkItem == null) { targetWorkItem = CreateWorkItem_Shell(destProject, currentRevisionWorkItem, destType); } //If the work item already exists and its type has changed, update its type. Done this way because there doesn't appear to be a way to do this through the store. else if (targetWorkItem.Type.Name != destType) { Debug.WriteLine($"Work Item type change! '{targetWorkItem.Title}': From {targetWorkItem.Type.Name} to {destType}"); var typePatch = new JsonPatchOperation() { Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add, Path = "/fields/System.WorkItemType", Value = destType }; var datePatch = new JsonPatchOperation() { Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add, Path = "/fields/System.ChangedDate", Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.ChangedDate"].Value }; var patchDoc = new JsonPatchDocument(); patchDoc.Add(typePatch); patchDoc.Add(datePatch); _witClient.UpdateWorkItemAsync(patchDoc, targetWorkItem.Id, bypassRules: true).Wait(); } PopulateWorkItem(currentRevisionWorkItem, targetWorkItem, destType); me.ApplyFieldMappings(currentRevisionWorkItem, targetWorkItem); targetWorkItem.Fields["System.ChangedBy"].Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.ChangedBy"].Value; targetWorkItem.Fields["System.History"].Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.History"].Value; //Debug.WriteLine("Discussion:" + currentRevisionWorkItem.Revisions[revision.Index].Fields["System.History"].Value); var fails = targetWorkItem.Validate(); foreach (Field f in fails) { TraceWriteLine(currentRevisionWorkItem, $"{current} - Invalid: {currentRevisionWorkItem.Id}-{currentRevisionWorkItem.Type.Name}-{f.ReferenceName}-{sourceWorkItem.Title} Value: {f.Value}"); } targetWorkItem.Save(); TraceWriteLine(currentRevisionWorkItem, $" Saved TargetWorkItem {targetWorkItem.Id}. Replayed revision {revision.Number} of {currentRevisionWorkItem.Revisions.Count}"); } if (targetWorkItem != null) { ProcessWorkItemAttachments(sourceWorkItem, targetWorkItem, false); ProcessWorkItemLinks(sourceStore, targetStore, sourceWorkItem, targetWorkItem, false); string reflectedUri = sourceStore.CreateReflectedWorkItemId(sourceWorkItem); if (targetWorkItem.Fields.Contains(me.Target.Config.ReflectedWorkItemIDFieldName)) { targetWorkItem.Fields[me.Target.Config.ReflectedWorkItemIDFieldName].Value = reflectedUri; } var history = new StringBuilder(); history.Append( $"This work item was migrated from a different project or organization. You can find the old version at <a href=\"{reflectedUri}\">{reflectedUri}</a>."); targetWorkItem.History = history.ToString(); SaveWorkItem(targetWorkItem); attachmentOMatic.CleanUpAfterSave(targetWorkItem); TraceWriteLine(sourceWorkItem, $"...Saved as {targetWorkItem.Id}"); if (_config.UpdateSourceReflectedId && sourceWorkItem.Fields.Contains(me.Source.Config.ReflectedWorkItemIDFieldName)) { sourceWorkItem.Fields[me.Source.Config.ReflectedWorkItemIDFieldName].Value = targetStore.CreateReflectedWorkItemId(targetWorkItem); SaveWorkItem(sourceWorkItem); TraceWriteLine(sourceWorkItem, $"...and Source Updated {sourceWorkItem.Id}"); } } } catch (Exception ex) { TraceWriteLine(sourceWorkItem, "...FAILED to Save"); if (targetWorkItem != null) { foreach (Field f in targetWorkItem.Fields) { TraceWriteLine(sourceWorkItem, $"{f.ReferenceName} ({f.Name}) | {f.Value}"); } } TraceWriteLine(sourceWorkItem, ex.ToString()); } return(targetWorkItem); }
private WorkItem ReplayRevisions(List <RevisionItem> revisionsToMigrate, WorkItem sourceWorkItem, WorkItem targetWorkItem, Project destProject, WorkItemStoreContext sourceStore, int current, WorkItemStoreContext targetStore) { try { var skipToFinalRevisedWorkItemType = _config.SkipToFinalRevisedWorkItemType; var last = sourceStore.GetRevision(sourceWorkItem, revisionsToMigrate.Last().Number); string finalDestType = last.Type.Name; if (skipToFinalRevisedWorkItemType && me.WorkItemTypeDefinitions.ContainsKey(finalDestType)) { finalDestType = me.WorkItemTypeDefinitions[finalDestType].Map(last); } //If work item hasn't been created yet, create a shell if (targetWorkItem == null) { targetWorkItem = CreateWorkItem_Shell(destProject, sourceWorkItem, skipToFinalRevisedWorkItemType ? finalDestType : sourceStore.GetRevision(sourceWorkItem, revisionsToMigrate.First().Number).Type.Name); } if (_config.CollapseRevisions) { var data = revisionsToMigrate.Select(rev => sourceStore.GetRevision(sourceWorkItem, rev.Number)).Select(rev => new { rev.Id, rev.Rev, rev.RevisedDate, Fields = rev.Fields.AsDictionary() }); var fileData = JsonConvert.SerializeObject(data, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.None }); var filePath = Path.Combine(Path.GetTempPath(), $"{sourceWorkItem.Id}_PreMigrationHistory.json"); File.WriteAllText(filePath, fileData); targetWorkItem.Attachments.Add(new Attachment(filePath, "History has been consolidated into the attached file.")); revisionsToMigrate = revisionsToMigrate.GetRange(revisionsToMigrate.Count - 1, 1); TraceWriteLine(targetWorkItem, $" Attached a consolidated set of {data.Count()} revisions."); } foreach (var revision in revisionsToMigrate) { var currentRevisionWorkItem = sourceStore.GetRevision(sourceWorkItem, revision.Number); TraceWriteLine(currentRevisionWorkItem, $" Processing Revision [{revision.Number}]"); // Decide on WIT string destType = currentRevisionWorkItem.Type.Name; if (me.WorkItemTypeDefinitions.ContainsKey(destType)) { destType = me.WorkItemTypeDefinitions[destType].Map(currentRevisionWorkItem); } //If the work item already exists and its type has changed, update its type. Done this way because there doesn't appear to be a way to do this through the store. if (!skipToFinalRevisedWorkItemType && targetWorkItem.Type.Name != finalDestType) { Debug.WriteLine($"Work Item type change! '{targetWorkItem.Title}': From {targetWorkItem.Type.Name} to {destType}"); var typePatch = new JsonPatchOperation() { Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add, Path = "/fields/System.WorkItemType", Value = destType }; var datePatch = new JsonPatchOperation() { Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add, Path = "/fields/System.ChangedDate", Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.ChangedDate"].Value }; var patchDoc = new JsonPatchDocument(); patchDoc.Add(typePatch); patchDoc.Add(datePatch); _witClient.UpdateWorkItemAsync(patchDoc, targetWorkItem.Id, bypassRules: true).Wait(); } PopulateWorkItem(currentRevisionWorkItem, targetWorkItem, destType); me.ApplyFieldMappings(currentRevisionWorkItem, targetWorkItem); targetWorkItem.Fields["System.ChangedBy"].Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.ChangedBy"].Value; targetWorkItem.Fields["System.History"].Value = currentRevisionWorkItem.Revisions[revision.Index].Fields["System.History"].Value; //Debug.WriteLine("Discussion:" + currentRevisionWorkItem.Revisions[revision.Index].Fields["System.History"].Value); var fails = targetWorkItem.Validate(); foreach (Field f in fails) { TraceWriteLine(currentRevisionWorkItem, $"{current} - Invalid: {currentRevisionWorkItem.Id}-{currentRevisionWorkItem.Type.Name}-{f.ReferenceName}-{sourceWorkItem.Title} Value: {f.Value}"); } targetWorkItem.Save(); TraceWriteLine(currentRevisionWorkItem, $" Saved TargetWorkItem {targetWorkItem.Id}. Replayed revision {revision.Number} of {revisionsToMigrate.Count}"); } if (targetWorkItem != null) { ProcessWorkItemAttachments(sourceWorkItem, targetWorkItem, false); ProcessWorkItemLinks(sourceStore, targetStore, sourceWorkItem, targetWorkItem, false); string reflectedUri = sourceStore.CreateReflectedWorkItemId(sourceWorkItem); if (targetWorkItem.Fields.Contains(me.Target.Config.ReflectedWorkItemIDFieldName)) { targetWorkItem.Fields[me.Target.Config.ReflectedWorkItemIDFieldName].Value = reflectedUri; } var history = new StringBuilder(); history.Append( $"This work item was migrated from a different project or organization. You can find the old version at <a href=\"{reflectedUri}\">{reflectedUri}</a>."); targetWorkItem.History = history.ToString(); SaveWorkItem(targetWorkItem); attachmentOMatic.CleanUpAfterSave(targetWorkItem); TraceWriteLine(sourceWorkItem, $"...Saved as {targetWorkItem.Id}"); if (_config.UpdateSourceReflectedId && sourceWorkItem.Fields.Contains(me.Source.Config.ReflectedWorkItemIDFieldName)) { sourceWorkItem.Fields[me.Source.Config.ReflectedWorkItemIDFieldName].Value = targetStore.CreateReflectedWorkItemId(targetWorkItem); SaveWorkItem(sourceWorkItem); TraceWriteLine(sourceWorkItem, $"...and Source Updated {sourceWorkItem.Id}"); } } } catch (Exception ex) { TraceWriteLine(sourceWorkItem, "...FAILED to Save"); if (targetWorkItem != null) { foreach (Field f in targetWorkItem.Fields) { TraceWriteLine(sourceWorkItem, $"{f.ReferenceName} ({f.Name}) | {f.Value}"); } } TraceWriteLine(sourceWorkItem, ex.ToString()); } return(targetWorkItem); }