Import from internal git

This commit is contained in:
2025-10-11 13:08:09 +02:00
commit 97aaa715dc
175 changed files with 7014 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
using Core;
using Core.Events;
using Core.Interfaces;
using Generator.Services;
namespace Generator.Controllers;
public class AnalyzeController : IController
{
private readonly AnalyzeService _analyzeService;
public DisplayEmitter Emitter { get; set; }
public AnalyzeController(DisplayEmitter emitter, AnalyzeService service)
{
_analyzeService = service;
Emitter = emitter;
}
public string GetSpecText(string folder, string spec) => _analyzeService.GetSpecText(folder, spec);
public bool CanBeGenerated(string folder, string spec)
{
return _analyzeService.CanBeGenerated(folder, spec);
}
public IEnumerable<Location> ListSpecs() => _analyzeService.ListSpecs();
}

View File

@@ -0,0 +1,31 @@
using Core;
using Core.Events;
using Core.Interfaces;
using Generator.Services;
using Generator.views;
namespace Generator.Controllers;
public class ExportController : IController
{
private readonly ExportService _exportService;
public DisplayEmitter Emitter { get; set; }
public ExportController(DisplayEmitter emitter, ExportService service)
{
_exportService = service;
Emitter = emitter;
}
public void PlantUml(ISpecFile file)
{
try
{
_exportService.ExportAsPuml(file);
} catch (Exception e)
{
Emitter.Warn(this, $"{e.Message} \n Cause : {e.Source} \n Full stacktrace : \n {e.StackTrace}");
}
}
}

View File

@@ -0,0 +1,30 @@
using Core.Events;
using Core.Interfaces;
using Core.Process;
using Generator.Services;
namespace Generator.Controllers;
public class GenerationController : IController
{
private readonly GenerationService _genService;
public DisplayEmitter Emitter { get; set; }
public GenerationController(DisplayEmitter emitter, GenerationService service)
{
_genService = service;
Emitter = emitter;
}
public async Task Launch(GenerationProcess process)
{
try
{
foreach (var task in process) await _genService.Launch(task);
}
catch (Exception e)
{
Emitter.Warn(this, $"{e.Message} \n Cause : {e.Source} \n Full stacktrace : \n {e.StackTrace}");
}
}
}

View File

@@ -0,0 +1,37 @@
using Core;
using Core.Events;
using Core.Interfaces;
using Core.Process;
using Core.SpecConfig;
using Generator.Services;
using Generator.views;
namespace Generator.Controllers;
public class PreGenerationController : IController
{
private readonly PreGenerationService _preGenService;
private readonly ConsoleView _view;
public DisplayEmitter Emitter { get; set; }
public PreGenerationController(DisplayEmitter emitter, PreGenerationService preGenService)
{
_view = new ConsoleView();
_preGenService = preGenService;
Emitter = emitter;
}
public GenerationProcess ComputeGeneration(string specPath, GenerationType? generationType, PublishType publishType)
{
try
{
return _preGenService.ComputeGeneration(specPath, generationType, publishType);
}
catch (Exception e)
{
Emitter.Warn(this, e.Message);
throw;
}
}
}

View File

@@ -0,0 +1,33 @@
using Core.Events;
using Core.Interfaces;
using Core.Process;
using Generator.Services;
using Generator.views;
namespace Generator.Controllers;
public class PublicationController : IController
{
private readonly PublicationService _pubService;
public DisplayEmitter Emitter { get; set; }
public PublicationController(DisplayEmitter emitter, PublicationService pubService)
{
_pubService = pubService;
Emitter = emitter;
}
public async Task Publish(GenerationProcess process)
{
try
{
await _pubService.Publish(process);
}
catch (Exception e)
{
Emitter.Warn(this, $"{e.Message} \n Cause : {e.Source} \n Full stacktrace : \n {e.StackTrace}");
}
}
}

View File

@@ -0,0 +1,17 @@
using Generator.DataSource.Settings;
namespace Generator.Daos;
public abstract class AbstractDao
{
protected readonly ConfigManager ConfManager;
protected AbstractDao(ConfigManager confManager, string spec)
{
ConfManager = confManager;
}
protected AbstractDao(ConfigManager confManager) : this(confManager, confManager.GetDefArgs().SpecIdentifier)
{ }
}

View File

@@ -0,0 +1,19 @@
using Core.Actions;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class CredentialsDao : AbstractDao
{
public string Username => ConfManager.Credentials.Username;
public string Password => ConfManager.Credentials.Password;
public CredentialsDao(ConfigManager confManager)
: base(confManager, confManager.GetDefArgs().SpecIdentifier)
{
}
public PackageDeletion GetPackageDeletion() => ConfManager.Credentials.ToPackageDeletion();
}

View File

@@ -0,0 +1,40 @@
using Core;
using Core.Actions;
using Core.Settings;
using Core.SpecConfig;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class DotnetDao : AbstractDao
{
public DotnetDao(ConfigManager confManager)
: base(confManager, confManager.GetDefArgs().SpecIdentifier)
{
}
public DotnetConfig GetDotnetGenerate(GenerationType type, ISpecFile file)
{
var config = ConfManager.Dotnet.Map(ConfManager, file);
config.Type = type;
return config ;
}
public DotnetPublish GetDotnetPublish(GenerationType type, ISpecFile file)
{
var d = GetDotnetGenerate(type, file);
return new DotnetPublish
{
LocalRoot = d.LocalRoot,
DockerRoot = d.DockerRoot,
Image = d.BuildImage,
Registry = d.Registry,
PackageFolder = d.PackageFolderPath(),
PackageVersion = file.Version,
PackageFile = d.PackageFile,
AuthorizationToken = d.AuthorizationToken,
};
}
}

View File

@@ -0,0 +1,14 @@
using Core;
using Generator.DataSource.Settings;
namespace Generator.Daos;
public class EnvironmentDao : AbstractDao
{
public Location ApiFolder() => new ([ConfManager.GetBase().LocalRoot, ConfManager.GetGeneral().ApiFolder]);
public string Invite => ConfManager.GetBase().Invite;
public EnvironmentDao(ConfigManager confManager) : base(confManager)
{ }
}

37
Generator/Daos/JavaDao.cs Normal file
View File

@@ -0,0 +1,37 @@
using Core;
using Core.Actions;
using Core.Settings;
using Core.SpecConfig;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class JavaDao : AbstractDao
{
public JavaDao(ConfigManager confManager) : base(confManager)
{ }
public JavaConfig GetJavaGenerate(ISpecFile file) => ConfManager.Java.Map(ConfManager, file);
public JavaPublish GetJavaPublish(GenerationType type, ISpecFile file)
{
var config = GetJavaGenerate(file);
return new JavaPublish
{
LocalRoot = config.LocalRoot,
DockerRoot = config.DockerRoot,
Image = config.BuildImage,
Registry = config.Registry,
TemplateFolder = config.TemplateFolder,
OutputFolder = config.OutputFolder(),
Group = file.MavenGroup,
Artifact = config.Artifact,
Version = config.Version,
Username = config.Username,
Password = config.Password,
};
}
}

View File

@@ -0,0 +1,35 @@
using Core;
using Core.Actions;
using Core.Settings;
using Core.SpecConfig;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class JavascriptDao : AbstractDao
{
public JavascriptDao(ConfigManager confManager) : base(confManager, confManager.GetDefArgs().SpecIdentifier)
{ }
public JavascriptConfig GetJavascript(ISpecFile file) => ConfManager.Javascript.Map(ConfManager, file);
public JavascriptPublish GetJavascriptPublish(GenerationType type, ISpecFile file)
{
var j = GetJavascript(file);
return new JavascriptPublish
{
LocalRoot = j.LocalRoot,
DockerRoot = j.DockerRoot,
Image = j.BuildImage,
Registry = j.Registry,
PackageName = j.PackageName,
Version = file.Version,
SpecFile = j.OpenApiSpecFile(),
FrontFolder = j.OutputFolder(),
};
}
}

View File

@@ -0,0 +1,23 @@
using Core;
using Core.Settings;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class OpenApiDao : AbstractDao
{
public OpenApiDao(ConfigManager confManager) : base(confManager)
{ }
public Location ConfigOf(string spec) => GetOpenApi(true, spec).SpecConfig;
public OpenApiConfig GetOpenApi(bool isLocal, string file)
{
var items = file.Split("/");
var o = ConfManager.OpenApi.Map(ConfManager, items[0], items[1]);
o.AddRoot(ConfManager.GetRoot(isLocal));
return o;
}
}

View File

@@ -0,0 +1,23 @@
using Core;
using Core.Actions;
using Generator.DataSource.Settings;
using Generator.Mappers;
namespace Generator.Daos;
public class TemplateDao : AbstractDao
{
public TemplateDao(ConfigManager confManager) : base(confManager)
{ }
public PlantUmlExport PlantUml(ISpecFile file)
{
var config = ConfManager.Templates.Map();
return new PlantUmlExport
{
LocalRoot = ConfManager.GetBase().LocalRoot,
Template = config.PlantUml,
Output = ConfManager.GetGeneral().ApiFolder.ConcatenateWith([file.Folder, $"{file.Name}.puml"])
};
}
}

View File

