···
8
+
"tangled.sh/tangled.sh/core/api/tangled"
10
+
"github.com/go-git/go-git/v5/plumbing"
14
+
// - when a repo is modified, it results in the trigger of a "Pipeline"
15
+
// - a repo could consist of several workflow files
16
+
// * .tangled/workflows/test.yml
17
+
// * .tangled/workflows/lint.yml
18
+
// - therefore a pipeline consists of several workflows, these execute in parallel
19
+
// - each workflow consists of some execution steps, these execute serially
24
+
// this is simply a structural representation of the workflow file
26
+
Name string `yaml:"-"` // name of the workflow file
27
+
When []Constraint `yaml:"when"`
28
+
Dependencies Dependencies `yaml:"dependencies"`
29
+
Steps []Step `yaml:"steps"`
30
+
Environment map[string]string `yaml:"environment"`
31
+
CloneOpts CloneOpts `yaml:"clone"`
35
+
Event StringList `yaml:"event"`
36
+
Branch StringList `yaml:"branch"` // this is optional, and only applied on "push" events
39
+
Dependencies map[string][]string
42
+
Skip bool `yaml:"skip"`
43
+
Depth int `yaml:"depth"`
44
+
IncludeSubmodules bool `yaml:"submodules"`
48
+
Name string `yaml:"name"`
49
+
Command string `yaml:"command"`
56
+
TriggerKindPush string = "push"
57
+
TriggerKindPullRequest string = "pull_request"
58
+
TriggerKindManual string = "manual"
61
+
func FromFile(name string, contents []byte) (Workflow, error) {
64
+
err := yaml.Unmarshal(contents, &wf)
74
+
// if any of the constraints on a workflow is true, return true
75
+
func (w *Workflow) Match(trigger tangled.Pipeline_TriggerMetadata) bool {
76
+
// manual triggers always run the workflow
77
+
if trigger.Manual != nil {
81
+
// if not manual, run through the constraint list and see if any one matches
82
+
for _, c := range w.When {
83
+
if c.Match(trigger) {
88
+
// no constraints, always run this workflow
89
+
if len(w.When) == 0 {
96
+
func (c *Constraint) Match(trigger tangled.Pipeline_TriggerMetadata) bool {
99
+
// manual triggers always pass this constraint
100
+
if trigger.Manual != nil {
104
+
// apply event constraints
105
+
match = match && c.MatchEvent(trigger.Kind)
107
+
// apply branch constraints for PRs
108
+
if trigger.PullRequest != nil {
109
+
match = match && c.MatchBranch(trigger.PullRequest.TargetBranch)
112
+
// apply ref constraints for pushes
113
+
if trigger.Push != nil {
114
+
match = match && c.MatchRef(trigger.Push.Ref)
120
+
func (c *Constraint) MatchBranch(branch string) bool {
121
+
return slices.Contains(c.Branch, branch)
124
+
func (c *Constraint) MatchRef(ref string) bool {
125
+
refName := plumbing.ReferenceName(ref)
126
+
if refName.IsBranch() {
127
+
return slices.Contains(c.Branch, refName.Short())
129
+
fmt.Println("no", c.Branch, refName.Short())
134
+
func (c *Constraint) MatchEvent(event string) bool {
135
+
return slices.Contains(c.Event, event)
138
+
// Custom unmarshaller for StringList
139
+
func (s *StringList) UnmarshalYAML(unmarshal func(any) error) error {
140
+
var stringType string
141
+
if err := unmarshal(&stringType); err == nil {
142
+
*s = []string{stringType}
146
+
var sliceType []any
147
+
if err := unmarshal(&sliceType); err == nil {
149
+
if sliceType == nil {
154
+
parts := make([]string, len(sliceType))
155
+
for k, v := range sliceType {
156
+
if sv, ok := v.(string); ok {
159
+
return fmt.Errorf("cannot unmarshal '%v' of type %T into a string value", v, v)
167
+
return errors.New("failed to unmarshal StringOrSlice")
170
+
// conversion utilities to atproto records
171
+
func (d Dependencies) AsRecord() []tangled.Pipeline_Dependencies_Elem {
172
+
var deps []tangled.Pipeline_Dependencies_Elem
173
+
for registry, packages := range d {
174
+
deps = append(deps, tangled.Pipeline_Dependencies_Elem{
175
+
Registry: registry,
176
+
Packages: packages,
182
+
func (s Step) AsRecord() tangled.Pipeline_Step {
183
+
return tangled.Pipeline_Step{
184
+
Command: s.Command,
189
+
func (c CloneOpts) AsRecord() tangled.Pipeline_CloneOpts {
190
+
return tangled.Pipeline_CloneOpts{
191
+
Depth: int64(c.Depth),
193
+
Submodules: c.IncludeSubmodules,