summaryrefslogtreecommitdiff
path: root/src/marlin.core/functional/WorkflowBuilder.cs
blob: a9121960b2131ae6683b2e62617813cf8b909e59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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);
    }

    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;

        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<string, string>(dto.With) : new();
        step.Fail = dto.Fail;
    }
}