forked from
tangled.org/core
fork
Configure Feed
Select the types of activity you want to include in your feed.
Monorepo for Tangled
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package workflow
2
3import (
4 "errors"
5 "fmt"
6
7 "tangled.org/core/api/tangled"
8)
9
10type RawWorkflow struct {
11 Name string
12 Contents []byte
13}
14
15type RawPipeline = []RawWorkflow
16
17type Compiler struct {
18 Trigger tangled.Pipeline_TriggerMetadata
19 Diagnostics Diagnostics
20}
21
22type Diagnostics struct {
23 Errors []Error
24 Warnings []Warning
25}
26
27func (d *Diagnostics) IsEmpty() bool {
28 return len(d.Errors) == 0 && len(d.Warnings) == 0
29}
30
31func (d *Diagnostics) Combine(o Diagnostics) {
32 d.Errors = append(d.Errors, o.Errors...)
33 d.Warnings = append(d.Warnings, o.Warnings...)
34}
35
36func (d *Diagnostics) AddWarning(path string, kind WarningKind, reason string) {
37 d.Warnings = append(d.Warnings, Warning{path, kind, reason})
38}
39
40func (d *Diagnostics) AddError(path string, err error) {
41 d.Errors = append(d.Errors, Error{path, err})
42}
43
44func (d Diagnostics) IsErr() bool {
45 return len(d.Errors) != 0
46}
47
48type Error struct {
49 Path string
50 Error error
51}
52
53func (e Error) String() string {
54 return fmt.Sprintf("error: %s: %s", e.Path, e.Error.Error())
55}
56
57type Warning struct {
58 Path string
59 Type WarningKind
60 Reason string
61}
62
63func (w Warning) String() string {
64 return fmt.Sprintf("warning: %s: %s: %s", w.Path, w.Type, w.Reason)
65}
66
67var (
68 MissingEngine error = errors.New("missing engine")
69)
70
71type WarningKind string
72
73var (
74 WorkflowSkipped WarningKind = "workflow skipped"
75 InvalidConfiguration WarningKind = "invalid configuration"
76)
77
78func (compiler *Compiler) Parse(p RawPipeline) Pipeline {
79 var pp Pipeline
80
81 for _, w := range p {
82 wf, err := FromFile(w.Name, w.Contents)
83 if err != nil {
84 compiler.Diagnostics.AddError(w.Name, err)
85 continue
86 }
87
88 pp = append(pp, wf)
89 }
90
91 return pp
92}
93
94// convert a repositories' workflow files into a fully compiled pipeline that runners accept
95func (compiler *Compiler) Compile(p Pipeline) tangled.Pipeline {
96 cp := tangled.Pipeline{
97 TriggerMetadata: &compiler.Trigger,
98 }
99
100 for _, wf := range p {
101 cw := compiler.compileWorkflow(wf)
102
103 if cw == nil {
104 continue
105 }
106
107 cp.Workflows = append(cp.Workflows, cw)
108 }
109
110 return cp
111}
112
113func (compiler *Compiler) compileWorkflow(w Workflow) *tangled.Pipeline_Workflow {
114 cw := &tangled.Pipeline_Workflow{}
115
116 if !w.Match(compiler.Trigger) {
117 compiler.Diagnostics.AddWarning(
118 w.Name,
119 WorkflowSkipped,
120 fmt.Sprintf("did not match trigger %s", compiler.Trigger.Kind),
121 )
122 return nil
123 }
124
125 // validate clone options
126 compiler.analyzeCloneOptions(w)
127
128 cw.Name = w.Name
129
130 if w.Engine == "" {
131 compiler.Diagnostics.AddError(w.Name, MissingEngine)
132 return nil
133 }
134
135 cw.Engine = w.Engine
136 cw.Raw = w.Raw
137
138 o := w.CloneOpts.AsRecord()
139 cw.Clone = &o
140
141 return cw
142}
143
144func (compiler *Compiler) analyzeCloneOptions(w Workflow) {
145 if w.CloneOpts.Skip && w.CloneOpts.IncludeSubmodules {
146 compiler.Diagnostics.AddWarning(
147 w.Name,
148 InvalidConfiguration,
149 "cannot apply `clone.skip` and `clone.submodules`",
150 )
151 }
152
153 if w.CloneOpts.Skip && w.CloneOpts.Depth > 0 {
154 compiler.Diagnostics.AddWarning(
155 w.Name,
156 InvalidConfiguration,
157 "cannot apply `clone.skip` and `clone.depth`",
158 )
159 }
160}