Monorepo for Tangled
at master 179 lines 3.9 kB view raw
1package models 2 3import ( 4 "fmt" 5 "slices" 6 "strings" 7 "time" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "github.com/go-git/go-git/v5/plumbing" 11 "tangled.org/core/api/tangled" 12 spindle "tangled.org/core/spindle/models" 13 "tangled.org/core/workflow" 14) 15 16type Pipeline struct { 17 Id int 18 Rkey string 19 Knot string 20 RepoOwner syntax.DID 21 RepoName string 22 RepoDid string 23 TriggerId int 24 Sha string 25 Created time.Time 26 27 // populate when querying for reverse mappings 28 Trigger *Trigger 29 Statuses map[string]WorkflowStatus 30} 31 32func (p *Pipeline) AtUri() syntax.ATURI { 33 return syntax.ATURI(fmt.Sprintf("at://did:web:%s/%s/%s", p.Knot, tangled.PipelineNSID, p.Rkey)) 34} 35 36type WorkflowStatus struct { 37 Data []PipelineStatus 38} 39 40func (w WorkflowStatus) Latest() PipelineStatus { 41 return w.Data[len(w.Data)-1] 42} 43 44// time taken by this workflow to reach an "end state" 45func (w WorkflowStatus) TimeTaken() time.Duration { 46 var start, end *time.Time 47 for _, s := range w.Data { 48 if s.Status.IsStart() { 49 start = &s.Created 50 } 51 if s.Status.IsFinish() { 52 end = &s.Created 53 } 54 } 55 56 if start != nil && end != nil && end.After(*start) { 57 return end.Sub(*start) 58 } 59 60 return 0 61} 62 63// produces short summary of successes: 64// - "0/4" when zero successes of 4 workflows 65// - "4/4" when all successes of 4 workflows 66// - "0/0" when no workflows run in this pipeline 67func (p Pipeline) ShortStatusSummary() string { 68 counts := make(map[spindle.StatusKind]int) 69 for _, w := range p.Statuses { 70 counts[w.Latest().Status] += 1 71 } 72 73 total := len(p.Statuses) 74 successes := counts[spindle.StatusKindSuccess] 75 76 return fmt.Sprintf("%d/%d", successes, total) 77} 78 79// produces a string of the form "3/4 success, 2/4 failed, 1/4 pending" 80func (p Pipeline) LongStatusSummary() string { 81 counts := make(map[spindle.StatusKind]int) 82 for _, w := range p.Statuses { 83 counts[w.Latest().Status] += 1 84 } 85 86 total := len(p.Statuses) 87 88 var result []string 89 // finish states first, followed by start states 90 states := append(spindle.FinishStates[:], spindle.StartStates[:]...) 91 for _, state := range states { 92 if count, ok := counts[state]; ok { 93 result = append(result, fmt.Sprintf("%d/%d %s", count, total, state.String())) 94 } 95 } 96 97 return strings.Join(result, ", ") 98} 99 100func (p Pipeline) Counts() map[string]int { 101 m := make(map[string]int) 102 for _, w := range p.Statuses { 103 m[w.Latest().Status.String()] += 1 104 } 105 return m 106} 107 108func (p Pipeline) TimeTaken() time.Duration { 109 var s time.Duration 110 for _, w := range p.Statuses { 111 s += w.TimeTaken() 112 } 113 return s 114} 115 116func (p Pipeline) Workflows() []string { 117 var ws []string 118 for v := range p.Statuses { 119 ws = append(ws, v) 120 } 121 slices.Sort(ws) 122 return ws 123} 124 125// if we know that a spindle has picked up this pipeline, then it is Responding 126func (p Pipeline) IsResponding() bool { 127 return len(p.Statuses) != 0 128} 129 130type Trigger struct { 131 Id int 132 Kind workflow.TriggerKind 133 134 // push trigger fields 135 PushRef *string 136 PushNewSha *string 137 PushOldSha *string 138 139 // pull request trigger fields 140 PRSourceBranch *string 141 PRTargetBranch *string 142 PRSourceSha *string 143 PRAction *string 144} 145 146func (t *Trigger) IsPush() bool { 147 return t != nil && t.Kind == workflow.TriggerKindPush 148} 149 150func (t *Trigger) IsPullRequest() bool { 151 return t != nil && t.Kind == workflow.TriggerKindPullRequest 152} 153 154func (t *Trigger) TargetRef() string { 155 if t.IsPush() { 156 return plumbing.ReferenceName(*t.PushRef).Short() 157 } else if t.IsPullRequest() { 158 return *t.PRTargetBranch 159 } 160 161 return "" 162} 163 164type PipelineStatus struct { 165 ID int 166 Spindle string 167 Rkey string 168 PipelineKnot string 169 PipelineRkey string 170 Created time.Time 171 Workflow string 172 Status spindle.StatusKind 173 Error *string 174 ExitCode int 175} 176 177func (ps *PipelineStatus) PipelineAt() syntax.ATURI { 178 return syntax.ATURI(fmt.Sprintf("at://did:web:%s/%s/%s", ps.PipelineKnot, tangled.PipelineNSID, ps.PipelineRkey)) 179}