From cf0ba16850c34a052825fd8fd72b62175f80f67c Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Fri, 12 Aug 2022 13:53:14 +0200 Subject: [PATCH 01/37] Add CommandLinerParser package --- src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj index bdc8bcc6..ef267054 100644 --- a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj +++ b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj @@ -25,6 +25,7 @@ + From 2f25eee7aed7744b7820b650e469949b42c4f1b3 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:09:38 +0200 Subject: [PATCH 02/37] Rename class --- src/ConductorSharp.Toolkit/Commands/Command.cs | 2 +- src/ConductorSharp.Toolkit/Commands/ScaffoldCommand.cs | 2 +- .../Models/{CommandInput.cs => Configuration.cs} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/ConductorSharp.Toolkit/Models/{CommandInput.cs => Configuration.cs} (89%) diff --git a/src/ConductorSharp.Toolkit/Commands/Command.cs b/src/ConductorSharp.Toolkit/Commands/Command.cs index 165f6e79..d05dc612 100644 --- a/src/ConductorSharp.Toolkit/Commands/Command.cs +++ b/src/ConductorSharp.Toolkit/Commands/Command.cs @@ -5,6 +5,6 @@ namespace ConductorSharp.Toolkit.Commands public interface Command { public string GetName(); - public Task Execute(CommandInput input); + public Task Execute(Configuration input); } } diff --git a/src/ConductorSharp.Toolkit/Commands/ScaffoldCommand.cs b/src/ConductorSharp.Toolkit/Commands/ScaffoldCommand.cs index 39159cde..7e20f868 100644 --- a/src/ConductorSharp.Toolkit/Commands/ScaffoldCommand.cs +++ b/src/ConductorSharp.Toolkit/Commands/ScaffoldCommand.cs @@ -14,7 +14,7 @@ public ScaffoldCommand(IScaffoldingService scaffoldingService) public string GetName() => "scaffold"; - public async Task Execute(CommandInput input) + public async Task Execute(Configuration input) { await _scaffoldingService.Scaffold(); } diff --git a/src/ConductorSharp.Toolkit/Models/CommandInput.cs b/src/ConductorSharp.Toolkit/Models/Configuration.cs similarity index 89% rename from src/ConductorSharp.Toolkit/Models/CommandInput.cs rename to src/ConductorSharp.Toolkit/Models/Configuration.cs index 19b2d75d..8e3fc3ae 100644 --- a/src/ConductorSharp.Toolkit/Models/CommandInput.cs +++ b/src/ConductorSharp.Toolkit/Models/Configuration.cs @@ -1,6 +1,6 @@ namespace ConductorSharp.Toolkit.Models { - public class CommandInput + public class Configuration { public string Api { get; set; } public string Namespace { get; set; } From 4936d04a62f188dd51348acf0a1988bfa30dc4c5 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:20:02 +0200 Subject: [PATCH 03/37] Add YamlDotNet package --- src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj index ef267054..e94e30a4 100644 --- a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj +++ b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj @@ -28,6 +28,7 @@ + From 297ec15c05ec8fec767215901c448a03fa412aa1 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:20:25 +0200 Subject: [PATCH 04/37] Integrate command line parser library --- .../Models/ToolkitOptions.cs | 10 +++ src/ConductorSharp.Toolkit/Program.cs | 68 +++++++++++++++---- 2 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs diff --git a/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs b/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs new file mode 100644 index 00000000..7ec10c4f --- /dev/null +++ b/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs @@ -0,0 +1,10 @@ +using CommandLine; + +namespace ConductorSharp.Toolkit.Models +{ + public class ToolkitOptions + { + [Option('f', "file", HelpText = "Configuration file", Default = "conductorsharp.yaml")] + public string ConfiugrationFilePath { get; set; } + } +} diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index f5ddbf01..6f297297 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -4,6 +4,11 @@ using ConductorSharp.Engine.Extensions; using ConductorSharp.Toolkit.Commands; using ConductorSharp.Toolkit.Models; +using CommandLine; +using CommandLine.Text; +using System.Reflection; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; namespace ConductorSharp.Toolkit { @@ -11,29 +16,64 @@ class Program { public async static Task Main(string[] args) { - try + var parseResult = new Parser(opts => opts.HelpWriter = null).ParseArguments(args); + var withParsed = await parseResult.WithParsedAsync(Scaffold); + withParsed.WithNotParsed(err => { - var action = args[0]; + var versionText = new HeadingInfo("conductorsharp", GetVersionString()); + var writer = err.IsHelp() || err.IsVersion() ? Console.Out : Console.Error; + string textToWrite; + if (err.IsVersion()) + textToWrite = versionText; + else + { + textToWrite = HelpText.AutoBuild( + parseResult, + help => + { + help.AddPreOptionsLine("Usage: dotnet conductorsharp [options]"); + help.Heading = versionText; + return help; + } + ); + } - var input = ParseInput(args); + writer.WriteLine(textToWrite); + }); + } - var container = BuildContainer(input); + private static string GetVersionString() + { + var version = Assembly.GetExecutingAssembly().GetName().Version; - var commandRegistry = container.Resolve(); + return $"version {version.Major}.{version.Minor}.{version.Build}"; + } - var command = commandRegistry.Get(action); + private static async Task Scaffold(ToolkitOptions options) + { + Console.WriteLine(options.ConfiugrationFilePath); - await command.Execute(input); - } - catch (Exception exc) + if (!File.Exists(options.ConfiugrationFilePath)) { - PrintHelp(); + Console.Error.WriteLine($"Configuration file {options.ConfiugrationFilePath} does not exists"); + return; } + + var config = await ParseConfigurationFile(options.ConfiugrationFilePath); + var container = BuildContainer(config); + var commandRegistry = container.Resolve(); + // Currently only scaffolding is supported + var command = commandRegistry.Get("scaffold"); + await command.Execute(config); } - private static void PrintHelp() => Console.WriteLine("PLACEHOLDER HELP"); + private static async Task ParseConfigurationFile(string configFilePath) => + new DeserializerBuilder() + .WithNamingConvention(CamelCaseNamingConvention.Instance) + .Build() + .Deserialize(await File.ReadAllTextAsync(configFilePath)); - private static IContainer BuildContainer(CommandInput input) + private static IContainer BuildContainer(Configuration input) { var serviceCollection = new ServiceCollection(); @@ -57,12 +97,12 @@ private static IContainer BuildContainer(CommandInput input) return builder.Build(); } - private static CommandInput ParseInput(string[] args) + private static Configuration ParseInput(string[] args) { var action = args[0]; var inputParameters = args.Skip(1).Select(a => new KeyValuePair(a.Split("=")[0], a.Split("=")[1])).ToList(); - return new CommandInput + return new Configuration { Api = inputParameters.Where(a => a.Key == "path").Select(a => a.Value).FirstOrDefault(), Namespace = inputParameters.Where(a => a.Key == "namespace").Select(a => a.Value).FirstOrDefault(), From e24abc69697aed03f9da0ed164021490cf184ba7 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:20:58 +0200 Subject: [PATCH 05/37] Rename method --- src/ConductorSharp.Toolkit/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 6f297297..d9567267 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -17,7 +17,7 @@ class Program public async static Task Main(string[] args) { var parseResult = new Parser(opts => opts.HelpWriter = null).ParseArguments(args); - var withParsed = await parseResult.WithParsedAsync(Scaffold); + var withParsed = await parseResult.WithParsedAsync(RunToolkit); withParsed.WithNotParsed(err => { var versionText = new HeadingInfo("conductorsharp", GetVersionString()); @@ -49,7 +49,7 @@ private static string GetVersionString() return $"version {version.Major}.{version.Minor}.{version.Build}"; } - private static async Task Scaffold(ToolkitOptions options) + private static async Task RunToolkit(ToolkitOptions options) { Console.WriteLine(options.ConfiugrationFilePath); From d17e52373abbf98904e16846f90629e87d454fd6 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:21:15 +0200 Subject: [PATCH 06/37] Remove unnecessary function --- src/ConductorSharp.Toolkit/Program.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index d9567267..ffea96d0 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -96,20 +96,5 @@ private static IContainer BuildContainer(Configuration input) return builder.Build(); } - - private static Configuration ParseInput(string[] args) - { - var action = args[0]; - var inputParameters = args.Skip(1).Select(a => new KeyValuePair(a.Split("=")[0], a.Split("=")[1])).ToList(); - - return new Configuration - { - Api = inputParameters.Where(a => a.Key == "path").Select(a => a.Value).FirstOrDefault(), - Namespace = inputParameters.Where(a => a.Key == "namespace").Select(a => a.Value).FirstOrDefault(), - Host = inputParameters.Where(a => a.Key == "host").Select(a => a.Value).FirstOrDefault(), - Dryrun = inputParameters.Where(a => a.Key == "dryrun").Select(a => bool.Parse(a.Value)).FirstOrDefault(), - Destination = inputParameters.Where(a => a.Key == "destination").Select(a => a.Value).FirstOrDefault() - }; - } } } From 6072a95e74396ca61908fd4103c623953d9df6a7 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:24:15 +0200 Subject: [PATCH 07/37] Rename properties --- src/ConductorSharp.Toolkit/Models/Configuration.cs | 4 ++-- src/ConductorSharp.Toolkit/Program.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Models/Configuration.cs b/src/ConductorSharp.Toolkit/Models/Configuration.cs index 8e3fc3ae..dac5ddc0 100644 --- a/src/ConductorSharp.Toolkit/Models/Configuration.cs +++ b/src/ConductorSharp.Toolkit/Models/Configuration.cs @@ -2,9 +2,9 @@ { public class Configuration { - public string Api { get; set; } + public string ApiPath { get; set; } public string Namespace { get; set; } - public string Host { get; set; } + public string BaseUrl { get; set; } public bool Dryrun { get; set; } public string Destination { get; set; } } diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index ffea96d0..e8000ad6 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -83,15 +83,15 @@ private static IContainer BuildContainer(Configuration input) serviceCollection.Configure(config => { - config.ApiUrl = input.Api; - config.BaseUrl = input.Host; + config.ApiUrl = input.ApiPath; + config.BaseUrl = input.BaseUrl; config.BaseNamespace = input.Namespace; config.Dryrun = input.Dryrun; config.Destination = input.Destination; }); builder.Populate(serviceCollection); - builder.AddWorkflowEngine(input.Host, input.Api); + builder.AddWorkflowEngine(input.BaseUrl, input.ApiPath); builder.RegisterModule(new ToolkitModule()); return builder.Build(); From 9206b5da0deb2ff590a91c5beac6a71fab6c28a5 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:29:17 +0200 Subject: [PATCH 08/37] Remove unnecessary property --- src/ConductorSharp.Toolkit/Models/Configuration.cs | 8 +++++++- src/ConductorSharp.Toolkit/Program.cs | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Models/Configuration.cs b/src/ConductorSharp.Toolkit/Models/Configuration.cs index dac5ddc0..1ec0615f 100644 --- a/src/ConductorSharp.Toolkit/Models/Configuration.cs +++ b/src/ConductorSharp.Toolkit/Models/Configuration.cs @@ -2,10 +2,16 @@ { public class Configuration { + public class Header + { + public string Name { get; set; } + public string Value { get; set; } + } + public string ApiPath { get; set; } public string Namespace { get; set; } public string BaseUrl { get; set; } - public bool Dryrun { get; set; } public string Destination { get; set; } + public Header[] Headers { get; set; } } } diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index e8000ad6..55b75471 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -86,7 +86,6 @@ private static IContainer BuildContainer(Configuration input) config.ApiUrl = input.ApiPath; config.BaseUrl = input.BaseUrl; config.BaseNamespace = input.Namespace; - config.Dryrun = input.Dryrun; config.Destination = input.Destination; }); From 0e4429a202493ea52fccf3a315e0b47eaa2470e1 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:42:06 +0200 Subject: [PATCH 09/37] Remove unnecessary class --- src/ConductorSharp.Toolkit/Models/Configuration.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Models/Configuration.cs b/src/ConductorSharp.Toolkit/Models/Configuration.cs index 1ec0615f..04a4380b 100644 --- a/src/ConductorSharp.Toolkit/Models/Configuration.cs +++ b/src/ConductorSharp.Toolkit/Models/Configuration.cs @@ -2,16 +2,10 @@ { public class Configuration { - public class Header - { - public string Name { get; set; } - public string Value { get; set; } - } - public string ApiPath { get; set; } public string Namespace { get; set; } public string BaseUrl { get; set; } public string Destination { get; set; } - public Header[] Headers { get; set; } + public Dictionary Headers { get; set; } = new Dictionary(); } } From 8957a71ffa52899fc2a97f0da25220e035f5e58b Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sat, 13 Aug 2022 22:53:14 +0200 Subject: [PATCH 10/37] Pass headers to client --- src/ConductorSharp.Toolkit/Program.cs | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 55b75471..bbfc1a49 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -9,6 +9,8 @@ using System.Reflection; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; +using RestSharp; +using RestSharp.Serializers.NewtonsoftJson; namespace ConductorSharp.Toolkit { @@ -51,8 +53,6 @@ private static string GetVersionString() private static async Task RunToolkit(ToolkitOptions options) { - Console.WriteLine(options.ConfiugrationFilePath); - if (!File.Exists(options.ConfiugrationFilePath)) { Console.Error.WriteLine($"Configuration file {options.ConfiugrationFilePath} does not exists"); @@ -73,7 +73,7 @@ private static async Task ParseConfigurationFile(string configFil .Build() .Deserialize(await File.ReadAllTextAsync(configFilePath)); - private static IContainer BuildContainer(Configuration input) + private static IContainer BuildContainer(Configuration config) { var serviceCollection = new ServiceCollection(); @@ -81,16 +81,26 @@ private static IContainer BuildContainer(Configuration input) var builder = new ContainerBuilder(); - serviceCollection.Configure(config => + serviceCollection.Configure(scaffoldingConfig => { - config.ApiUrl = input.ApiPath; - config.BaseUrl = input.BaseUrl; - config.BaseNamespace = input.Namespace; - config.Destination = input.Destination; + scaffoldingConfig.ApiUrl = config.ApiPath; + scaffoldingConfig.BaseUrl = config.BaseUrl; + scaffoldingConfig.BaseNamespace = config.Namespace; + scaffoldingConfig.Destination = config.Destination; }); builder.Populate(serviceCollection); - builder.AddWorkflowEngine(input.BaseUrl, input.ApiPath); + builder.AddWorkflowEngine( + config.BaseUrl, + config.ApiPath, + createClient: () => + { + var client = new RestClient(); + client.UseNewtonsoftJson(); + client.AddDefaultHeaders(config.Headers); + return client; + } + ); builder.RegisterModule(new ToolkitModule()); return builder.Build(); From d67e84220c5babd09954309709081a27111dd61a Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 00:40:45 +0200 Subject: [PATCH 11/37] Remove unnecessary newline --- src/ConductorSharp.Toolkit/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index bbfc1a49..9f4476a8 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -47,7 +47,6 @@ public async static Task Main(string[] args) private static string GetVersionString() { var version = Assembly.GetExecutingAssembly().GetName().Version; - return $"version {version.Major}.{version.Minor}.{version.Build}"; } From edc0c785fa8197b2367cfb17ef51568f3e5935e8 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 00:44:03 +0200 Subject: [PATCH 12/37] Add exception handling --- src/ConductorSharp.Toolkit/Program.cs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 9f4476a8..04d72dbe 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -52,18 +52,25 @@ private static string GetVersionString() private static async Task RunToolkit(ToolkitOptions options) { - if (!File.Exists(options.ConfiugrationFilePath)) + try { - Console.Error.WriteLine($"Configuration file {options.ConfiugrationFilePath} does not exists"); - return; - } + if (!File.Exists(options.ConfiugrationFilePath)) + { + Console.Error.WriteLine($"Configuration file {options.ConfiugrationFilePath} does not exists"); + return; + } - var config = await ParseConfigurationFile(options.ConfiugrationFilePath); - var container = BuildContainer(config); - var commandRegistry = container.Resolve(); - // Currently only scaffolding is supported - var command = commandRegistry.Get("scaffold"); - await command.Execute(config); + var config = await ParseConfigurationFile(options.ConfiugrationFilePath); + var container = BuildContainer(config); + var commandRegistry = container.Resolve(); + // Currently only scaffolding is supported + var command = commandRegistry.Get("scaffold"); + await command.Execute(config); + } + catch (Exception ex) + { + Console.Error.WriteLine($"Exception occured with message: {ex.Message}"); + } } private static async Task ParseConfigurationFile(string configFilePath) => From ba74c50da127e54ecd51e0d6f4baba9d03e6d501 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 00:44:54 +0200 Subject: [PATCH 13/37] Rename option --- src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs | 2 +- src/ConductorSharp.Toolkit/Program.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs b/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs index 7ec10c4f..25a6634e 100644 --- a/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs +++ b/src/ConductorSharp.Toolkit/Models/ToolkitOptions.cs @@ -5,6 +5,6 @@ namespace ConductorSharp.Toolkit.Models public class ToolkitOptions { [Option('f', "file", HelpText = "Configuration file", Default = "conductorsharp.yaml")] - public string ConfiugrationFilePath { get; set; } + public string ConfigurationFilePath { get; set; } } } diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 04d72dbe..079cc20d 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -54,13 +54,13 @@ private static async Task RunToolkit(ToolkitOptions options) { try { - if (!File.Exists(options.ConfiugrationFilePath)) + if (!File.Exists(options.ConfigurationFilePath)) { - Console.Error.WriteLine($"Configuration file {options.ConfiugrationFilePath} does not exists"); + Console.Error.WriteLine($"Configuration file {options.ConfigurationFilePath} does not exists"); return; } - var config = await ParseConfigurationFile(options.ConfiugrationFilePath); + var config = await ParseConfigurationFile(options.ConfigurationFilePath); var container = BuildContainer(config); var commandRegistry = container.Resolve(); // Currently only scaffolding is supported From ddc9d2e2e7e919fc9d10563f5a5e4f92060f04f6 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 00:49:14 +0200 Subject: [PATCH 14/37] Specify default value for api path --- src/ConductorSharp.Toolkit/Models/Configuration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ConductorSharp.Toolkit/Models/Configuration.cs b/src/ConductorSharp.Toolkit/Models/Configuration.cs index 04a4380b..9caafdb3 100644 --- a/src/ConductorSharp.Toolkit/Models/Configuration.cs +++ b/src/ConductorSharp.Toolkit/Models/Configuration.cs @@ -2,7 +2,7 @@ { public class Configuration { - public string ApiPath { get; set; } + public string ApiPath { get; set; } = "api"; public string Namespace { get; set; } public string BaseUrl { get; set; } public string Destination { get; set; } From c9456ce60303952d9e4424f27cb82a3781e94cee Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 00:49:23 +0200 Subject: [PATCH 15/37] Validate configuration --- src/ConductorSharp.Toolkit/Program.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 079cc20d..8f2ea394 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -61,6 +61,9 @@ private static async Task RunToolkit(ToolkitOptions options) } var config = await ParseConfigurationFile(options.ConfigurationFilePath); + if (!ValidateConfiguration(config)) + return; + var container = BuildContainer(config); var commandRegistry = container.Resolve(); // Currently only scaffolding is supported @@ -79,6 +82,18 @@ private static async Task ParseConfigurationFile(string configFil .Build() .Deserialize(await File.ReadAllTextAsync(configFilePath)); + private static bool ValidateConfiguration(Configuration config) + { + if (config.BaseUrl == null) + Console.Error.WriteLine("baseUrl property missing in configuration"); + if (config.Namespace == null) + Console.Error.WriteLine("namespace property missing in configuration"); + if (config.Destination == null) + Console.Error.WriteLine("destination property missing in configuration"); + + return config.BaseUrl != null && config.Destination != null && config.Namespace != null; + } + private static IContainer BuildContainer(Configuration config) { var serviceCollection = new ServiceCollection(); From 2980d0e040eb1996d99f643f772ec06aa1e2e50a Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Sun, 14 Aug 2022 23:20:38 +0200 Subject: [PATCH 16/37] Add comment --- src/ConductorSharp.Toolkit/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 8f2ea394..06417c33 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -70,6 +70,7 @@ private static async Task RunToolkit(ToolkitOptions options) var command = commandRegistry.Get("scaffold"); await command.Execute(config); } + // TODO: Improve error handling catch (Exception ex) { Console.Error.WriteLine($"Exception occured with message: {ex.Message}"); From bbd3c14e49106c56cc3f8a5e9fc112090098ff64 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 00:39:24 +0200 Subject: [PATCH 17/37] Make method sync --- src/ConductorSharp.Toolkit/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index 06417c33..cda3d84c 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -60,7 +60,7 @@ private static async Task RunToolkit(ToolkitOptions options) return; } - var config = await ParseConfigurationFile(options.ConfigurationFilePath); + var config = ParseConfigurationFile(options.ConfigurationFilePath); if (!ValidateConfiguration(config)) return; @@ -77,11 +77,11 @@ private static async Task RunToolkit(ToolkitOptions options) } } - private static async Task ParseConfigurationFile(string configFilePath) => + private static Configuration ParseConfigurationFile(string configFilePath) => new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) .Build() - .Deserialize(await File.ReadAllTextAsync(configFilePath)); + .Deserialize(File.ReadAllText(configFilePath)); private static bool ValidateConfiguration(Configuration config) { From 8e00de7c16cf4bba3856708011aa56d78b465714 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 09:19:38 +0200 Subject: [PATCH 18/37] Change copyright line --- src/ConductorSharp.Toolkit/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index cda3d84c..ada2e1fa 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -33,6 +33,7 @@ public async static Task Main(string[] args) parseResult, help => { + help.Copyright = new CopyrightInfo("Codaxy", 2022); help.AddPreOptionsLine("Usage: dotnet conductorsharp [options]"); help.Heading = versionText; return help; From d17b1fb39d2018822691ae3d18a0d8350f582d94 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 10:13:05 +0200 Subject: [PATCH 19/37] Read version from constant string --- src/ConductorSharp.Toolkit/Program.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index ada2e1fa..b5773cc9 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -16,13 +16,15 @@ namespace ConductorSharp.Toolkit { class Program { + public const string Version = "0.0.1"; + public async static Task Main(string[] args) { var parseResult = new Parser(opts => opts.HelpWriter = null).ParseArguments(args); var withParsed = await parseResult.WithParsedAsync(RunToolkit); withParsed.WithNotParsed(err => { - var versionText = new HeadingInfo("conductorsharp", GetVersionString()); + var versionText = new HeadingInfo("conductorsharp", Version); var writer = err.IsHelp() || err.IsVersion() ? Console.Out : Console.Error; string textToWrite; if (err.IsVersion()) @@ -45,12 +47,6 @@ public async static Task Main(string[] args) }); } - private static string GetVersionString() - { - var version = Assembly.GetExecutingAssembly().GetName().Version; - return $"version {version.Major}.{version.Minor}.{version.Build}"; - } - private static async Task RunToolkit(ToolkitOptions options) { try From fc1e20ca790ca77171ab7f9c4ebe0a53436642e3 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 12:05:29 +0200 Subject: [PATCH 20/37] Perform IsNullOrEmpty check instead of null check only --- src/ConductorSharp.Toolkit/Program.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index b5773cc9..fed52eff 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -82,14 +82,24 @@ private static Configuration ParseConfigurationFile(string configFilePath) => private static bool ValidateConfiguration(Configuration config) { - if (config.BaseUrl == null) + bool validConfiguration = true; + if (string.IsNullOrEmpty(config.BaseUrl)) + { Console.Error.WriteLine("baseUrl property missing in configuration"); - if (config.Namespace == null) + validConfiguration = false; + } + if (string.IsNullOrEmpty(config.Namespace)) + { Console.Error.WriteLine("namespace property missing in configuration"); - if (config.Destination == null) + validConfiguration = false; + } + if (string.IsNullOrEmpty(config.Destination)) + { Console.Error.WriteLine("destination property missing in configuration"); + validConfiguration = false; + } - return config.BaseUrl != null && config.Destination != null && config.Namespace != null; + return validConfiguration; } private static IContainer BuildContainer(Configuration config) From ac4bc26f9f9357b1f74826e2a86b9f62196dd664 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 12:51:11 +0200 Subject: [PATCH 21/37] Add package used for code generation --- src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj index e94e30a4..519a0fad 100644 --- a/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj +++ b/src/ConductorSharp.Toolkit/ConductorSharp.Toolkit.csproj @@ -26,6 +26,7 @@ + From 27eca6fa9585f05de8e572f807073e3a9a951b2d Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 14:56:11 +0200 Subject: [PATCH 22/37] Add class for generating task models --- .../Util/TaskModelGenerator.cs | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs new file mode 100644 index 00000000..b7f098f1 --- /dev/null +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -0,0 +1,189 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ConductorSharp.Toolkit.Util +{ + public class TaskModelGenerator + { + public enum ModelType + { + Task, + Workflow + }; + + public class PropertyData + { + public string Name { get; set; } + public string OriginalName { get; set; } + public string Type { get; set; } + } + + public string Namespace { get; set; } + public string ClassName { get; set; } + public string OriginalName { get; set; } + public string OwnerApp { get; set; } + public string OwnerEmail { get; set; } + public string Summary { get; set; } + public string Note { get; private set; } = string.Empty; + + protected CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); + private readonly ModelType _modelType; + private List _inputProperties = new(); + private List _outputProperties = new(); + + public TaskModelGenerator(string @namespace, string className, ModelType modelType) + { + Namespace = @namespace; + ClassName = className; + _modelType = modelType; + } + + public void AppendNote(string note) => Note += note; + + public void AddInputProperty(string propName, string originalName, string type) + { + _inputProperties.Add( + new PropertyData + { + Name = propName, + OriginalName = originalName, + Type = type + } + ); + } + + public void AddOutputProperty(string propName, string originalName, string type) + { + _inputProperties.Add( + new PropertyData + { + Name = propName, + OriginalName = originalName, + Type = type + } + ); + } + + public string Build() + { + _compilationUnit = _compilationUnit.AddUsings( + CreateUsings("ConductorSharp.Engine.Model", "ConductorSharp.Engine.Util", "MediatR", "Newtonsoft.Json") + ); + var namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(Namespace)); + namespaceDeclaration = namespaceDeclaration.AddMembers(CreateInputClass(), CreateOutputClass(), CreateModelClass()); + _compilationUnit = _compilationUnit.AddMembers(namespaceDeclaration); + return _compilationUnit.NormalizeWhitespace().ToFullString(); + } + + private SyntaxTriviaList GenerateAutoGeneratedComment() + { + // This comment is written: + + // + // This code was generated by a tool. + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + + var list = SyntaxFactory.TriviaList(); + list.Add(SyntaxFactory.Comment("// ")); + list.Add(SyntaxFactory.Comment("// This code was generated by a tool.")); + list.Add(SyntaxFactory.Comment("// Changes to this file may cause incorrect behavior and will be lost if")); + list.Add(SyntaxFactory.Comment("// the code is regenerated.")); + list.Add(SyntaxFactory.Comment("// ")); + + return list; + } + + private UsingDirectiveSyntax[] CreateUsings(params string[] namespaces) + { + var usings = namespaces.Select(@namespace => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(@namespace))).ToArray(); + usings[0] = usings[0].WithUsingKeyword( + SyntaxFactory.Token(GenerateAutoGeneratedComment(), SyntaxKind.UsingKeyword, SyntaxFactory.TriviaList()) + ); + return usings; + } + + private AttributeSyntax CreateInputPropertyAttribute(string originalName) + { + var attribute = SyntaxFactory + .Attribute(SyntaxFactory.ParseName("JsonProperty")) + .AddArgumentListArguments( + SyntaxFactory.AttributeArgument( + SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(originalName)) + ) + ); + return attribute; + } + + private PropertyDeclarationSyntax CreateInputProperty(PropertyData inputData) + { + var propertyDeclaration = SyntaxFactory + .PropertyDeclaration(SyntaxFactory.ParseTypeName(inputData.Type), inputData.Name) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddAccessorListAccessors( + SyntaxFactory + .AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), + SyntaxFactory + .AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)) + ); + + var attributeList = SyntaxFactory.AttributeList( + SyntaxFactory.SingletonSeparatedList(CreateInputPropertyAttribute(inputData.OriginalName)) + ); + propertyDeclaration = propertyDeclaration.AddAttributeLists(attributeList); + return propertyDeclaration; + } + + private ClassDeclarationSyntax CreateInputClass() + { + var typeArgumentList = SyntaxFactory.TypeArgumentList( + SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ParseTypeName($"{ClassName}Output")) + ); + var baseType = SyntaxFactory.SimpleBaseType(SyntaxFactory.GenericName("IRequest").WithTypeArgumentList(typeArgumentList)); + var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(baseType)); + var classDeclaration = SyntaxFactory + .ClassDeclaration($"{ClassName}Input") + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) + .WithBaseList(baseList) + .AddMembers(_inputProperties.Select(CreateInputProperty).ToArray()); + + return classDeclaration; + } + + private ClassDeclarationSyntax CreateOutputClass() + { + var classDeclaration = SyntaxFactory + .ClassDeclaration($"{ClassName}Output") + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) + .AddMembers(_outputProperties.Select(CreateInputProperty).ToArray()); + + return classDeclaration; + } + + private ClassDeclarationSyntax CreateModelClass() + { + var typeArgumentList = SyntaxFactory.TypeArgumentList( + SyntaxFactory.SeparatedList( + new List { SyntaxFactory.ParseTypeName($"{ClassName}Input"), SyntaxFactory.ParseTypeName($"{ClassName}Output") } + ) + ); + var baseType = SyntaxFactory.SimpleBaseType( + SyntaxFactory + .GenericName(_modelType == ModelType.Task ? "SimpleTaskModel" : "SubWorkflowTaskModel") + .WithTypeArgumentList(typeArgumentList) + ); + var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(baseType)); + var classDeclaration = SyntaxFactory + .ClassDeclaration(ClassName) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) + .WithBaseList(baseList); + + return classDeclaration; + } + } +} From 095e1ad9235a8c7e68b1fee25def87fb82e66c0c Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 15 Aug 2022 15:01:22 +0200 Subject: [PATCH 23/37] Change the way note is build --- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index b7f098f1..f4387af7 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Text; namespace ConductorSharp.Toolkit.Util { @@ -25,12 +26,12 @@ public class PropertyData public string OwnerApp { get; set; } public string OwnerEmail { get; set; } public string Summary { get; set; } - public string Note { get; private set; } = string.Empty; protected CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); private readonly ModelType _modelType; private List _inputProperties = new(); private List _outputProperties = new(); + private StringBuilder _noteBuilder = new StringBuilder(); public TaskModelGenerator(string @namespace, string className, ModelType modelType) { @@ -39,7 +40,7 @@ public TaskModelGenerator(string @namespace, string className, ModelType modelTy _modelType = modelType; } - public void AppendNote(string note) => Note += note; + public void AppendNoteLine(string note) => _noteBuilder.AppendLine(note); public void AddInputProperty(string propName, string originalName, string type) { From 480a759184845126990bbdd3ceebdf22c072f5dd Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 08:59:50 +0200 Subject: [PATCH 24/37] Change the way properties are added, fix comment generation --- .../Util/TaskModelGenerator.cs | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index f4387af7..c6c7b476 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -18,6 +18,7 @@ public class PropertyData public string Name { get; set; } public string OriginalName { get; set; } public string Type { get; set; } + public Dictionary XmlComments { get; } = new(); } public string Namespace { get; set; } @@ -42,28 +43,14 @@ public TaskModelGenerator(string @namespace, string className, ModelType modelTy public void AppendNoteLine(string note) => _noteBuilder.AppendLine(note); - public void AddInputProperty(string propName, string originalName, string type) + public void AddInputProperty(PropertyData propData) { - _inputProperties.Add( - new PropertyData - { - Name = propName, - OriginalName = originalName, - Type = type - } - ); + _inputProperties.Add(propData); } - public void AddOutputProperty(string propName, string originalName, string type) + public void AddOutputProperty(PropertyData propData) { - _inputProperties.Add( - new PropertyData - { - Name = propName, - OriginalName = originalName, - Type = type - } - ); + _outputProperties.Add(propData); } public string Build() @@ -89,11 +76,11 @@ private SyntaxTriviaList GenerateAutoGeneratedComment() // var list = SyntaxFactory.TriviaList(); - list.Add(SyntaxFactory.Comment("// ")); - list.Add(SyntaxFactory.Comment("// This code was generated by a tool.")); - list.Add(SyntaxFactory.Comment("// Changes to this file may cause incorrect behavior and will be lost if")); - list.Add(SyntaxFactory.Comment("// the code is regenerated.")); - list.Add(SyntaxFactory.Comment("// ")); + list = list.Add(SyntaxFactory.Comment("// ")); + list = list.Add(SyntaxFactory.Comment("// This code was generated by a tool.")); + list = list.Add(SyntaxFactory.Comment("// Changes to this file may cause incorrect behavior and will be lost if")); + list = list.Add(SyntaxFactory.Comment("// the code is regenerated.")); + list = list.Add(SyntaxFactory.Comment("// ")); return list; } @@ -101,9 +88,7 @@ private SyntaxTriviaList GenerateAutoGeneratedComment() private UsingDirectiveSyntax[] CreateUsings(params string[] namespaces) { var usings = namespaces.Select(@namespace => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(@namespace))).ToArray(); - usings[0] = usings[0].WithUsingKeyword( - SyntaxFactory.Token(GenerateAutoGeneratedComment(), SyntaxKind.UsingKeyword, SyntaxFactory.TriviaList()) - ); + usings[0] = usings[0].WithLeadingTrivia(GenerateAutoGeneratedComment()); return usings; } @@ -119,7 +104,7 @@ private AttributeSyntax CreateInputPropertyAttribute(string originalName) return attribute; } - private PropertyDeclarationSyntax CreateInputProperty(PropertyData inputData) + private PropertyDeclarationSyntax CreateProperty(PropertyData inputData) { var propertyDeclaration = SyntaxFactory .PropertyDeclaration(SyntaxFactory.ParseTypeName(inputData.Type), inputData.Name) @@ -151,7 +136,7 @@ private ClassDeclarationSyntax CreateInputClass() .ClassDeclaration($"{ClassName}Input") .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .WithBaseList(baseList) - .AddMembers(_inputProperties.Select(CreateInputProperty).ToArray()); + .AddMembers(_inputProperties.Select(CreateProperty).ToArray()); return classDeclaration; } @@ -161,7 +146,7 @@ private ClassDeclarationSyntax CreateOutputClass() var classDeclaration = SyntaxFactory .ClassDeclaration($"{ClassName}Output") .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) - .AddMembers(_outputProperties.Select(CreateInputProperty).ToArray()); + .AddMembers(_outputProperties.Select(CreateProperty).ToArray()); return classDeclaration; } From 4afdb46b65b236953a79258cc13bab2abd2486ec Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 11:52:23 +0200 Subject: [PATCH 25/37] Implement new way of scaffolding for workflows --- .../Service/ScaffoldingService.cs | 47 +++++++++++-------- .../Util/TaskModelGenerator.cs | 27 ++++++++--- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index 2647a610..e7f21c8f 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -69,8 +69,6 @@ public async Task Scaffold() public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) { - var lines = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/WorkflowTemplate.default"); - string name = SnakeCaseUtil.ToPascalCase($"{workflowDefinition.Name}_V{workflowDefinition.Version}").Trim(); string note = null; if (LangUtils.MakeValidMemberName(name, "A", out name)) @@ -78,6 +76,7 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) note = "The autogenerated name has been changed because it is invalid C# member name"; } + var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Tasks", name, TaskModelGenerator.ModelType.Workflow); string workflowDescription = workflowDefinition.Description; string[] labels; @@ -97,13 +96,14 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) _logger.LogWarning("Unable to parse description for workflow {0}", workflowDefinition.Name); } - var inputLinesBuilder = new StringBuilder(); try { var inputParameters = JObject.Parse(workflowDefinition.InputParametersJSON[0]); foreach (var param in inputParameters) { + var inputPropData = new TaskModelGenerator.PropertyData(); + var value = param.Value.SelectToken("value")?.ToString(Newtonsoft.Json.Formatting.None); var type = param.Value.SelectToken("type")?.Value(); var description = param.Value.SelectToken("description")?.Value(); @@ -111,10 +111,10 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) if (type == null) type = "string"; - AppendXmlComment(inputLinesBuilder, "originalName", param.Key); + inputPropData.XmlComments["originalName"] = param.Key; if (!string.IsNullOrEmpty(description)) - AppendXmlComment(inputLinesBuilder, "summary", value); + inputPropData.XmlComments["summary"] = description; switch (type) { @@ -122,12 +122,13 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) case "integer": if (!string.IsNullOrEmpty(value)) { - AppendXmlComment(inputLinesBuilder, "remark", $"Example: {value}"); + inputPropData.XmlComments["remark"] = $"Example: {value}"; } - AppendClassProperty(inputLinesBuilder, "dynamic", param.Key); + DefinePropertyParams(inputPropData, "dynamic", param.Key); + break; case "toggle": - AppendClassProperty(inputLinesBuilder, "dynamic", param.Key); + DefinePropertyParams(inputPropData, "dynamic", param.Key); break; case "select": var optionsToken = param.Value.SelectToken("options"); @@ -139,13 +140,15 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) options = optionsArray.ToObject(); } if (options != null && options.Length > 0) - AppendXmlComment(inputLinesBuilder, "remark", $"Options: {string.Join(',', options)}"); + inputPropData.XmlComments["remark"] = $"Options: {string.Join(',', options)}"; - AppendClassProperty(inputLinesBuilder, "dynamic", param.Key); + DefinePropertyParams(inputPropData, "dynamic", param.Key); break; default: break; } + + modelGenerator.AddInputProperty(inputPropData); } } catch (Exception) @@ -164,19 +167,17 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) if (string.IsNullOrEmpty(workflowDefinition.OwnerApp)) _logger.LogWarning($"No owner app defined for task {workflowDefinition.Name}"); - lines = lines.Replace("{{inputProperties}}", inputLinesBuilder.ToString()); - lines = lines.Replace("{{workflowName}}", name); - lines = lines.Replace("{{note}}", note); - lines = lines.Replace("{{ownerEmail}}", $"{workflowDefinition.OwnerEmail}"); - lines = lines.Replace("{{ownerApp}}", $"{workflowDefinition.OwnerApp}"); - lines = lines.Replace("{{originalName}}", $"{workflowDefinition.Name}"); - lines = lines.Replace("{{description}}", workflowDescription); - lines = lines.Replace("{{commentDescription}}", workflowDescription?.Replace('\n', ',')); + //modelGenerator.OwnerApp = workflowDefinition.OwnerApp; + modelGenerator.AddXmlComment("summary", workflowDescription?.Replace('\n', ',')); + modelGenerator.AddXmlComment("originalName", workflowDefinition.Name); + modelGenerator.AddXmlComment("ownerApp", workflowDefinition.OwnerApp); + modelGenerator.AddXmlComment("ownerEmail", workflowDefinition.OwnerEmail); + modelGenerator.AddXmlComment("note", note); if (_config.Dryrun) return null; - return lines; + return modelGenerator.Build(); } private void AppendClassProperty(StringBuilder linesBuilder, string type, string name) @@ -186,6 +187,14 @@ private void AppendClassProperty(StringBuilder linesBuilder, string type, string linesBuilder.AppendLine($" public {type} {propertyName} {{ get; set; }}"); } + private void DefinePropertyParams(TaskModelGenerator.PropertyData propData, string type, string originalName) + { + LangUtils.MakeValidMemberName(SnakeCaseUtil.ToPascalCase(originalName), "A", out var propertyName); + propData.OriginalName = originalName; + propData.Name = propertyName; + propData.Type = type; + } + private void AppendXmlComment(StringBuilder linesBuilder, string tag, string value) { linesBuilder.AppendLine($" /// <{tag}>"); diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index c6c7b476..93543b59 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -24,15 +24,13 @@ public class PropertyData public string Namespace { get; set; } public string ClassName { get; set; } public string OriginalName { get; set; } - public string OwnerApp { get; set; } - public string OwnerEmail { get; set; } public string Summary { get; set; } protected CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); private readonly ModelType _modelType; private List _inputProperties = new(); private List _outputProperties = new(); - private StringBuilder _noteBuilder = new StringBuilder(); + private readonly Dictionary _xmlComments = new(); public TaskModelGenerator(string @namespace, string className, ModelType modelType) { @@ -41,8 +39,6 @@ public TaskModelGenerator(string @namespace, string className, ModelType modelTy _modelType = modelType; } - public void AppendNoteLine(string note) => _noteBuilder.AppendLine(note); - public void AddInputProperty(PropertyData propData) { _inputProperties.Add(propData); @@ -53,6 +49,8 @@ public void AddOutputProperty(PropertyData propData) _outputProperties.Add(propData); } + public void AddXmlComment(string tag, string value) => _xmlComments[tag] = value; + public string Build() { _compilationUnit = _compilationUnit.AddUsings( @@ -122,9 +120,25 @@ private PropertyDeclarationSyntax CreateProperty(PropertyData inputData) SyntaxFactory.SingletonSeparatedList(CreateInputPropertyAttribute(inputData.OriginalName)) ); propertyDeclaration = propertyDeclaration.AddAttributeLists(attributeList); + propertyDeclaration = propertyDeclaration.WithLeadingTrivia(GenerateXmlDocComment(inputData.XmlComments)); + return propertyDeclaration; } + private SyntaxTriviaList GenerateXmlDocComment(Dictionary xmlComments) + { + var list = new SyntaxTriviaList(); + + foreach (var elem in xmlComments) + { + list = list.Add(SyntaxFactory.Comment($"/// <{elem.Key}>")); + list = list.Add(SyntaxFactory.Comment($"/// {elem.Value}")); + list = list.Add(SyntaxFactory.Comment($"/// ")); + } + + return list; + } + private ClassDeclarationSyntax CreateInputClass() { var typeArgumentList = SyntaxFactory.TypeArgumentList( @@ -167,7 +181,8 @@ private ClassDeclarationSyntax CreateModelClass() var classDeclaration = SyntaxFactory .ClassDeclaration(ClassName) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) - .WithBaseList(baseList); + .WithBaseList(baseList) + .WithLeadingTrivia(GenerateXmlDocComment(_xmlComments)); return classDeclaration; } From f80cf3a644ac3b328221bf8374ec537e2c50b601 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 12:52:06 +0200 Subject: [PATCH 26/37] Add using --- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index 93543b59..fe51e7b1 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -54,7 +54,13 @@ public void AddOutputProperty(PropertyData propData) public string Build() { _compilationUnit = _compilationUnit.AddUsings( - CreateUsings("ConductorSharp.Engine.Model", "ConductorSharp.Engine.Util", "MediatR", "Newtonsoft.Json") + CreateUsings( + "ConductorSharp.Engine.Model", + "ConductorSharp.Engine.Util", + "MediatR", + "Newtonsoft.Json", + "ConductorSharp.Engine.Builders" + ) ); var namespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(Namespace)); namespaceDeclaration = namespaceDeclaration.AddMembers(CreateInputClass(), CreateOutputClass(), CreateModelClass()); From f8e6ca7f1ac6df44eefb9538d5df6462f877d2bf Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 12:52:36 +0200 Subject: [PATCH 27/37] Implement scaffolding using roslyn --- .../Service/ScaffoldingService.cs | 114 ++++++++---------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index e7f21c8f..052eb879 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -27,47 +27,54 @@ public async Task Scaffold() { var workflowDefinitions = await _metadataService.GetAllWorkflowDefinitions(); var workflowCollectionBuilder = new StringBuilder(); + var workflowDirectory = Path.Combine(_config.Destination, "Workflows"); foreach (var workflowDefinition in workflowDefinitions) { - var workflowClass = CreateWorkflowClass(workflowDefinition); + (var contents, var modelClassName) = CreateWorkflowClass(workflowDefinition); - if (workflowClass != null) - workflowCollectionBuilder.Append(workflowClass); + if (contents != null) + { + var filePath = Path.Combine(workflowDirectory, $"{modelClassName}.scaff.cs"); + File.WriteAllText(filePath, contents); + } } var taskDefinitions = await _metadataService.GetAllTaskDefinitions(); - var taskCollectionBuilder = new StringBuilder(); + var tasksDirectory = Path.Combine(_config.Destination, "Tasks"); foreach (var taskDefinition in taskDefinitions) { - var taskClass = CreateTaskClass(taskDefinition); + (var contents, var modelClassName) = CreateTaskClass(taskDefinition); - if (taskClass != null) - taskCollectionBuilder.Append(taskClass); + if (contents != null) + { + var filePath = Path.Combine(tasksDirectory, $"{modelClassName}.scaff.cs"); + File.WriteAllText(filePath, contents); + } } - var taskTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/TaskCollectionTemplate.default"); - var taskCollection = taskCollectionBuilder.ToString(); - taskTemplate = taskTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Tasks"); - taskTemplate = taskTemplate.Replace("{{taskCollection}}", taskCollection); - var dir = _config.Destination + Path.DirectorySeparatorChar + "Tasks"; + //var taskTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/TaskCollectionTemplate.default"); + //var taskCollection = taskCollectionBuilder.ToString(); + //taskTemplate = taskTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Tasks"); + //taskTemplate = taskTemplate.Replace("{{taskCollection}}", taskCollection); + //var dir = _config.Destination + Path.DirectorySeparatorChar + "Tasks"; - Directory.CreateDirectory(dir); + //Directory.CreateDirectory(dir); - File.WriteAllText(dir + Path.DirectorySeparatorChar + "Tasks.scaff.cs", taskTemplate); + //File.WriteAllText(dir + Path.DirectorySeparatorChar + "Tasks.scaff.cs", taskTemplate); - var workflowTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/WorkflowCollectionTemplate.default"); - var workflowCollection = workflowCollectionBuilder.ToString(); - workflowTemplate = workflowTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Workflows"); - workflowTemplate = workflowTemplate.Replace("{{workflowCollection}}", workflowCollection); - var workflowDir = _config.Destination + Path.DirectorySeparatorChar + "Workflows"; + //var workflowTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/WorkflowCollectionTemplate.default"); + //var workflowCollection = workflowCollectionBuilder.ToString(); + //workflowTemplate = workflowTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Workflows"); + //workflowTemplate = workflowTemplate.Replace("{{workflowCollection}}", workflowCollection); + //var workflowDir = _config.Destination + Path.DirectorySeparatorChar + "Workflows"; - Directory.CreateDirectory(workflowDir); + //Directory.CreateDirectory(workflowDir); - File.WriteAllText(workflowDir + Path.DirectorySeparatorChar + "Workflows.scaff.cs", workflowTemplate); + //File.WriteAllText(workflowDir + Path.DirectorySeparatorChar + "Workflows.scaff.cs", workflowTemplate); } - public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) + public (string contents, string modelClassName) CreateWorkflowClass(WorkflowDefinition workflowDefinition) { string name = SnakeCaseUtil.ToPascalCase($"{workflowDefinition.Name}_V{workflowDefinition.Version}").Trim(); string note = null; @@ -76,7 +83,7 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) note = "The autogenerated name has been changed because it is invalid C# member name"; } - var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Tasks", name, TaskModelGenerator.ModelType.Workflow); + var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Workflows", name, TaskModelGenerator.ModelType.Workflow); string workflowDescription = workflowDefinition.Description; string[] labels; @@ -125,10 +132,12 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) inputPropData.XmlComments["remark"] = $"Example: {value}"; } DefinePropertyParams(inputPropData, "dynamic", param.Key); + modelGenerator.AddInputProperty(inputPropData); break; case "toggle": DefinePropertyParams(inputPropData, "dynamic", param.Key); + modelGenerator.AddInputProperty(inputPropData); break; case "select": var optionsToken = param.Value.SelectToken("options"); @@ -143,12 +152,11 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) inputPropData.XmlComments["remark"] = $"Options: {string.Join(',', options)}"; DefinePropertyParams(inputPropData, "dynamic", param.Key); + modelGenerator.AddInputProperty(inputPropData); break; default: break; } - - modelGenerator.AddInputProperty(inputPropData); } } catch (Exception) @@ -167,7 +175,6 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) if (string.IsNullOrEmpty(workflowDefinition.OwnerApp)) _logger.LogWarning($"No owner app defined for task {workflowDefinition.Name}"); - //modelGenerator.OwnerApp = workflowDefinition.OwnerApp; modelGenerator.AddXmlComment("summary", workflowDescription?.Replace('\n', ',')); modelGenerator.AddXmlComment("originalName", workflowDefinition.Name); modelGenerator.AddXmlComment("ownerApp", workflowDefinition.OwnerApp); @@ -175,9 +182,9 @@ public string CreateWorkflowClass(WorkflowDefinition workflowDefinition) modelGenerator.AddXmlComment("note", note); if (_config.Dryrun) - return null; + return (null, null); - return modelGenerator.Build(); + return (modelGenerator.Build(), name); } private void AppendClassProperty(StringBuilder linesBuilder, string type, string name) @@ -202,21 +209,8 @@ private void AppendXmlComment(StringBuilder linesBuilder, string tag, string val linesBuilder.AppendLine($" /// "); } - public string CreateTaskClass(TaskDefinition taskDefinition) + public (string contents, string modelClassName) CreateTaskClass(TaskDefinition taskDefinition) { - var lines = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/WorkerTemplate.default"); - - var namespaceRegex = new Regex("(^[^_]+)_.+"); - - var matches = namespaceRegex.Match(taskDefinition.Name).Groups; - - string naspace = ""; - if (matches.Count > 1) - { - naspace = matches[1].Value.ToLowerInvariant(); - naspace = char.ToUpperInvariant(naspace[0]) + naspace[1..]; - } - string name = SnakeCaseUtil.ToPascalCase(taskDefinition.Name).Trim(); string note = null; if (LangUtils.MakeValidMemberName(name, "A", out name)) @@ -224,30 +218,26 @@ public string CreateTaskClass(TaskDefinition taskDefinition) note = "The autogenerated name has been prepended because it starts with a digit character."; } - var inputLinesBuilder = new StringBuilder(); + var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Tasks", name, TaskModelGenerator.ModelType.Task); foreach (var property in taskDefinition.InputKeys) { - AppendXmlComment(inputLinesBuilder, "originalName", property); - AppendClassProperty(inputLinesBuilder, "dynamic", property); + var inputPropData = new TaskModelGenerator.PropertyData(); + DefinePropertyParams(inputPropData, "dynamic", property); + inputPropData.XmlComments["originalName"] = property; + modelGenerator.AddInputProperty(inputPropData); } - var outputLinesBuilder = new StringBuilder(); foreach (var property in taskDefinition.OutputKeys) { - AppendXmlComment(outputLinesBuilder, "originalName", property); - AppendClassProperty(outputLinesBuilder, "dynamic", property); + var inputPropData = new TaskModelGenerator.PropertyData(); + DefinePropertyParams(inputPropData, "dynamic", property); + inputPropData.XmlComments["originalName"] = property; + modelGenerator.AddOutputProperty(inputPropData); } - var generatedNamespace = _config.BaseNamespace + ".Tasks" + (!string.IsNullOrEmpty(naspace) ? $".{naspace}" : ""); - - lines = lines.Replace("{{workerName}}", name); - lines = lines.Replace("{{note}}", note); - lines = lines.Replace("{{inputProperties}}", inputLinesBuilder.ToString()); - lines = lines.Replace("{{outputProperties}}", outputLinesBuilder.ToString()); - lines = lines.Replace("{{namespace}}", $"{generatedNamespace}"); - lines = lines.Replace("{{ownerEmail}}", $"{taskDefinition.OwnerEmail}"); - lines = lines.Replace("{{ownerApp}}", $"{taskDefinition.OwnerApp}"); - lines = lines.Replace("{{originalName}}", $"{taskDefinition.Name}"); + modelGenerator.AddXmlComment("originalName", taskDefinition.Name); + modelGenerator.AddXmlComment("ownerEmail", taskDefinition.OwnerEmail); + modelGenerator.AddXmlComment("node", note); var description = ""; try @@ -268,13 +258,11 @@ public string CreateTaskClass(TaskDefinition taskDefinition) if (string.IsNullOrEmpty(ownerApp)) _logger.LogWarning($"No owner app defined for task {taskDefinition.Name}"); - lines = lines.Replace("{{description}}", description); - lines = lines.Replace("{{commentDescription}}", description.Replace('\n', ',')); - + modelGenerator.AddXmlComment("summary", description.Replace('\n', ',')); if (_config.Dryrun) - return null; + return (null, null); - return lines; + return (modelGenerator.Build(), name); } } } From 4fbda2cb77c6ee5cdef35c88e25c8a74f200a7e8 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 12:54:46 +0200 Subject: [PATCH 28/37] Remve unnecessary property --- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index fe51e7b1..34b0e811 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -24,7 +24,6 @@ public class PropertyData public string Namespace { get; set; } public string ClassName { get; set; } public string OriginalName { get; set; } - public string Summary { get; set; } protected CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); private readonly ModelType _modelType; From 28210b59c628834ab9a9b475e329f08edd5fd17b Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 13:04:23 +0200 Subject: [PATCH 29/37] Create directory sctructure if it does not exists --- .../Service/ScaffoldingService.cs | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index 052eb879..00f897a9 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -28,6 +28,7 @@ public async Task Scaffold() var workflowDefinitions = await _metadataService.GetAllWorkflowDefinitions(); var workflowCollectionBuilder = new StringBuilder(); var workflowDirectory = Path.Combine(_config.Destination, "Workflows"); + Directory.CreateDirectory(workflowDirectory); foreach (var workflowDefinition in workflowDefinitions) { (var contents, var modelClassName) = CreateWorkflowClass(workflowDefinition); @@ -42,6 +43,7 @@ public async Task Scaffold() var taskDefinitions = await _metadataService.GetAllTaskDefinitions(); var taskCollectionBuilder = new StringBuilder(); var tasksDirectory = Path.Combine(_config.Destination, "Tasks"); + Directory.CreateDirectory(tasksDirectory); foreach (var taskDefinition in taskDefinitions) { (var contents, var modelClassName) = CreateTaskClass(taskDefinition); @@ -52,26 +54,6 @@ public async Task Scaffold() File.WriteAllText(filePath, contents); } } - - //var taskTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/TaskCollectionTemplate.default"); - //var taskCollection = taskCollectionBuilder.ToString(); - //taskTemplate = taskTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Tasks"); - //taskTemplate = taskTemplate.Replace("{{taskCollection}}", taskCollection); - //var dir = _config.Destination + Path.DirectorySeparatorChar + "Tasks"; - - //Directory.CreateDirectory(dir); - - //File.WriteAllText(dir + Path.DirectorySeparatorChar + "Tasks.scaff.cs", taskTemplate); - - //var workflowTemplate = EmbeddedFileHelper.GetLinesFromEmbeddedFile("~/Templates/WorkflowCollectionTemplate.default"); - //var workflowCollection = workflowCollectionBuilder.ToString(); - //workflowTemplate = workflowTemplate.Replace("{{namespace}}", _config.BaseNamespace + ".Workflows"); - //workflowTemplate = workflowTemplate.Replace("{{workflowCollection}}", workflowCollection); - //var workflowDir = _config.Destination + Path.DirectorySeparatorChar + "Workflows"; - - //Directory.CreateDirectory(workflowDir); - - //File.WriteAllText(workflowDir + Path.DirectorySeparatorChar + "Workflows.scaff.cs", workflowTemplate); } public (string contents, string modelClassName) CreateWorkflowClass(WorkflowDefinition workflowDefinition) From c5b07488e1e81425ee8e3907062986fbdb86c00e Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 13:04:58 +0200 Subject: [PATCH 30/37] Remove unnecessary lines --- src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index 00f897a9..cc1bc8a2 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -26,7 +26,6 @@ public ScaffoldingService(IMetadataService metadataService, IOptions Date: Tue, 16 Aug 2022 13:17:36 +0200 Subject: [PATCH 31/37] Remove unnecessary comment --- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index 34b0e811..d3e08219 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -69,15 +69,6 @@ public string Build() private SyntaxTriviaList GenerateAutoGeneratedComment() { - // This comment is written: - - // - // This code was generated by a tool. - // - // Changes to this file may cause incorrect behavior and will be lost if - // the code is regenerated. - // - var list = SyntaxFactory.TriviaList(); list = list.Add(SyntaxFactory.Comment("// ")); list = list.Add(SyntaxFactory.Comment("// This code was generated by a tool.")); From a9926c72b1d57fb9e85d9cc0cdb86ec9d98f8f32 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Tue, 16 Aug 2022 13:19:19 +0200 Subject: [PATCH 32/37] Add stack trace --- src/ConductorSharp.Toolkit/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ConductorSharp.Toolkit/Program.cs b/src/ConductorSharp.Toolkit/Program.cs index fed52eff..f25f91bb 100644 --- a/src/ConductorSharp.Toolkit/Program.cs +++ b/src/ConductorSharp.Toolkit/Program.cs @@ -71,6 +71,8 @@ private static async Task RunToolkit(ToolkitOptions options) catch (Exception ex) { Console.Error.WriteLine($"Exception occured with message: {ex.Message}"); + Console.Error.WriteLine("Stack trace:"); + Console.Error.WriteLine(ex.StackTrace); } } From 004f9645b0d84cf02bb6483b7fdbb33de6b5ffdf Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 22 Aug 2022 13:19:16 +0200 Subject: [PATCH 33/37] Generate OriginalName attribute --- .../Util/TaskModelGenerator.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index d3e08219..93de7e7a 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -98,6 +98,18 @@ private AttributeSyntax CreateInputPropertyAttribute(string originalName) return attribute; } + private AttributeSyntax CreateOriginalNameAttribute(string originalName) + { + var attribute = SyntaxFactory + .Attribute(SyntaxFactory.ParseName("OriginalName")) + .AddArgumentListArguments( + SyntaxFactory.AttributeArgument( + SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(originalName)) + ) + ); + return attribute; + } + private PropertyDeclarationSyntax CreateProperty(PropertyData inputData) { var propertyDeclaration = SyntaxFactory @@ -174,9 +186,12 @@ private ClassDeclarationSyntax CreateModelClass() .WithTypeArgumentList(typeArgumentList) ); var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(baseType)); + + var attributeList = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(CreateOriginalNameAttribute(OriginalName))); var classDeclaration = SyntaxFactory .ClassDeclaration(ClassName) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)) + .AddAttributeLists(attributeList) .WithBaseList(baseList) .WithLeadingTrivia(GenerateXmlDocComment(_xmlComments)); From 8092cea3eddbaf653e7e4fb3d64a447dfed7a9ac Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 22 Aug 2022 13:19:38 +0200 Subject: [PATCH 34/37] Specify OriginalName for task and classes --- .../Service/ScaffoldingService.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index cc1bc8a2..201fe3aa 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -63,7 +63,10 @@ public async Task Scaffold() note = "The autogenerated name has been changed because it is invalid C# member name"; } - var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Workflows", name, TaskModelGenerator.ModelType.Workflow); + var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Workflows", name, TaskModelGenerator.ModelType.Workflow) + { + OriginalName = workflowDefinition.Name + }; string workflowDescription = workflowDefinition.Description; string[] labels; @@ -198,7 +201,11 @@ private void AppendXmlComment(StringBuilder linesBuilder, string tag, string val note = "The autogenerated name has been prepended because it starts with a digit character."; } - var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Tasks", name, TaskModelGenerator.ModelType.Task); + var modelGenerator = new TaskModelGenerator(_config.BaseNamespace + ".Tasks", name, TaskModelGenerator.ModelType.Task) + { + OriginalName = taskDefinition.Name + }; + foreach (var property in taskDefinition.InputKeys) { var inputPropData = new TaskModelGenerator.PropertyData(); From 787b9d27e1b3ad7c48a0e14f665748955ff2161c Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 22 Aug 2022 13:26:53 +0200 Subject: [PATCH 35/37] Add MemberNamePrefix constant --- .../Service/ScaffoldingService.cs | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs index 201fe3aa..36240c95 100644 --- a/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs +++ b/src/ConductorSharp.Toolkit/Service/ScaffoldingService.cs @@ -16,6 +16,9 @@ public class ScaffoldingService : IScaffoldingService private readonly ILogger _logger; private readonly ScaffoldingConfig _config; + // Prefix prepended if member name is invalid + private const string MemberNamePrefix = "A"; + public ScaffoldingService(IMetadataService metadataService, IOptions options, ILogger logger) { _metadataService = metadataService; @@ -58,7 +61,7 @@ public async Task Scaffold() { string name = SnakeCaseUtil.ToPascalCase($"{workflowDefinition.Name}_V{workflowDefinition.Version}").Trim(); string note = null; - if (LangUtils.MakeValidMemberName(name, "A", out name)) + if (LangUtils.MakeValidMemberName(name, MemberNamePrefix, out name)) { note = "The autogenerated name has been changed because it is invalid C# member name"; } @@ -170,33 +173,19 @@ public async Task Scaffold() return (modelGenerator.Build(), name); } - private void AppendClassProperty(StringBuilder linesBuilder, string type, string name) - { - linesBuilder.AppendLine($" [JsonProperty(\"{name}\")]"); - LangUtils.MakeValidMemberName(SnakeCaseUtil.ToPascalCase(name), "A", out var propertyName); - linesBuilder.AppendLine($" public {type} {propertyName} {{ get; set; }}"); - } - private void DefinePropertyParams(TaskModelGenerator.PropertyData propData, string type, string originalName) { - LangUtils.MakeValidMemberName(SnakeCaseUtil.ToPascalCase(originalName), "A", out var propertyName); + LangUtils.MakeValidMemberName(SnakeCaseUtil.ToPascalCase(originalName), MemberNamePrefix, out var propertyName); propData.OriginalName = originalName; propData.Name = propertyName; propData.Type = type; } - private void AppendXmlComment(StringBuilder linesBuilder, string tag, string value) - { - linesBuilder.AppendLine($" /// <{tag}>"); - linesBuilder.AppendLine($" /// {value}"); - linesBuilder.AppendLine($" /// "); - } - public (string contents, string modelClassName) CreateTaskClass(TaskDefinition taskDefinition) { string name = SnakeCaseUtil.ToPascalCase(taskDefinition.Name).Trim(); string note = null; - if (LangUtils.MakeValidMemberName(name, "A", out name)) + if (LangUtils.MakeValidMemberName(name, MemberNamePrefix, out name)) { note = "The autogenerated name has been prepended because it starts with a digit character."; } From 9168268565813d92f7fae8a8b7660a049366e8d2 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 22 Aug 2022 13:37:24 +0200 Subject: [PATCH 36/37] Add readonly modifier, use arrow syntax for some methods --- .../Util/TaskModelGenerator.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index 93de7e7a..530b0196 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -25,10 +25,10 @@ public class PropertyData public string ClassName { get; set; } public string OriginalName { get; set; } - protected CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); + private CompilationUnitSyntax _compilationUnit = SyntaxFactory.CompilationUnit(); private readonly ModelType _modelType; - private List _inputProperties = new(); - private List _outputProperties = new(); + private readonly List _inputProperties = new(); + private readonly List _outputProperties = new(); private readonly Dictionary _xmlComments = new(); public TaskModelGenerator(string @namespace, string className, ModelType modelType) @@ -38,15 +38,9 @@ public TaskModelGenerator(string @namespace, string className, ModelType modelTy _modelType = modelType; } - public void AddInputProperty(PropertyData propData) - { - _inputProperties.Add(propData); - } + public void AddInputProperty(PropertyData propData) => _inputProperties.Add(propData); - public void AddOutputProperty(PropertyData propData) - { - _outputProperties.Add(propData); - } + public void AddOutputProperty(PropertyData propData) => _outputProperties.Add(propData); public void AddXmlComment(string tag, string value) => _xmlComments[tag] = value; @@ -150,7 +144,7 @@ private SyntaxTriviaList GenerateXmlDocComment(Dictionary xmlCom private ClassDeclarationSyntax CreateInputClass() { var typeArgumentList = SyntaxFactory.TypeArgumentList( - SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ParseTypeName($"{ClassName}Output")) + SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ParseTypeName($"{ClassName}Output")) ); var baseType = SyntaxFactory.SimpleBaseType(SyntaxFactory.GenericName("IRequest").WithTypeArgumentList(typeArgumentList)); var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(baseType)); From 18107e87179db815c8854c3a9f43e96f47b05765 Mon Sep 17 00:00:00 2001 From: "bojan.malinic" Date: Mon, 22 Aug 2022 13:39:38 +0200 Subject: [PATCH 37/37] Remove unnecessary newline --- src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs index 530b0196..2e19150c 100644 --- a/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs +++ b/src/ConductorSharp.Toolkit/Util/TaskModelGenerator.cs @@ -69,7 +69,6 @@ private SyntaxTriviaList GenerateAutoGeneratedComment() list = list.Add(SyntaxFactory.Comment("// Changes to this file may cause incorrect behavior and will be lost if")); list = list.Add(SyntaxFactory.Comment("// the code is regenerated.")); list = list.Add(SyntaxFactory.Comment("// ")); - return list; }