namespace marlin.core.functional; using models.meta; using models.meta.dto; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; public class WorkflowBuilder { private static readonly IDeserializer Deserializer = new DeserializerBuilder() .WithNamingConvention(HyphenatedNamingConvention.Instance) .WithEnumNamingConvention(HyphenatedNamingConvention.Instance) .IgnoreUnmatchedProperties() .Build(); private readonly Workflow _workflow = new(); public Workflow Build() => this._workflow; public void LoadFromDirectory(string path) { var files = Directory.EnumerateFiles(path, "*.yml", SearchOption.AllDirectories); foreach (var file in files) this.LoadFromString(File.ReadAllText(file)); } public void LoadFromString(string content) { var file = Deserializer.Deserialize(content); if (file == null) return; this.ApplyRequirements(file.Requirements); this.ApplyRecipes(file.Recipes); this.ApplySteps(file.Steps); } private void ApplyRequirements(Dictionary? requirements) { if (requirements == null) return; foreach (var (id, dto) in requirements) { var requirementSet = new RequirementSet(id) { Base = dto.Base, Has = dto.Has != null ? new Dictionary(dto.Has) : new() }; this._workflow.Requirements[id] = requirementSet; } } private void ApplyRecipes(Dictionary? recipes) { if (recipes == null) return; foreach (var (id, dto) in recipes) { var recipe = new Recipe(id) { Name = dto.Name ?? id, RunsOnId = dto.RunsOn, RequireIds = dto.Requires ?? [], Parameters = dto.Parameters != null ? new Dictionary(dto.Parameters) : new(), Environment = dto.Environment != null ? new Dictionary(dto.Environment) : new() }; if (dto.Steps != null) { foreach (var (stepId, stepDto) in dto.Steps) recipe.Steps[stepId] = this.BuildRecipeStep(stepId, stepDto); } this._workflow.Recipes[id] = recipe; } } private void ApplySteps(Dictionary? steps) { if (steps == null) return; foreach (var (id, dto) in steps) this._workflow.Steps[id] = this.BuildRecipeStep(id, dto); } private RecipeStep BuildRecipeStep(string id, StepDto dto) { var step = new RecipeStep(id); ApplyAbstractStep(step, dto); step.BaseId = dto.Base; if (dto.Artifacts != null) { foreach (var item in dto.Artifacts) step.Artifacts[item.Key] = item.Value; } if (dto.Cleanup != null) step.Cleanup = BuildCleanupStep(id + "/cleanup", dto.Cleanup); return step; } private static CleanupStep BuildCleanupStep(string id, CleanupStepDto dto) { var step = new CleanupStep(id) { After = dto.After ?? CleanupAfter.Step }; ApplyAbstractStep(step, dto); return step; } private static void ApplyAbstractStep(AbstractStep step, StepDtoBase dto) { step.Name = dto.Name; step.Run = dto.Run; step.With = dto.With != null ? new Dictionary(dto.With) : new(); step.Fail = dto.Fail; } }