private bool ProcessWorkItemWithLogging(WorkItemData sourceWorkItemData, int current, int totalWorkItem) { var sourceWorkItem = TfsExtensions.ToWorkItem(sourceWorkItemData); workItemLog = contextLog.ForContext("SourceWorkItemId", sourceWorkItem.Id); using (LogContext.PushProperty("sourceWorkItemTypeName", sourceWorkItem.Type.Name)) using (LogContext.PushProperty("currentWorkItem", current)) using (LogContext.PushProperty("totalWorkItems", totalWorkItem)) using (LogContext.PushProperty("sourceWorkItemId", sourceWorkItem.Id)) using (LogContext.PushProperty("sourceRevisionInt", sourceWorkItem.Revision)) using (LogContext.PushProperty("targetWorkItemId", null)) { ProcessWorkItem(sourceWorkItemData, _config.WorkItemCreateRetryLimit); if (_config.PauseAfterEachWorkItem) { Console.WriteLine("Do you want to continue? (y/n)"); if (Console.ReadKey().Key != ConsoleKey.Y) { workItemLog.Warning("USER ABORTED"); return(false); } } } return(true); }
protected override void InternalExecute() { Log.LogInformation("WorkItemMigrationContext::InternalExecute "); if (_config == null) { throw new Exception("You must call Configure() first"); } var workItemServer = Engine.Source.GetService <WorkItemServer>(); attachmentEnricher = new TfsAttachmentEnricher(workItemServer, _config.AttachmentWorkingPath, _config.AttachmentMaxSize); workItemLinkEnricher = Services.GetRequiredService <TfsWorkItemLinkEnricher>(); embededImagesEnricher = Services.GetRequiredService <TfsEmbededImagesEnricher>(); gitRepositoryEnricher = Services.GetRequiredService <TfsGitRepositoryEnricher>(); nodeStructureEnricher = Services.GetRequiredService <TfsNodeStructureEnricher>(); _witClient = new WorkItemTrackingHttpClient(Engine.Target.Config.AsTeamProjectConfig().Collection, Engine.Target.Credentials); //Validation: make sure that the ReflectedWorkItemId field name specified in the config exists in the target process, preferably on each work item type. PopulateIgnoreList(); Log.LogInformation("Migrating all Nodes before the work item run."); nodeStructureEnricher.MigrateAllNodeStructures(_config.PrefixProjectToNodes, _config.NodeBasePaths); var stopwatch = Stopwatch.StartNew(); ////////////////////////////////////////////////// string sourceQuery = string.Format( @"SELECT [System.Id], [System.Tags] FROM WorkItems WHERE [System.TeamProject] = @TeamProject {0} ORDER BY {1}", _config.WIQLQueryBit, _config.WIQLOrderBit); // Inform the user that he maybe has to be patient now contextLog.Information("Querying items to be migrated: {SourceQuery} ...", sourceQuery); var sourceWorkItems = Engine.Source.WorkItems.GetWorkItems(sourceQuery); contextLog.Information("Replay all revisions of {sourceWorkItemsCount} work items?", sourceWorkItems.Count); ////////////////////////////////////////////////// contextLog.Information("Found target project as {@destProject}", Engine.Target.WorkItems.Project.Name); //////////////////////////////////////////////////////////FilterCompletedByQuery if (_config.FilterWorkItemsThatAlreadyExistInTarget) { contextLog.Information("[FilterWorkItemsThatAlreadyExistInTarget] is enabled. Searching for work items that have already been migrated to the target...", sourceWorkItems.Count()); sourceWorkItems = ((TfsWorkItemMigrationClient)Engine.Target.WorkItems).FilterExistingWorkItems(sourceWorkItems, new TfsWiqlDefinition() { OrderBit = _config.WIQLOrderBit, QueryBit = _config.WIQLQueryBit }, (TfsWorkItemMigrationClient)Engine.Source.WorkItems); contextLog.Information("!! After removing all found work items there are {SourceWorkItemCount} remaining to be migrated.", sourceWorkItems.Count()); } ////////////////////////////////////////////////// var result = validateConfig.ValidatingRequiredField(Engine.Target.Config.AsTeamProjectConfig().ReflectedWorkItemIDFieldName, sourceWorkItems); if (!result) { var ex = new InvalidFieldValueException("Not all work items in scope contain a valid ReflectedWorkItemId Field!"); Log.LogError(ex, "Not all work items in scope contain a valid ReflectedWorkItemId Field!"); throw ex; } ////////////////////////////////////////////////// _current = 1; _count = sourceWorkItems.Count; _elapsedms = 0; _totalWorkItem = sourceWorkItems.Count; foreach (MigrationTools._EngineV1.DataContracts.WorkItemData sourceWorkItemData in sourceWorkItems) { var sourceWorkItem = TfsExtensions.ToWorkItem(sourceWorkItemData); workItemLog = contextLog.ForContext("SourceWorkItemId", sourceWorkItem.Id); using (LogContext.PushProperty("sourceWorkItemTypeName", sourceWorkItem.Type.Name)) using (LogContext.PushProperty("currentWorkItem", _current)) using (LogContext.PushProperty("totalWorkItems", _totalWorkItem)) using (LogContext.PushProperty("sourceWorkItemId", sourceWorkItem.Id)) using (LogContext.PushProperty("sourceRevisionInt", sourceWorkItem.Revision)) using (LogContext.PushProperty("targetWorkItemId", null)) { ProcessWorkItem(sourceWorkItemData, _config.WorkItemCreateRetryLimit); if (_config.PauseAfterEachWorkItem) { Console.WriteLine("Do you want to continue? (y/n)"); if (Console.ReadKey().Key != ConsoleKey.Y) { workItemLog.Warning("USER ABORTED"); break; } } } } ////////////////////////////////////////////////// stopwatch.Stop(); contextLog.Information("DONE in {Elapsed}", stopwatch.Elapsed.ToString("c")); }
protected override void InternalExecute() { Stopwatch stopwatch = Stopwatch.StartNew(); ////////////////////////////////////////////////// IWorkItemQueryBuilder wiqb = Services.GetRequiredService <IWorkItemQueryBuilder>(); //Builds the constraint part of the query string constraints = BuildQueryBitConstraints(); wiqb.Query = string.Format(@"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = @TeamProject {0} ORDER BY [System.Id] ", constraints); List <MigrationTools._EngineV1.DataContracts.WorkItemData> sourceWIS = Engine.Target.WorkItems.GetWorkItems((IWorkItemQueryBuilder)wiqb); Log.LogInformation("Migrate {0} work items?", sourceWIS.Count); ////////////////////////////////////////////////// ProjectData destProject = Engine.Target.WorkItems.GetProject(); Log.LogInformation("Found target project as {0}", destProject.Name); int current = sourceWIS.Count; int count = 0; long elapsedms = 0; foreach (MigrationTools._EngineV1.DataContracts.WorkItemData sourceWI in sourceWIS) { Stopwatch witstopwatch = Stopwatch.StartNew(); MigrationTools._EngineV1.DataContracts.WorkItemData targetFound; targetFound = Engine.Target.WorkItems.FindReflectedWorkItem((MigrationTools._EngineV1.DataContracts.WorkItemData)sourceWI, (bool)false); Log.LogInformation("{0} - Updating: {1}-{2}", current, sourceWI.Id, sourceWI.Type); if (targetFound == null) { Log.LogWarning("{0} - WARNING: does not exist {1}-{2}", current, sourceWI.Id, sourceWI.Type); } else { Log.LogInformation("...Exists"); TfsExtensions.ToWorkItem(targetFound).Open(); Engine.FieldMaps.ApplyFieldMappings(sourceWI, targetFound); if (TfsExtensions.ToWorkItem(targetFound).IsDirty) { try { TfsExtensions.SaveToAzureDevOps(targetFound); Log.LogInformation(" Updated"); } catch (ValidationException ve) { Log.LogError(ve, " [FAILED] {0}", ve.ToString()); } } else { Log.LogInformation(" No changes"); } TfsExtensions.ToWorkItem(sourceWI).Close(); } witstopwatch.Stop(); elapsedms = elapsedms + witstopwatch.ElapsedMilliseconds; current--; count++; TimeSpan average = new TimeSpan(0, 0, 0, 0, (int)(elapsedms / count)); TimeSpan remaining = new TimeSpan(0, 0, 0, 0, (int)(average.TotalMilliseconds * current)); Log.LogInformation("Average time of {0} per work item and {1} estimated to completion", string.Format(@"{0:s\:fff} seconds", average), string.Format(@"{0:%h} hours {0:%m} minutes {0:s\:fff} seconds", remaining)); } ////////////////////////////////////////////////// stopwatch.Stop(); Log.LogInformation("DONE in {Elapsed}", stopwatch.Elapsed.ToString("c")); }