summaryrefslogtreecommitdiff
path: root/src/marlin.core/functional
diff options
context:
space:
mode:
Diffstat (limited to 'src/marlin.core/functional')
-rw-r--r--src/marlin.core/functional/WorkflowBuilder.cs153
-rw-r--r--src/marlin.core/functional/WorkflowJson.cs17
2 files changed, 170 insertions, 0 deletions
diff --git a/src/marlin.core/functional/WorkflowBuilder.cs b/src/marlin.core/functional/WorkflowBuilder.cs
new file mode 100644
index 0000000..79da909
--- /dev/null
+++ b/src/marlin.core/functional/WorkflowBuilder.cs
@@ -0,0 +1,153 @@
+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<WorkflowFileDto>(content);
+ if (file == null)
+ return;
+
+ this.ApplyRequirements(file.Requirements);
+ this.ApplyRecipes(file.Recipes);
+ this.ApplySteps(file.Steps);
+ this.ApplyArtifactHandlers(file.ArtifactHandlers);
+ }
+
+ private void ApplyRequirements(Dictionary<string, RequirementSetDto>? 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<string, string>(dto.Has) : new()
+ };
+
+ this._workflow.Requirements[id] = requirementSet;
+ }
+ }
+
+ private void ApplyRecipes(Dictionary<string, RecipeDto>? 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<string, string>(dto.Parameters) : new(),
+ Environment = dto.Environment != null ? new Dictionary<string, string>(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<string, StepDto>? 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;
+ step.Ingest = dto.Ingest ?? [];
+
+ if (dto.Artifacts != null)
+ {
+ foreach (var (artifactId, artifactDto) in dto.Artifacts)
+ {
+ step.Artifacts[artifactId] = new Artifact(artifactId)
+ {
+ Path = artifactDto.Path!,
+ Type = artifactDto.As!,
+ Handle = artifactDto.Handle ?? ArtifactHandle.Defer
+ };
+ }
+ }
+
+ 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 void ApplyArtifactHandlers(Dictionary<string, ArtifactHandlerDto>? handlers)
+ {
+ if (handlers == null)
+ return;
+
+ foreach (var (id, dto) in handlers)
+ {
+ var handler = new ArtifactHandler(id);
+
+ if (dto.Handle != null)
+ {
+ var handleStep = new ArtifactHandlerStep(id + "/handle");
+ ApplyAbstractStep(handleStep, dto.Handle);
+ handler.Handle = handleStep;
+ }
+
+ this._workflow.ArtifactHandlers[id] = handler;
+ }
+ }
+
+ private static void ApplyAbstractStep(AbstractStep step, StepDtoBase dto)
+ {
+ step.Name = dto.Name;
+ step.Run = dto.Run;
+ step.With = dto.With != null ? new Dictionary<string, string>(dto.With) : new();
+ step.Fail = dto.Fail;
+ }
+}
diff --git a/src/marlin.core/functional/WorkflowJson.cs b/src/marlin.core/functional/WorkflowJson.cs
new file mode 100644
index 0000000..011edae
--- /dev/null
+++ b/src/marlin.core/functional/WorkflowJson.cs
@@ -0,0 +1,17 @@
+namespace marlin.core.functional;
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using models.meta;
+
+public static class WorkflowJson
+{
+ private static readonly JsonSerializerOptions Options = new()
+ {
+ Converters = { new JsonStringEnumConverter() }
+ };
+
+ public static string Serialize(Workflow workflow) => JsonSerializer.Serialize(workflow, Options);
+
+ public static Workflow Deserialize(string json) => JsonSerializer.Deserialize<Workflow>(json, Options)!;
+}