private void ExecuteMigration(CommandOption token, CommandOption url, CommandOption configFile, bool forceFresh) { ConfigJson config = null; var itemCount = 0; var revisionCount = 0; var importedItems = 0; var sw = new Stopwatch(); sw.Start(); try { var s_configFile = ""; var s_adoUrl = ""; var s_adoToken = ""; #if DEBUG s_configFile = "c:\\path\\to\\file\\config-scrum.json"; s_adoUrl = "https://dev.azure.com/org"; s_adoToken = "token"; #else s_configFile = configFile.Value(); s_adoUrl = url.Value(); s_adoToken = token.Value(); #endif ConfigReaderJson configReaderJson = new ConfigReaderJson(s_configFile); config = configReaderJson.Deserialize(); var context = MigrationContext.Init("wi-import", config.Workspace, config.LogLevel, forceFresh); // connection settings for Azure DevOps/TFS: // full base url incl https, name of the project where the items will be migrated (if it doesn't exist on destination it will be created), personal access token var settings = new Settings(s_adoUrl, config.TargetProject, s_adoToken) { BaseAreaPath = config.BaseAreaPath ?? string.Empty, // Root area path that will prefix area path of each migrated item BaseIterationPath = config.BaseIterationPath ?? string.Empty, // Root iteration path that will prefix each iteration IgnoreFailedLinks = config.IgnoreFailedLinks, ProcessTemplate = config.ProcessTemplate }; // initialize Azure DevOps/TFS connection. Creates/fetches project, fills area and iteration caches. var agent = Agent.Initialize(context, settings); if (agent == null) { Logger.Log(LogLevel.Critical, "Azure DevOps/TFS initialization error."); return; } var executionBuilder = new ExecutionPlanBuilder(context); var plan = executionBuilder.BuildExecutionPlan(); itemCount = plan.ReferenceQueue.AsEnumerable().Select(x => x.OriginId).Distinct().Count(); revisionCount = plan.ReferenceQueue.Count; BeginSession(configFile.Value(), config, forceFresh, agent, itemCount, revisionCount); while (plan.TryPop(out ExecutionPlan.ExecutionItem executionItem)) { try { if (!forceFresh && context.Journal.IsItemMigrated(executionItem.OriginId, executionItem.Revision.Index)) { continue; } WorkItem wi = null; if (executionItem.WiId > 0) { wi = agent.GetWorkItem(executionItem.WiId); } else { wi = agent.CreateWI(executionItem.WiType); } Logger.Log(LogLevel.Info, $"Processing {importedItems + 1}/{revisionCount} - wi '{wi.Id}', jira '{executionItem.OriginId}, rev {executionItem.Revision.Index}'."); agent.ImportRevision(executionItem.Revision, wi); importedItems++; } catch (AbortMigrationException) { Logger.Log(LogLevel.Info, "Aborting migration..."); break; } catch (Exception ex) { try { Logger.Log(ex, $"Failed to import '{executionItem.ToString()}'."); } catch (AbortMigrationException) { break; } } } } catch (CommandParsingException e) { Logger.Log(LogLevel.Error, $"Invalid command line option(s): {e}"); } catch (Exception e) { Logger.Log(e, $"Unexpected migration error."); } finally { EndSession(itemCount, revisionCount, sw); } }
private void ExecuteMigration(CommandOption token, CommandOption url, CommandOption configFile, bool forceFresh) { ConfigJson config = null; try { string configFileName = configFile.Value(); ConfigReaderJson configReaderJson = new ConfigReaderJson(configFileName); config = configReaderJson.Deserialize(); // Migration session level settings // where the logs and journal will be saved, logs aid debugging, journal is for recovery of interupted process string migrationWorkspace = config.Workspace; // level of log messages that will be let through to console LogLevel logLevel; switch (config.LogLevel) { case "Info": logLevel = LogLevel.Info; break; case "Debug": logLevel = LogLevel.Debug; break; case "Warning": logLevel = LogLevel.Warning; break; case "Error": logLevel = LogLevel.Error; break; case "Critical": logLevel = LogLevel.Critical; break; default: logLevel = LogLevel.Debug; break; } // set up log, journal and run session settings var context = MigrationContext.Init(migrationWorkspace, logLevel, forceFresh); // connection settings for Azure DevOps/TFS: // full base url incl https, name of the project where the items will be migrated (if it doesn't exist on destination it will be created), personal access token var settings = new Settings(url.Value(), config.TargetProject, token.Value()) { BaseAreaPath = config.BaseAreaPath ?? string.Empty, // Root area path that will prefix area path of each migrated item BaseIterationPath = config.BaseIterationPath ?? string.Empty, // Root iteration path that will prefix each iteration IgnoreFailedLinks = config.IgnoreFailedLinks, ProcessTemplate = config.ProcessTemplate }; // initialize Azure DevOps/TFS connection. Creates/fetches project, fills area and iteration caches. var agent = Agent.Initialize(context, settings); if (agent == null) { Logger.Log(LogLevel.Error, "Azure DevOps/TFS initialization error. Exiting..."); return; } var executionBuilder = new ExecutionPlanBuilder(context); var plan = executionBuilder.BuildExecutionPlan(); while (plan.TryPop(out ExecutionPlan.ExecutionItem executionItem)) { try { if (!forceFresh && context.Journal.IsItemMigrated(executionItem.OriginId, executionItem.Revision.Index)) { continue; } WorkItem wi = null; if (executionItem.WiId > 0) { wi = agent.GetWorkItem(executionItem.WiId); } else { wi = agent.CreateWI(executionItem.WiType); } agent.ImportRevision(executionItem.Revision, wi); } catch (AbortMigrationException) { Logger.Log(LogLevel.Info, "Aborting migration..."); break; } catch (Exception ex) { try { Logger.Log(ex); } catch (AbortMigrationException) { break; } } } } catch (CommandParsingException e) { Logger.Log(LogLevel.Error, $"Invalid command line option(s): {e}"); } catch (Exception e) { Logger.Log(LogLevel.Error, $"Unexpected error: {e}"); } }