@@ -0,0 +1,46 @@
using Core.Dto.Settings;
using Core.Interfaces;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Generator.DataSource;
/// <summary>
/// Provides some methods to load json objects from a json data source
/// </summary>
public class JsonLoader : IDataSourceLoader
{
private readonly IServiceCollection _services;
private readonly IConfiguration _configuration;
public JsonLoader(IServiceCollection services, IConfiguration configuration)
{
_services = services;
_configuration = configuration;
}
/// <summary>
/// Load data that can be found in appsettings.json
/// </summary>
public void LoadAppsettings()
{
_services.AddOptions<EnvironmentConfigDto>().Bind(_configuration.GetSection("Environment"));
_services.AddOptions<DefaultArgumentsConfigDto>().Bind(_configuration.GetSection("DefaultArguments"));
_services.AddOptions<GeneralConfigDto>().Bind(_configuration.GetSection("General"));
_services.AddOptions<PublishConfigDto>().Bind(_configuration.GetSection("Publish"));
_services.AddOptions<CredentialsConfigDto>().Bind(_configuration.GetSection("Credentials"));
_services.AddOptions<DockerImagesConfigDto>().Bind(_configuration.GetSection("DockerImages"));
_services.AddOptions<JavaConfigDto>().Bind(_configuration.GetSection("Java"));
_services.AddOptions<DotnetConfigDto>().Bind(_configuration.GetSection("Dotnet"));
_services.AddOptions<JavascriptConfigDto>().Bind(_configuration.GetSection("Javascript"));
_services.AddOptions<OpenApiConfigDto>().Bind(_configuration.GetSection("OpenApi"));
_services.AddOptions<TemplatesConfigDto>().Bind(_configuration.GetSection("Templates"));
}
}

View File

@@ -0,0 +1,64 @@
using Core;
using Core.Dto;
using Core.Dto.Settings;
using Core.Settings;
using Generator.Mappers;
using Microsoft.Extensions.Options;
namespace Generator.DataSource.Settings;
/// <summary>
/// This class is intended to encapsulate configurations objects
/// </summary>
public class ConfigManager
{
private readonly ArgumentsDto _args;
private readonly EnvironmentConfigDto _env;
private readonly DefaultArgumentsConfigDto _defArgs;
private readonly GeneralConfigDto _general;
public readonly DockerImagesConfigDto DockerImages;
public readonly TemplatesConfigDto Templates;
public readonly PublishConfigDto Publish;
public readonly CredentialsConfigDto Credentials;
public readonly DotnetConfigDto Dotnet;
public readonly JavaConfigDto Java;
public readonly JavascriptConfigDto Javascript;
public readonly OpenApiConfigDto OpenApi;
public ConfigManager(
ArgumentsDto args,
IOptions<EnvironmentConfigDto> env,
IOptions<DefaultArgumentsConfigDto> defArgs,
IOptions<GeneralConfigDto> general,
IOptions<PublishConfigDto> publish,
IOptions<CredentialsConfigDto> creds,
IOptions<DockerImagesConfigDto> images,
IOptions<DotnetConfigDto> dotnet,
IOptions<JavaConfigDto> java,
IOptions<JavascriptConfigDto> javascript,
IOptions<OpenApiConfigDto> openapi,
IOptions<TemplatesConfigDto> templates)
{
_args = args;
_env = env.Value;
Publish = publish.Value;
Credentials = creds.Value;
_defArgs = defArgs.Value;
_general = general.Value;
DockerImages = images.Value;
Templates = templates.Value;
Dotnet = dotnet.Value;
Java = java.Value;
Javascript = javascript.Value;
OpenApi = openapi.Value;
}
public BaseConfig GetBase() => _env.Map();
public DefaultArgumentsConfig GetDefArgs() => _defArgs.Map(_args);
public GeneralConfig GetGeneral() => _general.Map();
public Location GetRoot(bool isLocal) => isLocal ? GetBase().LocalRoot : GetBase().DockerRoot;
}

View File

@@ -0,0 +1,109 @@
using System.Text.RegularExpressions;
using Core;
using Core.Dto.Yaml;
using Core.Exceptions;
using Core.Helpers;
using Core.Yaml;
using Generator.Mappers;
using Newtonsoft.Json;
using YamlDotNet.Serialization;
namespace Generator.DataSource.Yaml;
public class OpenApiYamlExtractor
{
/// <summary>
/// Retrieves an openapi-formatted yaml at a specific location
/// </summary>
/// <param name="path">file location</param>
/// <returns></returns>
public OpenApiYaml ExtractNode(string path)
{
var text = PathHelper.TextFrom(path);
var deserializer = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
var dto = deserializer.Deserialize<OpenApiYamlDto>(text);
return dto.ToModel(path);
}
/// <summary>
/// Loads all configs that can be found in the config file located at the given path
/// </summary>
/// <param name="configPath">Given path</param>
/// <returns></returns>
/// <exception cref="InvalidOperationException">When config file couldn't has been deserialize</exception>
/// <exception cref="ConfigException">When the given path does not exists</exception>
public Dictionary<string, YamlConfig> LoadConfigs(string configPath)
{
try
{
var json = PathHelper.TextFrom(configPath);
var configDto = JsonConvert.DeserializeObject<SpecConfigDto>(json);
return (configDto ?? throw new InvalidOperationException()).Map();
}
catch (FileNotFoundException)
{
throw new ConfigException($"No config file found at {configPath}. Fix it or i'll never generate anything for you");
}
}
/// <summary>
/// Extract all scoped references of a specification file. In other words, this will extracts all references
/// between the given spec file and the closer reference-related schemas, including paths and params files
/// </summary>
/// <param name="filePath">Given file path</param>
/// <returns></returns>
public ISet<string> ExtractScopedRefs(string filePath) => ExtractRefs(filePath, false, new HashSet<string>());
/// <summary>
/// Extract all possibles references from a given specification file
/// </summary>
/// <param name="filePath">Given file path</param>
/// <returns></returns>
public ISet<string> ExtractAllRefs(string filePath) => ExtractRefs(filePath, true, new HashSet<string>());
private ISet<string> ExtractRefs(string filePath, bool deepSearch, ISet<string> refs)
{
const string pattern = """(\$ref):\s{1}['|"](.+)['|"]""";
var text = PathHelper.TextFrom(filePath);
var matches = Regex.Matches(text, pattern);
foreach (Match m in matches)
{
var rawReference = m.Groups[2].Value;
var absolutePath = AbsolutePathFromRef(filePath, rawReference);
//If path references itself or circular dependency is detected
if (absolutePath == string.Empty || refs.Contains(absolutePath)) continue;
if (!deepSearch && IsSchema(absolutePath))
{
refs.Add(absolutePath);
continue;
}
var subRefs = ExtractRefs(absolutePath, deepSearch, refs);
refs.UnionWith(subRefs);
refs.Add(absolutePath);
}
return refs;
}
private string AbsolutePathFromRef(string relative, string reference)
{
var result = PathHelper.GetFolder(relative) + reference;
var r = result.Split("#")[0];
return r[^1].Equals('/') ? string.Empty : PathHelper.AbsolutePath(r);
}
private bool IsSchema(string path)
{
var l = new Location(path);
return l.LastElement().Contains("schemas");
}
}

View File

@@ -0,0 +1,164 @@
using System.Text;
using Core;
using Core.Helpers;
using Core.Yaml;
using MoreLinq;
namespace Generator.DataSource.Yaml;
public class YamlBuilder
{
private OpenApiYaml _file;
private bool _isSubNode;
private readonly string _configIdentifier;
private readonly Dictionary<string, YamlConfig> _configs;
private readonly OpenApiYamlExtractor _extractor;
public YamlBuilder(string filePath, string configIdentifier)
{
_isSubNode = false;
_configIdentifier = configIdentifier;
_file = new OpenApiYaml(filePath);
_configs = new Dictionary<string, YamlConfig>();
_extractor = new OpenApiYamlExtractor();
}
/// <summary>
/// Adds all raw references to the object to build
/// </summary>
public void AddReferences()
{
var scopedRefs = _extractor.ExtractScopedRefs(_file.Location.ToString());
var allRefs = _extractor.ExtractAllRefs(_file.Location.ToString());
_file.ScopedRefs = scopedRefs;
_file.OutScopedRefs = allRefs;
_file.OutScopedRefs.ExceptWith(scopedRefs);
}
/// <summary>
/// Attributes the dedicated config file to the object to build
/// </summary>
public void SelectConfig()
{
if (_configs.ContainsKey(_file.Location.GetFileName()))
{
_file.Config = _configs[_file.Location.GetFileName()];
}
else
{
throw new Exception($"{_file.Location} cannot be generated. You either made a typo " +
$"or forgot to register file in {GetConfig(_file.Location)}");
}
}
/// <summary>
/// Adds all built schemas to the object to build
/// </summary>
public void AddSchema()
{
using var enumerator = _file.ScopedRefs.GetEnumerator();
while (enumerator.MoveNext())
{
var loc = new Location(enumerator.Current);
var fileName = loc.GetFileName();
if(!_configs.ContainsKey(fileName)) continue;
var schema = _isSubNode ?
_extractor.ExtractNode(loc.ToString())
: CreateSubNode(loc.ToString());
schema.Config = _configs[fileName];
_file.ReferencedSchemas.Add(schema);
}
}
/// <summary>
/// Adds the models that will be ignored to the object to build
/// </summary>
public void AddIgnoredModels()
{
foreach (var reference in _file.Refs)
{
var loc = new Location(reference);
var schema = _extractor.ExtractNode(loc.ToString());
_file.IgnoredModels.UnionWith(schema.Models);
}
}
/// <summary>
/// Simply output the object to build
/// </summary>
/// <returns></returns>
public OpenApiYaml Create() => _file;
/// <summary>
/// Loads the object to build
/// </summary>
public void LoadSpec()
{
_file = _extractor.ExtractNode(_file.Location.ToString());
_file.Openapi = _file.Openapi;
if (_file.Info != null) _file.Info = new Dictionary<string, object>(_file.Info);
_file.Tags = _file.Tags == null ? new List<object>() : [.._file.Tags];
}
/// <summary>
/// Load all the found config files into the builder
/// </summary>
public void LoadConfigs()
{
LoadConfig(_file.Location);
foreach (var reference in _file.Refs) LoadConfig(new Location(reference));
}
private void LoadConfig(Location path)
{
var configPath = GetConfig(path)?.ToString();
if (configPath == null || _configs.ContainsKey(path.GetFileName())) return;
_extractor.LoadConfigs(configPath)
.ForEach(c => _configs.TryAdd(c.Key, c.Value));
}
private void SetForSubNode() => _isSubNode = true;
private OpenApiYaml CreateSubNode(string path)
{
var yamlBuilder = new YamlBuilder(path, _configIdentifier);
yamlBuilder.SetForSubNode();
yamlBuilder.LoadSpec();
yamlBuilder.AddReferences();
yamlBuilder.LoadConfigs();
yamlBuilder.AddSchema();
yamlBuilder.AddIgnoredModels();
return yamlBuilder.Create();
}
private Location? GetConfig(Location loc)
{
var spec = loc.GetFolder();
var pathItems = loc.Path.Split(['/', '\\']);
pathItems[^1] = spec + _configIdentifier;
var builder = new StringBuilder();
builder.AppendJoin("/", pathItems);
var configPath = builder.ToString();
try
{
PathHelper.CheckPathValidity(configPath);
}
catch (FileNotFoundException)
{
return null;
}
return new Location(configPath);
}
}

