Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Topic/update jsonname #57

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Spectre.Console.Cli" Version="0.49.1" />
<PackageReference Include="Spectre.Console.ImageSharp" Version="0.49.1" />
<PackageReference Include="YamlDotNet" Version="16.0.0" />
</ItemGroup>

<ItemGroup>
Expand All @@ -40,6 +41,9 @@
<None Update="configuration.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="configuration.yaml">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
<None Update="Resources\ADO_TESTProjPipline_V03.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using Newtonsoft.Json;
using System.Threading.Tasks;
using YamlDotNet.Serialization;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
Expand All @@ -14,7 +15,7 @@ internal class BaseCommandSettings : CommandSettings
[Description("Pre configure paramiters using this config file. Run `Init` to create it.")]
[CommandOption("--config|--configFile")]
[DefaultValue("configuration.json")]
[JsonIgnore]
[JsonIgnore, YamlIgnore]
public string? configFile { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,23 @@
using System.Threading.Tasks;
using System.Diagnostics.Eventing.Reader;
using AzureDevOps.WorkItemClone.Repositories;
using YamlDotNet.Serialization;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
internal class WorkItemCloneCommand : WorkItemCommandBase<WorkItemCloneCommandSettings>
{
public override async Task<int> ExecuteAsync(CommandContext context, WorkItemCloneCommandSettings settingsFromCmd)
{
if (!FileStoreCheckExtensionMatchesFormat(settingsFromCmd.configFile, settingsFromCmd.ConfigFormat))
{
AnsiConsole.MarkupLine($"[bold red]The file extension of {settingsFromCmd.configFile} does not match the format {settingsFromCmd.ConfigFormat.ToString()} selected! Please rerun with the correct format You can use --configFormat JSON or update your file to YAML[/]");
return -1;
}
WorkItemCloneCommandSettings config = null;
if (File.Exists(settingsFromCmd.configFile))
if (FileStoreExist(settingsFromCmd.configFile, settingsFromCmd.ConfigFormat))
{
config = LoadWorkItemCloneCommandSettingsFromFile(settingsFromCmd.configFile);
config = FileStoreLoad<WorkItemCloneCommandSettings>(settingsFromCmd.configFile, settingsFromCmd.ConfigFormat);
}
if (config == null)
{
Expand All @@ -34,7 +40,7 @@ public override async Task<int> ExecuteAsync(CommandContext context, WorkItemClo
DirectoryInfo outputPathInfo = CreateOutputPath(runCache);
AzureDevOpsApi targetApi = CreateAzureDevOpsConnection(config.targetAccessToken, config.targetOrganization, config.targetProject);

JArray inputWorkItems = DeserializeWorkItemList(config);
JArray workItemControlList = DeserializeControlFile(config);

// --------------------------------------------------------------
WriteOutSettings(config);
Expand Down Expand Up @@ -96,7 +102,7 @@ await AnsiConsole.Progress()
task1.Increment(result.processed);
await Task.Delay(250);
}
task1.Description = $"[bold]Stage 1[/]: Load Template Items ({result.loadingFrom})";
task1.Description = $"[bold]Stage 1+2[/]: Load Template Items ({result.loadingFrom})";
task1.Increment(1);
}
task1.StopTask();
Expand Down Expand Up @@ -150,12 +156,12 @@ await AnsiConsole.Progress()
else
{
// Task 4: First Pass generation of Work Items to build
task4.MaxValue = inputWorkItems.Count();
task4.MaxValue = workItemControlList.Count();
task4.StartTask();
await Task.Delay(250);
//AnsiConsole.WriteLine($"Stage 4: First Pass generation of Work Items to build will merge the provided json work items with the data from the template.");
buildItems = new List<WorkItemToBuild>();
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildList(inputWorkItems, templateWor.Data.workitems, projectItem, config.targetProject))
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildList(workItemControlList, templateWor.Data.workitems, projectItem, config.targetProject))
{
// AnsiConsole.WriteLine($"Stage 4: processing {witb.guid}");
buildItems.Add(witb);
Expand All @@ -166,7 +172,7 @@ await AnsiConsole.Progress()
//AnsiConsole.WriteLine($"Stage 4: Completed first pass.");
// --------------------------------------------------------------
// Task 5: Second Pass Add Relations
task5.MaxValue = inputWorkItems.Count();
task5.MaxValue = workItemControlList.Count();
//AnsiConsole.WriteLine($"Stage 5: Second Pass generate relations.");
task5.StartTask();
await Task.Delay(250);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
using Spectre.Console.Cli;
using System.ComponentModel;
using Newtonsoft.Json;
using YamlDotNet.Serialization;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
public enum ConfigFormats
{
JSON,
YAML
}

internal class WorkItemCloneCommandSettings : BaseCommandSettings
{
//------------------------------------------------
[Description("Execute with no user interaction required.")]
[CommandOption("--NonInteractive")]
[JsonIgnore]
[JsonIgnore, YamlIgnore]
public bool NonInteractive { get; set; }
[Description("Clear any cache if there is any")]
[CommandOption("--ClearCache")]
[JsonIgnore]
[JsonIgnore, YamlIgnore]
public bool ClearCache { get; set; }
[Description("Use this run name to execute. This will create a unique folder under the CachePath for storing run specific data and status. Defaults to yyyyyMMddHHmmss.")]
[CommandOption("--RunName")]
[JsonIgnore]
[JsonIgnore, YamlIgnore]
public string? RunName { get; set; }
[Description("Use this run name to execute. This will create a unique folder under the CachePath for storing run specific data and status. Defaults to yyyyyMMddHHmmss.")]
[CommandOption("--configFormat")]
[DefaultValue(ConfigFormats.JSON)]
[JsonIgnore, YamlIgnore]
public ConfigFormats ConfigFormat { get; set; }
//------------------------------------------------
[CommandOption("--outputPath|--cachePath")]
[DefaultValue("./cache")]
public string? CachePath { get; set; }
//------------------------------------------------
[CommandOption("--jsonFile|--inputJsonFile")]
public string? inputJsonFile { get; set; }
[CommandOption("--jsonFile|--inputJsonFile|--controlFile")]
public string? controlFile { get; set; }
//------------------------------------------------
[Description("The access token for the target location")]
[CommandOption("--targetAccessToken")]
Expand Down
108 changes: 81 additions & 27 deletions AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization;
using Microsoft.SqlServer.Server;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
Expand All @@ -23,7 +26,7 @@ internal void CombineValuesFromConfigAndSettings(WorkItemCloneCommandSettings se
config.ClearCache = settings.ClearCache;
config.RunName = settings.RunName != null ? settings.RunName : DateTime.Now.ToString("yyyyyMMddHHmmss");
config.configFile = EnsureFileAskIfMissing(config.configFile = settings.configFile != null ? settings.configFile : config.configFile, "Where is the config file to load?");
config.inputJsonFile = EnsureFileAskIfMissing(config.inputJsonFile = settings.inputJsonFile != null ? settings.inputJsonFile : config.inputJsonFile, "Where is the JSON File?");
config.controlFile = EnsureFileAskIfMissing(config.controlFile = settings.controlFile != null ? settings.controlFile : config.controlFile, "Where is the Control File?");
config.CachePath = EnsureFolderAskIfMissing(config.CachePath = settings.CachePath != null ? settings.CachePath : config.CachePath, "What is the cache path?");

config.templateOrganization = EnsureStringAskIfMissing(config.templateOrganization = settings.templateOrganization != null ? settings.templateOrganization : config.templateOrganization, "What is the template organisation?");
Expand Down Expand Up @@ -79,26 +82,26 @@ private JArray DeserializeWorkItemList(string jsonFile)
return configWorkItems;
}

internal JArray DeserializeWorkItemList(WorkItemCloneCommandSettings config)
internal JArray DeserializeControlFile(WorkItemCloneCommandSettings config)
{
string CachedRunJson = System.IO.Path.Combine(config.CachePath, config.RunName, "input.json");
if (System.IO.File.Exists(CachedRunJson))
{
// Load From Run Cache
config.inputJsonFile = CachedRunJson;
config.controlFile = CachedRunJson;
return DeserializeWorkItemList(CachedRunJson);
} else
{
// Load new
config.inputJsonFile = EnsureFileAskIfMissing(config.inputJsonFile, "Where is the JSON File?");
if (!System.IO.File.Exists(config.inputJsonFile))
config.controlFile = EnsureFileAskIfMissing(config.controlFile, "Where is the JSON File?");
if (!System.IO.File.Exists(config.controlFile))
{
AnsiConsole.MarkupLine("[red]Error:[/] No JSON file was found.");
throw new Exception(config.inputJsonFile + " not found.");
throw new Exception(config.controlFile + " not found.");
}

JArray inputWorkItems;
inputWorkItems= DeserializeWorkItemList(config.inputJsonFile);
inputWorkItems= DeserializeWorkItemList(config.controlFile);
System.IO.File.WriteAllText(CachedRunJson, JsonConvert.SerializeObject(inputWorkItems, Formatting.Indented));
return inputWorkItems;
}
Expand Down Expand Up @@ -137,16 +140,73 @@ internal string EnsureStringAskIfMissing(string value, string message)
}


internal ConfigurationSettings LoadConfigFile(string? configFile)
public TypeToLoad FileStoreLoad<TypeToLoad>(string configFile, ConfigFormats format)
{
ConfigurationSettings configSettings = System.Text.Json.JsonSerializer.Deserialize<ConfigurationSettings>(System.IO.File.ReadAllText(configFile));
return configSettings;
TypeToLoad loadedFromFile;
configFile = FileStoreEnsureExtension(configFile, format);
if (!System.IO.File.Exists(configFile))
{
AnsiConsole.MarkupLine("[red]Error:[/] No file was found.");
throw new Exception(configFile + " not found.");
}
string content = System.IO.File.ReadAllText(configFile);
switch (format)
{
case ConfigFormats.JSON:
loadedFromFile = JsonConvert.DeserializeObject<TypeToLoad>(content);
break;
case ConfigFormats.YAML:
var deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
loadedFromFile = deserializer.Deserialize<TypeToLoad>(content); /* compile error */
break;
default:
throw new Exception("Unknown format");
}
return loadedFromFile;
}

public bool FileStoreExist(string? configFile, ConfigFormats format)
{
return System.IO.File.Exists(FileStoreEnsureExtension(configFile, format));
}
public bool FileStoreCheckExtensionMatchesFormat(string? configFile, ConfigFormats format)
{
if (Path.GetExtension(configFile).ToLower() != $".{format.ToString().ToLower()}")
{
return false;
}
return true;
}

public string FileStoreEnsureExtension(string? configFile, ConfigFormats format)
{
if (Path.GetExtension(configFile).ToLower() != $".{format.ToString().ToLower()}")
{
var original = configFile;
configFile = Path.ChangeExtension(configFile, format.ToString().ToLower());
AnsiConsole.MarkupLine($"[green]Info:[/] Changed name of {original} to {configFile} ");
}
return configFile;
}

internal WorkItemCloneCommandSettings LoadWorkItemCloneCommandSettingsFromFile(string? configFile)
public string FileStoreSave<TypeToSave>(string configFile, TypeToSave content , ConfigFormats format)
{
WorkItemCloneCommandSettings configSettings = System.Text.Json.JsonSerializer.Deserialize<WorkItemCloneCommandSettings>(System.IO.File.ReadAllText(configFile));
return configSettings;
string output;
switch (format)
{
case ConfigFormats.JSON:
output = JsonConvert.SerializeObject(content, Formatting.Indented);
break;
case ConfigFormats.YAML:
var serializer = new SerializerBuilder().Build();
output = serializer.Serialize(content);
break;
default:
throw new Exception("Unknown format");
}
configFile = FileStoreEnsureExtension(configFile, format);
System.IO.File.WriteAllText(configFile, output);
return output;
}

internal string EnsureFileAskIfMissing(string? filename, string message = "What file should we load?")
Expand All @@ -155,17 +215,12 @@ internal string EnsureFileAskIfMissing(string? filename, string message = "What
{

filename = AnsiConsole.Prompt(
new TextPrompt<string>("Where is the config File?")
new TextPrompt<string>(message)
.Validate(configFile
=> !string.IsNullOrWhiteSpace(configFile) && System.IO.File.Exists(configFile)
=> !string.IsNullOrWhiteSpace(configFile)
? ValidationResult.Success()
: ValidationResult.Error("[yellow]Invalid config file[/]")));
}
if (!System.IO.File.Exists(filename))
{
AnsiConsole.MarkupLine("[red]Error:[/] No file was found.");
throw new Exception(filename + " not found.");
}
return filename;
}

Expand Down Expand Up @@ -197,11 +252,6 @@ internal string EnsureConfigFileAskIfMissing(string? configFile)
? ValidationResult.Success()
: ValidationResult.Error("[yellow]Invalid config file[/]")));
}
if (!System.IO.File.Exists(configFile))
{
AnsiConsole.MarkupLine("[red]Error:[/] No JSON file was found.");
throw new Exception(configFile + " not found.");
}
return configFile;
}

