forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1package db 2 3import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.opentelemetry.io/otel/attribute" 9 "go.opentelemetry.io/otel/codes" 10 "go.opentelemetry.io/otel/trace" 11) 12 13type RepoEvent struct { 14 Repo *Repo 15 Source *Repo 16} 17 18type ProfileTimeline struct { 19 ByMonth []ByMonth 20} 21 22type ByMonth struct { 23 RepoEvents []RepoEvent 24 IssueEvents IssueEvents 25 PullEvents PullEvents 26} 27 28func (b ByMonth) IsEmpty() bool { 29 return len(b.RepoEvents) == 0 && 30 len(b.IssueEvents.Items) == 0 && 31 len(b.PullEvents.Items) == 0 32} 33 34type IssueEvents struct { 35 Items []*Issue 36} 37 38type IssueEventStats struct { 39 Open int 40 Closed int 41} 42 43func (i IssueEvents) Stats() IssueEventStats { 44 var open, closed int 45 for _, issue := range i.Items { 46 if issue.Open { 47 open += 1 48 } else { 49 closed += 1 50 } 51 } 52 53 return IssueEventStats{ 54 Open: open, 55 Closed: closed, 56 } 57} 58 59type PullEvents struct { 60 Items []*Pull 61} 62 63func (p PullEvents) Stats() PullEventStats { 64 var open, merged, closed int 65 for _, pull := range p.Items { 66 switch pull.State { 67 case PullOpen: 68 open += 1 69 case PullMerged: 70 merged += 1 71 case PullClosed: 72 closed += 1 73 } 74 } 75 76 return PullEventStats{ 77 Open: open, 78 Merged: merged, 79 Closed: closed, 80 } 81} 82 83type PullEventStats struct { 84 Closed int 85 Open int 86 Merged int 87} 88 89const TimeframeMonths = 7 90 91func MakeProfileTimeline(ctx context.Context, e Execer, forDid string) (*ProfileTimeline, error) { 92 span := trace.SpanFromContext(ctx) 93 defer span.End() 94 95 span.SetAttributes( 96 attribute.String("forDid", forDid), 97 ) 98 99 timeline := ProfileTimeline{ 100 ByMonth: make([]ByMonth, TimeframeMonths), 101 } 102 currentMonth := time.Now().Month() 103 timeframe := fmt.Sprintf("-%d months", TimeframeMonths) 104 105 pulls, err := GetPullsByOwnerDid(e, forDid, timeframe) 106 if err != nil { 107 span.RecordError(err) 108 span.SetStatus(codes.Error, "error getting pulls by owner did") 109 return nil, fmt.Errorf("error getting pulls by owner did: %w", err) 110 } 111 112 span.SetAttributes(attribute.Int("pulls.count", len(pulls))) 113 114 // group pulls by month 115 for _, pull := range pulls { 116 pullMonth := pull.Created.Month() 117 118 if currentMonth-pullMonth >= TimeframeMonths { 119 // shouldn't happen; but times are weird 120 continue 121 } 122 123 idx := currentMonth - pullMonth 124 items := &timeline.ByMonth[idx].PullEvents.Items 125 126 *items = append(*items, &pull) 127 } 128 129 issues, err := GetIssuesByOwnerDid(e, forDid, timeframe) 130 if err != nil { 131 span.RecordError(err) 132 span.SetStatus(codes.Error, "error getting issues by owner did") 133 return nil, fmt.Errorf("error getting issues by owner did: %w", err) 134 } 135 136 span.SetAttributes(attribute.Int("issues.count", len(issues))) 137 138 for _, issue := range issues { 139 issueMonth := issue.Created.Month() 140 141 if currentMonth-issueMonth >= TimeframeMonths { 142 // shouldn't happen; but times are weird 143 continue 144 } 145 146 idx := currentMonth - issueMonth 147 items := &timeline.ByMonth[idx].IssueEvents.Items 148 149 *items = append(*items, &issue) 150 } 151 152 repos, err := GetAllReposByDid(ctx, e, forDid) 153 if err != nil { 154 span.RecordError(err) 155 span.SetStatus(codes.Error, "error getting all repos by did") 156 return nil, fmt.Errorf("error getting all repos by did: %w", err) 157 } 158 159 span.SetAttributes(attribute.Int("repos.count", len(repos))) 160 161 for _, repo := range repos { 162 // TODO: get this in the original query; requires COALESCE because nullable 163 var sourceRepo *Repo 164 if repo.Source != "" { 165 sourceRepo, err = GetRepoByAtUri(ctx, e, repo.Source) 166 if err != nil { 167 span.RecordError(err) 168 span.SetStatus(codes.Error, "error getting repo by at uri") 169 return nil, err 170 } 171 } 172 173 repoMonth := repo.Created.Month() 174 175 if currentMonth-repoMonth >= TimeframeMonths { 176 // shouldn't happen; but times are weird 177 continue 178 } 179 180 idx := currentMonth - repoMonth 181 182 items := &timeline.ByMonth[idx].RepoEvents 183 *items = append(*items, RepoEvent{ 184 Repo: &repo, 185 Source: sourceRepo, 186 }) 187 } 188 189 return &timeline, nil 190}