View File

@@ -0,0 +1,36 @@
using Core;
using Core.Yaml;
using Generator.Daos;
namespace Generator.DataSource.Yaml;
public class YamlDirector
{
private readonly OpenApiDao _openApiDao;
public YamlDirector(OpenApiDao openApiDao)
{
_openApiDao = openApiDao;
}
/// <summary>
/// Build a yaml object lmao what do you want me to say ? All the information's are in the method signature
/// </summary>
/// <param name="specPath"></param>
/// <returns></returns>
public OpenApiYaml BuildYaml(string specPath)
{
var openApiConfig = _openApiDao.GetOpenApi(true, specPath);
var yamlBuilder = new YamlBuilder(openApiConfig.SpecFile.ToString(), openApiConfig.ConfigIdentifier);
yamlBuilder.LoadSpec();
yamlBuilder.AddReferences();
yamlBuilder.LoadConfigs();
yamlBuilder.SelectConfig();
yamlBuilder.AddSchema();
yamlBuilder.AddIgnoredModels();
return yamlBuilder.Create();
}
}

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Generator</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.13" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.13" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="mustache-sharp" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="Services.Common" Version="1.0.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,89 @@
using Core;
using Core.Dto;
using Core.Events;
using Generator.Controllers;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Generator;
public class GeneratorHostedService : IHostedService
{
private readonly ArgumentsDto _args;
private readonly IHostApplicationLifetime _applicationLifetime;
private readonly ILogger<GeneratorHostedService> _logger;
private readonly PreGenerationController _preGenController;
private readonly GenerationController _genController;
private readonly ExportController _exportController;
public GeneratorHostedService(
ArgumentsDto args,
IHostApplicationLifetime applicationLifetime,
ILogger<GeneratorHostedService> logger,
PreGenerationController preGenController,
GenerationController genController,
ExportController exportController)
{
_args = args;
_applicationLifetime = applicationLifetime;
_logger = logger;
_preGenController = preGenController;
_genController = genController;
_exportController = exportController;
_genController.Emitter.OnSay += Display;
_genController.Emitter.OnWarn += Warn;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_applicationLifetime.ApplicationStarted.Register(() =>
{
Task.Run(async() =>
{
var startTime = DateTime.Now;
try
{
var extractor = new ArgumentsExtractor(_args);
var genProcess = _preGenController.ComputeGeneration(extractor.Spec, extractor.GenType, extractor.PublishType);
if (extractor.ExportPuml) _exportController.PlantUml(genProcess.BaseFile);
await _genController.Launch(genProcess);
}
catch (Exception e)
{
_logger.Log(LogLevel.Critical, e, $"A critical exception was thrown. {e.Message}");
}
finally
{
var endTime = DateTime.Now;
Console.WriteLine($"Process started at : {startTime}");
Console.WriteLine($"Process ended at : {endTime}");
Console.WriteLine($"Duration : {(endTime - startTime).Duration():mm':'ss}");
_applicationLifetime.StopApplication();
}
}, cancellationToken);
});
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private void Display(object? sender, DisplayEventArgs args)
{
Console.WriteLine(args.Content);
}
private void Warn(object? sender, DisplayEventArgs args)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(args.Content);
Console.ResetColor();
}
}

View File

@@ -0,0 +1,91 @@
using System.Diagnostics;
using Core.Events;
using Core.Exceptions;
namespace Generator.Infrastructure;
public class CommandExecutor
{
private readonly Queue<string> _commands;
private string _invite;
private DisplayEmitter _emitter;
public CommandExecutor(string invite, DisplayEmitter emitter)
{
_commands = new Queue<string>();
_invite = invite;
_emitter = emitter;
}
/// <summary>
/// Runs a single asynchronous command
/// </summary>
/// <param name="command">Command to run</param>
/// <exception cref="CommandExecutionException">When the command hasn't been terminated successfully</exception>
public async Task RunAsync(string command)
{
await Task.Run(() =>
{
using var process = new Process();
process.StartInfo = new ProcessStartInfo
{
FileName = _invite,
Arguments = $"{command}",
RedirectStandardOutput = true,
RedirectStandardError = true,
WindowStyle = ProcessWindowStyle.Normal
};
process.Start();
ReadOutput(process);
ReadError(process);
process.WaitForExit();
if(process.ExitCode == 1)
throw new CommandExecutionException($"The following task has failed : \n '{command}'");
});
}
private void ReadError(Process process)
{
Task.Run(async () =>
{
using var output = process.StandardError;
while (!output.EndOfStream)
{
var line = await output.ReadLineAsync();
_emitter.Warn(this, line);
}
});
}
private void ReadOutput(Process process)
{
Task.Run(async () =>
{
using var output = process.StandardOutput;
while (!output.EndOfStream)
{
var line = await output.ReadLineAsync();
_emitter.Say(this, line);
}
});
}
/// <summary>
/// Registers a command to execute later
/// </summary>
/// <param name="command"></param>
public void Register(string command) => _commands.Enqueue(command);
/// <summary>
/// Runs all previously registered command
/// </summary>
public async Task RunRegistered()
{
while (_commands.TryDequeue(out var c))
{
await RunAsync(c);
}
}
}

View File

@@ -0,0 +1,60 @@
using Core;
using Core.Actions;
using Core.Helpers;
using Core.Templates;
using Core.Yaml;
using Generator.Infrastructure.TemplateFiller;
namespace Generator.Infrastructure.Export;
/// <summary>
/// Provides multiple methods to specification references
/// </summary>
public class Exporter
{
private readonly ITemplateFactory _templateFactory;
public Exporter(ITemplateFactory factory)
{
_templateFactory = factory;
}
/// <summary>
/// Export file references as plant uml diagram
/// </summary>
/// <param name="export">plantuml data needed for exportation</param>
/// <param name="file">File to export</param>
public void PlantUml(PlantUmlExport export, ISpecFile file)
{
var yaml = TypeHelper.SafeCast<ISpecFile, OpenApiYaml>(file);
var input = export.LocalRoot.ConcatenateWith(export.Template);
var output = export.LocalRoot.ConcatenateWith(export.Output);
var references = new List<(string Package, string Reference)>();
var schemas = yaml.ReferencedSchemas.ToList();
for (var i = -1; i < schemas.Count; i++)
{
var baseFile = i == -1 ? yaml : schemas[i];
if(!baseFile.Location.IsInSameFolder(yaml.Location)) continue;
foreach (var reference in baseFile.ReferencedSchemas)
{
references.Add((baseFile.NugetPackage, reference.NugetPackage));
}
}
var data = new Dictionary<string, object>()
{
{"specName", file.Folder},
{"packages", references.Select(t => t.Package).ToHashSet()},
{"references", references}
};
var template = _templateFactory.GetTemplate(input.ToString(), data);
var f = new MustacheFiller(template);
f.Fill();
f.Write(output.ToString());
}
}

View File

@@ -0,0 +1,64 @@
using Core;
using Core.Events;
using Core.Helpers;
using Core.Templates;
using Generator.Infrastructure.TemplateFiller;
using Microsoft.OpenApi.Exceptions;
namespace Generator.Infrastructure.OpenApi.Builders;
/// <summary>
/// Provides base behavior for generation purpose
/// </summary>
/// <typeparam name="TFile">Derived type from ISpecFile</typeparam>
public abstract class AbstractBuilder<TFile> where TFile : ISpecFile
{
private readonly ITemplateFactory _templateFactory;
protected readonly CommandExecutor Executor;
protected TFile? SpecFile;
public AbstractBuilder(string invite, DisplayEmitter emitter)
{
Executor = new CommandExecutor(invite, emitter);
_templateFactory = new MustacheTemplateFactory();
SpecFile = default;
}
/// <summary>
/// Registers file used for generation
/// </summary>
/// <param name="specFile"></param>
public void Load(TFile specFile) => SpecFile = TypeHelper.SafeCast<ISpecFile, TFile>(specFile);
/// <summary>
/// Launches generation
/// </summary>
public async Task ExecuteAllAsync() => await Executor.RunRegistered();
/// <summary>
/// Registers generation process
/// </summary>
public abstract void Generate();
/// <summary>
/// Registers build process
/// </summary>
public abstract void Build();
/// <summary>
/// Check if the spec file has been loaded
/// </summary>
/// <exception cref="OpenApiException"></exception>
protected void CheckForNullSpec()
{
if (SpecFile == null) throw new OpenApiException("Spec file hasn't been loaded yet.");
}
protected void MakeTemplate(string inputPath, string outputPath, IDictionary<string, object> data)
{
var template = _templateFactory.GetTemplate(inputPath, data);
var f = new MustacheFiller(template);
f.Fill();
f.Write(outputPath);
}
}

