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