Expand All @@ -216,7 +266,7 @@ internal void WriteOutSettings(WorkItemCloneCommandSettings config)
.AddEmptyRow()
.AddRow("configFile", config.configFile != null ? config.configFile : "NOT SET")
.AddRow("CachePath", config.CachePath != null ? config.CachePath : "NOT SET")
.AddRow("inputJsonFile", config.inputJsonFile != null ? config.inputJsonFile : "NOT SET")
.AddRow("controlFile", config.controlFile != null ? config.controlFile : "NOT SET")
.AddEmptyRow()
.AddRow( "templateAccessToken", "***************")
.AddRow("templateOrganization", config.templateOrganization != null ? config.templateOrganization : "NOT SET")
Expand All @@ -228,7 +278,11 @@ internal void WriteOutSettings(WorkItemCloneCommandSettings config)
.AddRow("targetProject", config.targetProject != null ? config.targetProject : "NOT SET")
.AddRow("targetParentId", config.targetParentId != null ? config.targetParentId.ToString() : "NOT SET")
.AddRow("targetFalbackWit", config.targetFalbackWit != null ? config.targetFalbackWit : "NOT SET")

.AddEmptyRow()
.AddRow("targetQueryTitle", config.targetQueryTitle != null ? config.targetQueryTitle : "NOT SET")
.AddRow("targetQueryFolder", config.targetQueryFolder != null ? config.targetQueryFolder : "NOT SET")
.AddRow("targetQuery", config.targetQuery != null ? config.targetQuery.Replace("]", "]]").Replace("[", "[[") : "NOT SET")

);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@
using Spectre.Console;
using Spectre.Console.Cli;
using System.Linq;
using Microsoft.SqlServer.Server;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
internal class WorkItemInitCommand : WorkItemCommandBase<WorkItemCloneCommandSettings>
{
public override async Task<int> ExecuteAsync(CommandContext context, WorkItemCloneCommandSettings settings)
{

if (!FileStoreCheckExtensionMatchesFormat(settings.configFile, settings.ConfigFormat))
{
AnsiConsole.MarkupLine($"[bold red]The file extension of {settings.configFile} does not match the format {settings.ConfigFormat.ToString()} selected! Please rerun with the correct format You can use --configFormat JSON or update your file to YAML[/]");
return -1;
}
var configFile = EnsureConfigFileAskIfMissing(settings.configFile);
WorkItemCloneCommandSettings config = null;
if (File.Exists(configFile))
if (FileStoreExist(configFile, settings.ConfigFormat))
{
var proceedWithSettings = AnsiConsole.Prompt(
new SelectionPrompt<bool> { Converter = value => value ? "Yes" : "No" }
.Title("The config file name used exists would you like to load this one?")
.AddChoices(true, false));
if (proceedWithSettings)
{
config = LoadWorkItemCloneCommandSettingsFromFile(configFile);
config = FileStoreLoad<WorkItemCloneCommandSettings>(configFile, settings.ConfigFormat);
}
}
if (config == null)
Expand All @@ -34,12 +39,9 @@ public override async Task<int> ExecuteAsync(CommandContext context, WorkItemClo

WriteOutSettings(config);

FileStoreSave(configFile, config, settings.ConfigFormat);



System.IO.File.WriteAllText(configFile, JsonConvert.SerializeObject(config, Formatting.Indented));

AnsiConsole.WriteLine("Settings saved to {configFile}!");
AnsiConsole.WriteLine($"Settings saved to {configFile}!");

return 0;
}
Expand Down
Loading
Loading