View File

@@ -0,0 +1,118 @@
using System.Text;
using Core;
using Core.Events;
using Core.Helpers;
using Core.Settings;
using Core.Yaml;
using YamlDotNet.Core;
namespace Generator.Infrastructure.OpenApi.Builders;
public class OpenApiDotnetClientBuilder : AbstractBuilder<OpenApiYaml>
{
private readonly DotnetConfig _config;
public OpenApiDotnetClientBuilder(DotnetConfig config, DisplayEmitter emitter)
: base(config.Invite, emitter)
{
_config = config;
}
///<inheritdoc/>
public override void Generate()
{
CheckForNullSpec();
CreateIgnore();
GenerateOpenApi();
var inputFile = new Location([_config.DockerRoot, _config.OpenApiConfigFile()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} batch --clean {inputFile}";
Executor.Register(command);
}
///<inheritdoc/>
public override void Build()
{
CheckForNullSpec();
var templateFolder = new Location([_config.DockerRoot, _config.TemplateFolder]);
var packageFolder = new Location([_config.DockerRoot, _config.PackageFolderPath()]);
var stringBuilder = new StringBuilder();
stringBuilder
.Append($"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.BuildImage} /bin/sh -c '")
.Append($"cp {templateFolder}/NuGet.config {packageFolder} && ")
.Append($"cd {packageFolder} && ")
.Append($"dotnet pack -c Release -o out -p:PackageVersion={SpecFile.Version}'");
var command = stringBuilder.ToString();
Executor.Register(command);
}
/// <summary>
/// Creates config file used by openapi generator
/// </summary>
public void CreateGeneratorConfig()
{
CheckForNullSpec();
var inputPath = new Location([_config.LocalRoot, _config.ClientConfigTemplate]);
var outputPath = new Location([_config.LocalRoot, _config.ConfigFilePath()]);
PathHelper.CreateFileIfNotExists(outputPath.ToString());
var data = new Dictionary<string, object>
{
{"specPath", new Location([_config.DockerRoot, _config.OpenApiSpecFile()]).ToString()},
{"templateFolder", new Location([_config.DockerRoot, _config.TemplateFolder]).ToString()},
{"generatorVersion", "7.3.0"},
{"outputFolder", new Location([_config.DockerRoot, _config.OutputFolder()]).ToString()},
{"removeModelPackage", false},
{"modelSuffix", SpecFile.Config.ModelSuffix},
{"packageName", SpecFile.Config.NugetPackage},
{"packageVersion", SpecFile.Info["version"]},
{"refs", SpecFile.ReferencedSchemas},
{"modelNameSpace", SpecFile.ReferencedSchemas},
};
MakeTemplate(inputPath.ToString(), outputPath.ToString(), data);
}
/// <summary>
/// Registers the generation of the openapi spec file
/// </summary>
private void GenerateOpenApi()
{
CheckForNullSpec();
var specFile = new Location([_config.DockerRoot, _config.SpecFile]);
var output = new Location([_config.DockerRoot, _config.OpenApiFolder()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} " +
$"generate -g openapi-yaml -i {specFile} -o {output}";
Executor.Register(command);
}
/// <summary>
/// Generates the ignore file used by openapi generator
/// </summary>
private void CreateIgnore()
{
CheckForNullSpec();
var inputPath = new Location([_config.LocalRoot, _config.ClientIgnoreTemplate]).ToString();
var outputPath = new Location([_config.LocalRoot, _config.IgnoreFilePath()]).ToString();
PathHelper.CreateFileIfNotExists(outputPath);
var data = new Dictionary<string, object>
{
{"modelSuffix", SpecFile!.Config.ModelSuffix},
{"keepModels", SpecFile.Config.KeepModels},
};
MakeTemplate(inputPath, outputPath, data);
}
}

View File

@@ -0,0 +1,121 @@
using System.Text;
using Core;
using Core.Events;
using Core.Helpers;
using Core.Settings;
using Core.SpecConfig;
using Core.Yaml;
namespace Generator.Infrastructure.OpenApi.Builders;
public class OpenApiDotnetServerBuilder : AbstractBuilder<OpenApiYaml>
{
private readonly DotnetConfig _config;
public OpenApiDotnetServerBuilder(DotnetConfig config, DisplayEmitter emitter)
: base(config.Invite, emitter)
{
_config = config;
}
///<inheritdoc/>
public override void Generate()
{
CheckForNullSpec();
CreateIgnore();
GenerateOpenApi();
var inputFile = new Location([_config.DockerRoot, _config.OpenApiConfigFile()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} " +
$"{_config.GenerationImage} batch --clean {inputFile}";
Executor.Register(command);
}
///<inheritdoc/>
public override void Build()
{
CheckForNullSpec();
var templateFolder = new Location([_config.DockerRoot, _config.TemplateFolder]);
var packageFolder = new Location([_config.DockerRoot, _config.PackageFolderPath()]);
var stringBuilder = new StringBuilder();
stringBuilder
.Append($"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.BuildImage} /bin/sh -c '")
.Append($"cp {templateFolder}/NuGet.config {packageFolder} && ")
.Append($"cd {packageFolder} && ")
.Append($"dotnet pack -c Release -o out -p:PackageVersion={SpecFile.Version}'");
var command = stringBuilder.ToString();
Executor.Register(command);
}
/// <summary>
/// Creates config file used by openapi generator
/// </summary>
public void CreateGeneratorConfig()
{
CheckForNullSpec();
var inputPath = new Location([_config.LocalRoot, _config.ServerConfigTemplate]);
var outputPath = new Location([_config.LocalRoot, _config.ConfigFilePath()]);
PathHelper.CreateFileIfNotExists(outputPath.ToString());
var templateData = new Dictionary<string, object>
{
{"specPath", new Location([_config.DockerRoot, _config.OpenApiSpecFile()]).ToString()},
{"templateFolder", new Location([_config.DockerRoot, _config.TemplateFolder]).ToString()},
{"generatorVersion", "7.3.0"},
{"outputFolder", new Location([_config.DockerRoot, _config.OutputFolder()]).ToString()},
{"modelSuffix", SpecFile.Config.ModelSuffix},
{"aspnetCoreVersion", "3.1"},
{"packageName", SpecFile.Config.NugetPackage},
{"packageVersion", SpecFile.Info!["version"]},
{"refs", SpecFile.ReferencedSchemas},
{"modelNameSpace", SpecFile.ReferencedSchemas},
};
MakeTemplate(inputPath.ToString(), outputPath.ToString(), templateData);
}
/// <summary>
/// Registers the generation of the openapi spec file
/// </summary>
private void GenerateOpenApi()
{
CheckForNullSpec();
var specFile = new Location([_config.DockerRoot, _config.SpecFile]);
var output = new Location([_config.DockerRoot, _config.OpenApiFolder()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} " +
$"generate -g openapi-yaml -i {specFile} -o {output}";
Executor.Register(command);
}
/// <summary>
/// Generates the ignore file used by openapi generator
/// </summary>
private void CreateIgnore()
{
CheckForNullSpec();
var inputPath = new Location([_config.LocalRoot, _config.ServerIgnoreTemplate]).ToString();
var outputPath = new Location([_config.LocalRoot, _config.IgnoreFilePath()]).ToString();
PathHelper.CreateFileIfNotExists(outputPath);
var data = new Dictionary<string, object>
{
{"modelSuffix", SpecFile!.Config.ModelSuffix},
{"keepModels", SpecFile.Config.KeepModels},
{"ignoredModels", SpecFile.IgnoredModels},
{"isCommon", SpecFile.SpecType == SpecType.Model}
};
MakeTemplate(inputPath, outputPath, data);
}
}

View File

@@ -0,0 +1,98 @@
using System.Text;
using Core;
using Core.Events;
using Core.Helpers;
using Core.Settings;
using Core.Yaml;
namespace Generator.Infrastructure.OpenApi.Builders;
public class OpenApiJavaBuilder : AbstractBuilder<OpenApiYaml>
{
private readonly JavaConfig _config;
public OpenApiJavaBuilder(JavaConfig config, DisplayEmitter emitter)
: base(config.Invite, emitter)
{
_config = config;
}
///<inheritdoc/>
public override void Generate()
{
CheckForNullSpec();
GenerateOpenApi();
var configFile = new Location([_config.DockerRoot, _config.ConfigFilePath()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} " +
$"batch --clean {configFile}";
Executor.Register(command);
}
///<inheritdoc/>
public override void Build()
{
CheckForNullSpec();
var templateFolder = new Location([_config.DockerRoot, _config.TemplateFolder]);
var outputFolder = new Location([_config.DockerRoot, _config.OutputFolder()]);
var stringBuilder = new StringBuilder();
stringBuilder.Append($"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.BuildImage} /bin/sh -c '");
stringBuilder.Append($"cp {templateFolder}/settings.xml /root/.m2 && ");
stringBuilder.Append($"cd {outputFolder} && ");
stringBuilder.Append("mvn package'");
var command = stringBuilder.ToString();
Executor.Register(command);
}
/// <summary>
/// Creates config file used by openapi generator
/// </summary>
public void CreateGeneratorConfig()
{
CheckForNullSpec();
var inputPath = new Location([_config.LocalRoot, _config.ServerConfigTemplate]);
var outputPath = new Location([_config.LocalRoot, _config.ConfigFilePath()]);
PathHelper.CreateFileIfNotExists(outputPath.ToString());
var artifact = $"{SpecFile.Name}-api";
var data = new Dictionary<string, object>
{
{"specPath", new Location([_config.DockerRoot, _config.OpenApiSpecFile()]).ToString()},
{"templateFolder", new Location([_config.DockerRoot, _config.TemplateFolder]).ToString()},
{"generatorVersion", "7.3.0"},
{"outputFolder", new Location([_config.DockerRoot, _config.OutputFolder()]).ToString()},
{"groupId", SpecFile.Config.JavaGroup},
{"artifactId", artifact},
{"artifactVersion", SpecFile.Info["version"]},
};
MakeTemplate(inputPath.ToString(), outputPath.ToString(), data);
}
/// <summary>
/// Registers the generation of the openapi spec file
/// </summary>
private void GenerateOpenApi()
{
CheckForNullSpec();
var specFile = new Location([_config.DockerRoot, _config.SpecFile]);
var output = new Location([_config.DockerRoot, _config.OpenApiFolder()]);
PathHelper.CreateFileIfNotExists(output.ToString());
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} " +
$"generate -g openapi-yaml -i {specFile} -o {output}";
Executor.Register(command);
}
}

View File

@@ -0,0 +1,63 @@
using System.Text;
using Core;
using Core.Events;
using Core.Settings;
using Core.Yaml;
namespace Generator.Infrastructure.OpenApi.Builders;
public class OpenApiJavascriptBuilder : AbstractBuilder<OpenApiYaml>
{
private readonly JavascriptConfig _config;
public OpenApiJavascriptBuilder(JavascriptConfig config, DisplayEmitter emitter)
: base(config.Invite, emitter)
{
_config = config;
}
///<inheritdoc/>
public override void Generate()
{
CheckForNullSpec();
GenerateOpenApi();
var outputFolder = new Location([_config.DockerRoot, _config.ClientFolder]);
var specFile = new Location([_config.DockerRoot, _config.OpenApiSpecFile()]).ToString();
var stringBuilder = new StringBuilder();
stringBuilder
.Append($"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.BuildImage} /bin/sh -c '")
.Append($"npm run prepare-workspace -- --apiName={_config.PackageName} --apiVersion={_config.OpenApiVersion} ")
.Append($"--apiFile={specFile} --registry={_config.Registry} && ")
.Append("npm run package && ")
.Append($"mkdir -p {outputFolder} && ")
.Append($"cp -r dist/* {outputFolder}'");
var command = stringBuilder.ToString();
Executor.Register(command);
}
///<inheritdoc/>
public override void Build()
=> throw new InvalidOperationException("Why the heck do you want to compile javascript code ?");
/// <summary>
/// Registers the generation of the openapi spec file
/// </summary>
private void GenerateOpenApi()
{
CheckForNullSpec();
var specFile = new Location([_config.DockerRoot, _config.SpecFile]);
var output = new Location([_config.DockerRoot, _config.OpenApiFolder()]);
var command = $"docker run --rm -it -v {_config.LocalRoot}:{_config.DockerRoot} {_config.GenerationImage} " +
$"generate -g openapi-yaml -i {specFile} -o {output}";
Executor.Register(command);
}
}

View File

@@ -0,0 +1,76 @@
using Core.Events;
using Core.Interfaces;
using Core.Settings;
using Core.Yaml;
using Generator.Infrastructure.OpenApi.Builders;
namespace Generator.Infrastructure.OpenApi;
public class OpenApiDirector : IGeneratorDirector<OpenApiYaml>
{
private DisplayEmitter _emitter;
public OpenApiDirector(DisplayEmitter emitter)
{
_emitter = emitter;
}
/// <summary>
/// Launches dotnet server generation
/// </summary>
/// <param name="file"></param>
/// <param name="config"></param>
public async Task DotnetServer(OpenApiYaml file, DotnetConfig config)
{
var dotnetServerBuilder = new OpenApiDotnetServerBuilder(config, _emitter);
dotnetServerBuilder.Load(file);
dotnetServerBuilder.CreateGeneratorConfig();
dotnetServerBuilder.Generate();
dotnetServerBuilder.Build();
await dotnetServerBuilder.ExecuteAllAsync();
}
/// <summary>
/// Launches dotnet client generation
/// </summary>
/// <param name="file"></param>
/// <param name="config"></param>
public async Task DotnetClient(OpenApiYaml file, DotnetConfig config)
{
var dotnetClientBuilder = new OpenApiDotnetClientBuilder(config, _emitter);
dotnetClientBuilder.Load(file);
dotnetClientBuilder.CreateGeneratorConfig();
dotnetClientBuilder.Generate();
dotnetClientBuilder.Build();
await dotnetClientBuilder.ExecuteAllAsync();
}
/// <summary>
/// Launches java generation
/// </summary>
/// <param name="file"></param>
/// <param name="config"></param>
public async Task Java(OpenApiYaml file, JavaConfig config)
{
var javaBuilder = new OpenApiJavaBuilder(config, _emitter);
javaBuilder.Load(file);
javaBuilder.CreateGeneratorConfig();
javaBuilder.Generate();
javaBuilder.Build();
await javaBuilder.ExecuteAllAsync();
}
/// <summary>
/// Launches javascript generation
/// </summary>
/// <param name="file"></param>
/// <param name="config"></param>
public async Task Javascript(OpenApiYaml file, JavascriptConfig config)
{
_emitter.Warn(this, "Javascript generation is temporally disabled");
/*var jsBuilder = new OpenApiJavascriptBuilder(config, _emitter);
jsBuilder.Load(file);
jsBuilder.Generate();
await jsBuilder.ExecuteAllAsync();*/
}
}

View File

@@ -0,0 +1,90 @@
using System.Text;
using Core;
using Core.Actions;
using Core.Events;
namespace Generator.Infrastructure.Publication;
public class Publisher
{
private readonly CommandExecutor _executor;
public Publisher(string invite, DisplayEmitter emitter)
{
_executor = new CommandExecutor(invite, emitter);
}
/// <summary>
/// Published nuget package
/// </summary>
/// <param name="data"></param>
public async Task PublishNugget(DotnetPublish data)
{
var packageFolder = new Location([data.DockerRoot, data.PackageFolder]);
var stringBuilder = new StringBuilder();
stringBuilder
.Append($"docker run --rm -it -v {data.LocalRoot}:{data.DockerRoot} {data.Image} /bin/sh -c '")
.Append($"cd {packageFolder} && ")
.Append($"dotnet nuget push out/{data.PackageFile}.{data.PackageVersion}.nupkg -k {data.AuthorizationToken} -s {data.Registry}'");
await _executor.RunAsync(stringBuilder.ToString());
}
/// <summary>
/// Publishes npm packages
/// </summary>
/// <param name="data"></param>
public async Task PublishNpm(JavascriptPublish data)
{
var specFile = new Location([data.DockerRoot, data.SpecFile]).ToString().Replace("/api/", "");
var frontFolder = new Location([data.DockerRoot, data.FrontFolder]);
var creds = data.DockerRoot.ConcatenateWith(".npmrc");
var stringBuilder = new StringBuilder();
stringBuilder.Append($"docker run --rm -it -v {data.LocalRoot}:{data.DockerRoot} {data.Image} /bin/sh -c '");
stringBuilder.Append("cd front && ");
stringBuilder.Append($"npm run prepare-workspace -- --apiName={data.PackageName} --apiVersion={data.Version} ");
stringBuilder.Append($"--apiFile={specFile} --registry={data.Registry} && ");
stringBuilder.Append("npm run package && ");
stringBuilder.Append($"cp {creds} ./ && ");
stringBuilder.Append($"mkdir -p {frontFolder} && ");
stringBuilder.Append($"cp -r dist/* {frontFolder} && ");
stringBuilder.Append("npm run publish'");
await _executor.RunAsync(stringBuilder.ToString());
}
/// <summary>
/// Publishes maven package
/// </summary>
/// <param name="data"></param>
public async Task PublishMaven(JavaPublish data)
{
var templateFolder = new Location([data.DockerRoot, data.TemplateFolder]);
var outputFolder = new Location([data.DockerRoot, data.OutputFolder]);
var stringBuilder = new StringBuilder();
stringBuilder.Append($"docker run --rm -it -v {data.LocalRoot}:{data.DockerRoot} ");
stringBuilder.Append($"-v {data.LocalRoot}maven-generated:/root/.m2/repository {data.Image} /bin/sh -c '");
stringBuilder.Append($"cp {templateFolder}/settings.xml /root/.m2 && ");
stringBuilder.Append($"cd {outputFolder} && ");
stringBuilder.Append("mvn -e deploy:deploy-file ");
stringBuilder.Append($"-D file=target/{data.Artifact}-{data.Version}.jar ");
stringBuilder.Append($"-D groupId={data.Group} ");
stringBuilder.Append($"-D artifactId={data.Artifact} ");
stringBuilder.Append($"-D version={data.Version} ");
stringBuilder.Append("-D packaging=jar ");
stringBuilder.Append("-D generatePom=true ");
stringBuilder.Append("-D repositoryId=fcsd ");
stringBuilder.Append("-D skipTests ");
stringBuilder.Append($"-D url={data.Registry} ");
stringBuilder.Append("-D repo.id=fcsd ");
stringBuilder.Append($"-D repo.username={data.Username} ");
stringBuilder.Append($"-D repo.password={data.Password}'");
await _executor.RunAsync(stringBuilder.ToString());
}
}

View File

@@ -0,0 +1,20 @@
using Core.Templates;
namespace Generator.Infrastructure.TemplateFiller;
public abstract class AbstractFiller
{
protected string Render;
protected ITemplate Template;
/// <summary>
/// Fills the text extracted from the template file
/// </summary>
public abstract void Fill();
/// <summary>
/// Output the filled text in a file
/// </summary>
/// <param name="outputPath"></param>
public abstract void Write(string outputPath);
}

View File

@@ -0,0 +1,35 @@
using Core.Exceptions;
using Core.Templates;
using Mustache;
namespace Generator.Infrastructure.TemplateFiller;
public class MustacheFiller : AbstractFiller
{
public MustacheFiller(ITemplate template)
{
Template = template;
}
/// <inheritdoc/>
public override void Fill()
{
var compiler = new FormatCompiler
{
RemoveNewLines = false
};
var generator = compiler.Compile(Template?.GetText());
Render = generator.Render(Template?.GetData());
}
/// <inheritdoc/>
public override void Write(string outputPath)
{
if (Render == null) throw new FillerException(
"Filler Exception : No text can be written. Have you forgot to call the Fill method ?");
using StreamWriter file = new StreamWriter(outputPath);
file.Write(Render);
}
}

View File

@@ -0,0 +1,27 @@
using Core.Actions;
using Core.Dto.Settings;
using Core.Settings;
namespace Generator.Mappers;
public static class CredentialsMapper
{
public static CredentialsConfig Map(this CredentialsConfigDto dto)
=> new()
{
Email = dto.Email,
Token = dto.Token,
Username = dto.Username,
Password = dto.Password,
AlwaysAuth = dto.AlwaysAuth
};
public static PackageDeletion ToPackageDeletion(this CredentialsConfigDto dto)
{
return new PackageDeletion
{
Username = dto.Username,
Password = dto.Password
};
}
}

View File

@@ -0,0 +1,54 @@
using Core;
using Core.Dto.Settings;
using Core.Settings;
using Generator.DataSource.Settings;
namespace Generator.Mappers;
public static class DotnetMapper
{
public static DotnetConfig Map(this DotnetConfigDto dto, ConfigManager configManager, ISpecFile file)
{
var specName = file.Name;
var specFolder = file.Folder;
var generationFolder = configManager.GetGeneral().GenerationFolder;
var apiFolder = configManager.GetGeneral().ApiFolder;
var templatesConfig = configManager.Templates;
var baseConfig = configManager.GetBase();
var openApiConfig = configManager.OpenApi.Map(configManager, specFolder, specName);
var publishConfig = configManager.Publish;
var credConfig = configManager.Credentials;
var d = new DotnetConfig
{
LocalRoot = baseConfig.LocalRoot,
DockerRoot = baseConfig.DockerRoot,
GenerationImage = configManager.DockerImages.OpenApiGeneratorImage,
BuildImage = configManager.DockerImages.DotnetSdkImage,
Invite = baseConfig.Invite,
SpecFile = apiFolder.ConcatenateWith([specFolder, $"{specName}{openApiConfig.SpecExtension}"]),
OpenApi = openApiConfig.Folder,
PackageFolder = "src",
PackageFile = file.NugetPackage,
TemplateFolder = new Location(templatesConfig.Folder),
CommonFolder = generationFolder.ConcatenateWith([specFolder, dto.CommonFolder, specName]),
ServerFolder = generationFolder.ConcatenateWith([specFolder, dto.ServerFolder, specName]),
ClientFolder = generationFolder.ConcatenateWith([specFolder, dto.ClientFolder, specName]),
ConfigFile = openApiConfig.GeneratorConfigFile,
IgnoreFile = openApiConfig.GeneratorIgnoreFile,
ServerConfigTemplate = new Location([templatesConfig.Folder, templatesConfig.DotnetServerGeneratorConfig]),
ClientConfigTemplate = new Location([templatesConfig.Folder, templatesConfig.DotnetClientGeneratorConfig]),
ServerIgnoreTemplate = new Location([templatesConfig.Folder, templatesConfig.ServerIgnore]),
ClientIgnoreTemplate = new Location([templatesConfig.Folder, templatesConfig.ClientIgnore]),
Registry = publishConfig.NugetRegistry,
AuthorizationToken = credConfig.Token
};
return d;
}
}

View File

@@ -0,0 +1,49 @@
using Core;
using Core.Dto.Settings;
using Core.Settings;
using Generator.DataSource.Settings;
namespace Generator.Mappers;
public static class JavaMapper
{
public static JavaConfig Map(this JavaConfigDto dto, ConfigManager configManager, ISpecFile file)
{
var apiFolder = configManager.GetGeneral().ApiFolder;
var specFolder = file.Folder;
var specName = file.Name;
var templatesConfig = configManager.Templates;
var pubConfig = configManager.Publish;
var credConfig = configManager.Credentials;
var openApiConfig = configManager.OpenApi.Map(configManager, specFolder, specName);;
var generationFolder = configManager.GetGeneral().GenerationFolder;
var baseConfig = configManager.GetBase();
var j = new JavaConfig
{
LocalRoot = baseConfig.LocalRoot,
DockerRoot = baseConfig.DockerRoot,
Invite = baseConfig.Invite,
BuildImage = configManager.DockerImages.MavenImage,
GenerationImage = configManager.DockerImages.OpenApiGeneratorImage,
ServerFolder = generationFolder.ConcatenateWith([specFolder, dto.Folder, specName]),
ConfigOutput = generationFolder.ConcatenateWith(openApiConfig.GeneratorConfigFile),
SpecFile = apiFolder.ConcatenateWith([specFolder, $"{specName}{openApiConfig.SpecExtension}"]),
ConfigFile = openApiConfig.GeneratorConfigFile,
OpenApi = configManager.OpenApi.Map(configManager, specFolder, specName).Folder,
TemplateFolder = new Location(templatesConfig.Folder),
ServerConfigTemplate = new Location([templatesConfig.Folder, templatesConfig.JavaGeneratorConfig]),
Registry = pubConfig.MavenRegistry,
Artifact = $"{file.Name}-api",
Version = file.Version,
Username = credConfig.Username,
Password = credConfig.Password,
};
return j;
}
}

View File

@@ -0,0 +1,36 @@
using Core;
using Core.Dto.Settings;
using Core.Settings;
using Generator.DataSource.Settings;
namespace Generator.Mappers;
public static class JavascriptMapper
{
public static JavascriptConfig Map(this JavascriptConfigDto dto, ConfigManager configManager, ISpecFile file)
{
var apiFolder = configManager.GetGeneral().ApiFolder;
var specFolder = file.Folder;
var specName = file.Name;
var templatesConfig = configManager.Templates;
var openApiConfig = configManager.OpenApi.Map(configManager, specFolder, specName);
var generationFolder = configManager.GetGeneral().GenerationFolder;
var baseConfig = configManager.GetBase();
return new JavascriptConfig
{
LocalRoot = baseConfig.LocalRoot,
DockerRoot = baseConfig.DockerRoot,
GenerationImage = configManager.DockerImages.OpenApiGeneratorImage,
BuildImage = configManager.DockerImages.JavascriptImage,
Invite = baseConfig.Invite,
ClientFolder = generationFolder.ConcatenateWith([specFolder, dto.Folder, specName]),
SpecFile = apiFolder.ConcatenateWith([specFolder, $"{specName}{openApiConfig.SpecExtension}"]),
PackageName = file.NpmPackage,
OpenApiVersion = file.Version,
Registry = configManager.Publish.NpmRegistry,
TemplateFolder = new Location(templatesConfig.Folder),
OpenApi = configManager.OpenApi.Map(configManager, specFolder, specName).Folder
};
}
}

View File

@@ -0,0 +1,92 @@
using Core.Dto.Yaml;
using Core.Exceptions;
using Core.SpecConfig;
using Core.Yaml;
namespace Generator.Mappers;
public static class OpenApiYamlMapper
{
public static OpenApiYaml ToModel(this OpenApiYamlDto dto, string loc)
{
ISet<string> models = new HashSet<string>();
if (dto.Components is not null && dto.Components.TryGetValue("schemas", out var component))
{
models = component.Keys.ToHashSet();
}
return new OpenApiYaml(loc)
{
Info = dto.Info,
Openapi = dto.Openapi,
Tags = dto.Tags,
Models = models,
IgnoredModels = new HashSet<string>(),
};
}
public static Dictionary<string, YamlConfig> Map(this SpecConfigDto dto)
{
var result = new Dictionary<string, YamlConfig>();
foreach (var config in dto.Packages)
{
var yaml = new YamlConfig
{
Priority = config.Priority,
ModelSuffix = dto.ModelSuffix,
JavaGroup = dto.JavaGroup,
NugetPackage = config.DotnetPackage,
NpmPackage = config.JavascriptPackage,
KeepModels = config.KeepModels,
Type = ConvertSpecType(config.Type),
PackageTypes = ConvertPackagesTypes(dto.PackageTypes)
};
result.Add(config.Name, yaml);
}
return result;
}
private static PackageTypes ConvertPackagesTypes(Dictionary<string, List<string>> dto)
{
var res = new PackageTypes();
foreach (var d in dto)
{
var language = d.Key.ToLower() switch
{
"dotnet" => Language.Dotnet,
"java" => Language.Java,
"javascript" => Language.Javascript,
_ => throw new ConfigException($"Currently supported languages are dotnet, java and javascript. {d.Key} is not one of them. Fix it or consequences")
};
var generationTypes = d.Value.Select(t => t.ToLower() switch
{
"server" => GenerationType.Server,
"common" => GenerationType.Common,
"client" => GenerationType.Client,
_ => throw new ConfigException($"Currently supported generation types are server, common and client. {t} is not one of them. Fix it or consequences")
}).ToList();
generationTypes.ForEach(gt =>
{
if (!res.TryAdd(language, gt))
res.Add(language, [gt]);
});
}
return res;
}
private static SpecType ConvertSpecType(string type)
{
return type.ToLower() switch
{
"api" => SpecType.Api,
"model" => SpecType.Model,
_ => throw new ConfigException($"Currently supported spec types are api and model. {type} is not one of them. Fix it or consequences")
};
}
}

View File

@@ -0,0 +1,18 @@
using Core;
using Core.Dto;
namespace Generator.Mappers;
public static class PackageDataMapper
{
public static List<PackageData> Map(this List<PackageDataDto> dto)
{
return dto.Select(pdd
=> new PackageData()
{
Id = pdd.Id,
Name = pdd.Name,
Version = pdd.Version
}).ToList();
}
}

View File

@@ -0,0 +1,76 @@
using Core;
using Core.Dto;
using Core.Dto.Settings;
using Core.Settings;
using Generator.DataSource.Settings;
namespace Generator.Mappers;
public static class SettingsMapper
{
public static DefaultArgumentsConfig Map(this DefaultArgumentsConfigDto dto, ArgumentsDto args)
{
var identifier = args.SpecName ?? dto.SpecIdentifier;
return new DefaultArgumentsConfig
{
SpecIdentifier = identifier,
};
}
public static DockerImagesConfig Map(this DockerImagesConfigDto dto)
=> new()
{
JavaImage = dto.MavenImage,
DotnetSdkImage = dto.DotnetSdkImage,
OpenApiGeneratorImage = dto.OpenApiGeneratorImage,
JavascriptImage = dto.JavascriptImage,
};
public static BaseConfig Map(this EnvironmentConfigDto dto)
=> new()
{
Invite = dto.Invite,
LocalRoot = new Location(dto.LocalRoot),
DockerRoot = new Location(dto.DockerRoot),
TemplateFolder = null,
};
public static PublishConfig Map(this PublishConfigDto dto)
=> new()
{
MavenRegistry = dto.MavenRegistry,
NpmRegistry = dto.NpmRegistry,
NugetRegistry = dto.NugetRegistry
};
public static OpenApiConfig Map(this OpenApiConfigDto dto, ConfigManager configManager, string folder, string name)
{
var apiFolder = configManager.GetGeneral().ApiFolder;
var config = new OpenApiConfig
{
Folder = new Location(dto.OutputFolder),
GeneratorConfigFile = new Location(dto.GeneratorConfigFile),
GeneratorIgnoreFile = new Location(dto.GeneratorIgnoreFile),
SpecFile = apiFolder.ConcatenateWith([folder, $"{name}{dto.SpecExtension}"]),
SpecConfig = apiFolder.ConcatenateWith([folder, $"{name}{dto.ConfigIdentifier}{dto.ConfigExtension}"]),
SpecExtension = dto.SpecExtension,
SchemasIdentifier = dto.SchemasIdentifier,
ConfigIdentifier = $"{dto.ConfigIdentifier}{dto.ConfigExtension}",
};
return config;
}
public static GeneralConfig Map(this GeneralConfigDto dto)
=> new()
{
ApiFolder = new Location(dto.ApiFolder),
GenerationFolder = new Location(dto.OutputFolder),
};
}

View File

@@ -0,0 +1,21 @@
using Core;
using Core.Dto.Settings;
using Core.Settings;
namespace Generator.Mappers;
public static class TemplateMapper
{
public static TemplatesConfig Map(this TemplatesConfigDto dto)
=> new()
{
Folder = new Location(dto.Folder),
PlantUml = new Location([dto.Folder, dto.PlantUml]),
DotnetServerGeneratorConfig = new Location(dto.DotnetServerGeneratorConfig),
DotnetClientGeneratorConfig = new Location(dto.DotnetClientGeneratorConfig),
JavaGeneratorConfig = new Location(dto.JavaGeneratorConfig),
ServerIgnore = new Location(dto.ServerIgnore),
ClientIgnore = new Location(dto.ClientIgnore),
};
}

View File

@@ -0,0 +1,45 @@
using Core;
using Core.Helpers;
using Generator.Daos;
using Generator.DataSource.Yaml;
namespace Generator.Repo;
public class ApiAnalyzer
{
private readonly EnvironmentDao _envDao;
private readonly OpenApiDao _openApiDao;
public ApiAnalyzer(OpenApiDao openApiDao, EnvironmentDao envDao)
{
_envDao = envDao;
_openApiDao = openApiDao;
}
public IEnumerable<Location> ListSpecifications()
{
var res = new List<string>();
var directories = Directory.GetDirectories(_envDao.ApiFolder().ToString());
foreach (var d in directories) res.AddRange(Directory.EnumerateFiles(d));
return res
.Select(s => new Location(s))
.Where(s => s.HasExtension("yaml"));
}
public bool CanBeGenerated(string folder, string spec)
{
var extractor = new OpenApiYamlExtractor();
var path = _openApiDao.ConfigOf($"{folder}/{folder}");
var configs = extractor.LoadConfigs(path.ToString());
return configs.ContainsKey(spec);
}
public string GetText(string folder, string spec)
{
var path = _envDao.ApiFolder().ConcatenateWith([folder, $"{spec}.yaml"]);
return PathHelper.TextFrom(path.ToString());
}
}

View File

@@ -0,0 +1,26 @@
using Core;
using Core.Templates;
using Generator.Daos;
using Generator.Infrastructure.Export;
namespace Generator.Repo;
public class ExportRepo
{
private readonly TemplateDao _templateDao;
private readonly Exporter _exporter;
public ExportRepo(TemplateDao templateDao)
{
_templateDao = templateDao;
_exporter = new Exporter(new MustacheTemplateFactory());
}
public void PlantUml(ISpecFile file)
{
var export = _templateDao.PlantUml(file);
_exporter.PlantUml(export, file);
}
}

View File

@@ -0,0 +1,58 @@
using Core;
using Core.Helpers;
using Core.Interfaces;
using Core.SpecConfig;
using Core.Yaml;
using Generator.Daos;
using Generator.Infrastructure.OpenApi;
namespace Generator.Repo;
public class GenerateRepo
{
private readonly IGeneratorDirector<OpenApiYaml> _genDirector;
private readonly DotnetDao _dotnetDao;
private readonly JavaDao _javaDao;
private readonly JavascriptDao _javascriptDao;
public GenerateRepo(
OpenApiDirector genDirector,
DotnetDao dotnetDao,
JavaDao javaDao,
JavascriptDao jsDao)
{
_genDirector = genDirector;
_dotnetDao = dotnetDao;
_javaDao = javaDao;
_javascriptDao = jsDao;
}
public async Task GenerateDotnet(GenerationType type, ISpecFile specFile)
{
var file = TypeHelper.SafeCast<ISpecFile, OpenApiYaml>(specFile);
var config = _dotnetDao.GetDotnetGenerate(type, specFile);
if (type != GenerationType.Client)
{
await _genDirector.DotnetServer(file, config);
}
else
{
await _genDirector.DotnetClient(file, config);
}
}
public async Task GenerateJava(ISpecFile specFile)
{
var file = TypeHelper.SafeCast<ISpecFile, OpenApiYaml>(specFile);
var config = _javaDao.GetJavaGenerate(specFile);
await _genDirector.Java(file, config);
}
public async Task GenerateJavascript(ISpecFile specFile)
{
var file = TypeHelper.SafeCast<ISpecFile, OpenApiYaml>(specFile);
var config = _javascriptDao.GetJavascript(file);
await _genDirector.Javascript(file, config);
}
}

View File

@@ -0,0 +1,22 @@
using Core.Process;
using Core.SpecConfig;
using Generator.Daos;
using Generator.DataSource.Yaml;
namespace Generator.Repo;
public class PreGenerationRepo
{
private readonly YamlDirector _specDirector;
public PreGenerationRepo(OpenApiDao openApiDao)
{
_specDirector = new YamlDirector(openApiDao);
}
public GenerationProcess GetProcess(string specPath, GenerationType? generationType, PublishType publishType)
{
var file = _specDirector.BuildYaml(specPath);
return new GenerationProcess(file, publishType, generationType);
}
}

View File

@@ -0,0 +1,48 @@
using Core;
using Core.Events;
using Core.SpecConfig;
using Generator.Daos;
using Generator.Infrastructure.Publication;
using YamlDotNet.Core;
namespace Generator.Repo;
public class PublisherRepo
{
private readonly Publisher _publisher;
private readonly DotnetDao _dotnetDao;
private readonly JavaDao _javaDao;
private readonly JavascriptDao _javascriptDao;
public PublisherRepo(
EnvironmentDao envDao,
DotnetDao dotnetDao,
JavaDao javaDao,
JavascriptDao jsDao,
DisplayEmitter emitter)
{
_publisher = new Publisher(envDao.Invite, emitter);
_dotnetDao = dotnetDao;
_javaDao = javaDao;
_javascriptDao = jsDao;
}
public async Task PublishDotnet(GenerationType type, ISpecFile file)
{
var config = _dotnetDao.GetDotnetPublish(type, file);
await _publisher.PublishNugget(config);
}
public async Task PublishJava(GenerationType type, ISpecFile file)
{
var config = _javaDao.GetJavaPublish(type, file);
await _publisher.PublishMaven(config);
}
public async Task PublishJavascript(GenerationType type, ISpecFile file)
{
var config = _javascriptDao.GetJavascriptPublish(type, file);
await _publisher.PublishNpm(config);
}
}

View File

@@ -0,0 +1,32 @@
using Core;
using Core.Interfaces;
using Core.SpecConfig;
using Generator.Daos;
using Generator.DataSource.Packages;
using Generator.Mappers;
namespace Generator.Repo;
public class RepositoryActions
{
private readonly CredentialsDao _credentialsDao;
private readonly IRepositoryRequest _requester;
public RepositoryActions(CredentialsDao credentialsDao)
{
_credentialsDao = credentialsDao;
_requester = new NexusRequester(_credentialsDao.Username, _credentialsDao.Password);
}
public async Task<List<PackageData>> GetVersions(Language language, string package)
{
var packages = await _requester.GetVersions(language, package);
return packages.Map();
}
public async Task DeleteVersion(string packageId)
{
await _requester.DeleteVersion(packageId);
}
}

View File

@@ -0,0 +1,61 @@
using Core.Dto;
using Core.Events;
using Core.Interfaces;
using Core.Yaml;
using Generator.Controllers;
using Generator.Daos;
using Generator.DataSource.Settings;
using Generator.Infrastructure.OpenApi;
using Generator.Repo;
using Generator.Services;
using Microsoft.Extensions.DependencyInjection;
namespace Generator;
public static class ServiceExtension
{
public static void AddServices(this IServiceCollection services, IDataSourceLoader loader, ArgumentsDto args)
{
loader.LoadAppsettings();
services.AddSingleton(args);
services.AddSingleton<ConfigManager>();
services.AddSingleton<DisplayEmitter>();
services.AddScoped<EnvironmentDao>();
services.AddScoped<TemplateDao>();
services.AddScoped<OpenApiDao>();
services.AddScoped<DotnetDao>();
services.AddScoped<JavaDao>();
services.AddScoped<JavascriptDao>();
services.AddScoped<CredentialsDao>();
services.AddScoped<IGeneratorDirector<OpenApiYaml>, OpenApiDirector>();
services.AddScoped<ApiAnalyzer>();
services.AddScoped<OpenApiDirector>();
services.AddScoped<PreGenerationRepo>();
services.AddScoped<GenerateRepo>();
services.AddScoped<PublisherRepo>();
services.AddScoped<RepositoryActions>();
services.AddScoped<ExportRepo>();
services.AddScoped<PreGenerationService>();
services.AddScoped<GenerationService>();
services.AddScoped<PublicationService>();
services.AddScoped<AnalyzeService>();
services.AddScoped<RepositoryService>();
services.AddScoped<ExportService>();
services.AddScoped<PreGenerationController>();
services.AddScoped<GenerationController>();
services.AddScoped<PublicationController>();
services.AddScoped<AnalyzeController>();
services.AddScoped<ExportController>();
services.AddLogging();
}
}

View File

@@ -0,0 +1,20 @@
using Core;
using Generator.Repo;
namespace Generator.Services;
public class AnalyzeService
{
private readonly ApiAnalyzer _analyzer;
public AnalyzeService(ApiAnalyzer analyzer)
{
_analyzer = analyzer;
}
public IEnumerable<Location> ListSpecs() => _analyzer.ListSpecifications();
public bool CanBeGenerated(string folder, string spec) => _analyzer.CanBeGenerated(folder, spec);
public string GetSpecText(string folder, string spec) => _analyzer.GetText(folder, spec);
}

View File

@@ -0,0 +1,19 @@
using Core;
using Generator.Repo;
namespace Generator.Services;
public class ExportService
{
private readonly ExportRepo _repo;
public ExportService(ExportRepo repo)
{
_repo = repo;
}
public void ExportAsPuml(ISpecFile file)
{
_repo.PlantUml(file);
}
}

View File

@@ -0,0 +1,68 @@
using Core.Exceptions;
using Core.SpecConfig;
using Generator.Repo;
namespace Generator.Services;
public class GenerationService
{
private readonly GenerateRepo _repo;
private readonly PublicationService _pubService;
public GenerationService(PublicationService publicationService, GenerateRepo repo)
{
_repo = repo;
_pubService = publicationService;
}
public async Task Launch(ProcessTask task)
{
switch (task.Language)
{
case Language.Dotnet:
await LaunchDotnet(task);
break;
case Language.Java:
await LaunchJava(task);
break;
case Language.Javascript:
await LaunchJavascript(task);
break;
default:
throw new WeirdException("You broke me :(");
}
}
public async Task LaunchDotnet(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await _repo.GenerateDotnet(task.GenerationType, file);
if (task.PublishType == PublishType.No) continue;
await _pubService.PublishDotnet(file, task.GenerationType, task.PublishType);
}
}
public async Task LaunchJava(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await _repo.GenerateJava(file);
if (task.PublishType == PublishType.No) continue;
await _pubService.PublishJava(file, task.GenerationType, task.PublishType);
}
}
public async Task LaunchJavascript(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await _repo.GenerateJavascript(file);
if (task.PublishType == PublishType.No) continue;
await _pubService.PublishJavascript(file, task.GenerationType, task.PublishType);
}
}
}

View File

@@ -0,0 +1,22 @@
using Core.Process;
using Core.SpecConfig;
using Generator.Repo;
namespace Generator.Services;
public class PreGenerationService
{
private readonly PreGenerationRepo _repo;
public PreGenerationService(PreGenerationRepo repo)
{
_repo = repo;
}
public GenerationProcess ComputeGeneration(string specPath, GenerationType? generationType, PublishType publishType)
{
return _repo.GetProcess(specPath, generationType, publishType);
}
}

View File

@@ -0,0 +1,123 @@
using Core;
using Core.Process;
using Core.SpecConfig;
using Generator.Repo;
namespace Generator.Services;
public class PublicationService
{
private readonly PublisherRepo _publisherRepo;
private readonly RepositoryService _repoService;
public PublicationService(
PublisherRepo pubRepo,
RepositoryService repoService)
{
_publisherRepo = pubRepo;
_repoService = repoService;
}
public async Task Publish(GenerationProcess process)
{
foreach (var task in process)
{
switch (task.Language)
{
case Language.Dotnet:
await PublishDotnet(task);
break;
case Language.Java:
await PublishJava(task);
break;
case Language.Javascript:
await PublishJavascript(task);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
public async Task PublishDotnet(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await PublishDotnet(file, task.GenerationType, task.PublishType);
}
}
public async Task PublishJava(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await PublishJava(file, task.GenerationType, task.PublishType);
}
}
public async Task PublishJavascript(ProcessTask task)
{
while (task.Tasks.TryDequeue(out var file))
{
await PublishJavascript(file, task.GenerationType, task.PublishType);
}
}
public async Task PublishDotnet(ISpecFile file, GenerationType genType, PublishType pubType)
{
var data = await _repoService.GetVersions(Language.Dotnet, file.NugetPackage);
var package = data.FirstOrDefault(pd => pd.Version == file.Version);
if(pubType == PublishType.Force)
{
if (package != null) await _repoService.DeletePackage(package.Id);
await _publisherRepo.PublishDotnet(genType, file);
return;
}
if(pubType == PublishType.Safe)
{
if (package == null) await _publisherRepo.PublishDotnet(genType, file);
else Console.WriteLine($"The version {file.Version} of package {file.NugetPackage} already exists on the repository");
}
}
public async Task PublishJava(ISpecFile file, GenerationType genType, PublishType pubType)
{
var artifact = $"{file.Name}-api";
var data = await _repoService.GetVersions(Language.Java, artifact);
var package = data.FirstOrDefault(pd => pd.Version == file.Version);
if(pubType == PublishType.Force)
{
if (package != null) await _repoService.DeletePackage(package.Id);
await _publisherRepo.PublishJava(genType, file);
return;
}
if(pubType == PublishType.Safe)
{
if (package == null) await _publisherRepo.PublishJava(genType, file);
else Console.WriteLine($"The version {file.Version} of package {artifact} already exists on the repository");
}
}
public async Task PublishJavascript(ISpecFile file, GenerationType genType, PublishType pubType)
{
var data = await _repoService.GetVersions(Language.Javascript, file.NpmPackage);
var package = data.FirstOrDefault(pd => pd.Version == file.Version);
if(pubType == PublishType.Force)
{
if (package != null) await _repoService.DeletePackage(package.Id);
await _publisherRepo.PublishJavascript(genType, file);
return;
}
if(pubType == PublishType.Safe)
{
if (package == null) await _publisherRepo.PublishJavascript(genType, file);
else Console.WriteLine($"The version {file.Version} of package {file.NpmPackage} already exists on the repository");
}
}
}

View File

@@ -0,0 +1,25 @@
using Core;
using Core.SpecConfig;
using Generator.Repo;
namespace Generator.Services;
public class RepositoryService
{
private readonly RepositoryActions _actions;
public RepositoryService(RepositoryActions actions)
{
_actions = actions;
}
public async Task<List<PackageData>> GetVersions(Language language, string package)
{
return await _actions.GetVersions(language, package);
}
public async Task DeletePackage(string packageId)
{
await _actions.DeleteVersion(packageId);
}
}

View File

@@ -0,0 +1,50 @@
using Core.Interfaces;
namespace Generator.views;
public class ConsoleView : IView
{
public ConsoleView()
{
}
public void Display(string item)
{
Console.WriteLine(item);
}
public void Exception(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Display($"##############################\n{message}\n##############################");
Console.ResetColor();
}
public void Warning(string message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Display(message);
Console.ResetColor();
}
public void Info(string message)
{
Console.ForegroundColor = ConsoleColor.Blue;
Display(message);
Console.ResetColor();
}
public void Success(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
Display(message);
Display("##############################");
Console.ResetColor();
}
public void Progress(int percentage)
{
Display($"|..........| {percentage}%");
}
}