-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
229 lines (188 loc) · 7.46 KB
/
types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package main
import "github.com/shurcooL/githubv4"
// ProjectItemsQuery is used to list the project items in a project
type ProjectItemsQuery struct {
ProjectV2ObjectFragment `graphql:"node(id: $nodeId)"`
}
// HasNextPage returns true if there are additional project items to be listed
func (p ProjectItemsQuery) HasNextPage() bool {
return p.Items.HasNextPage
}
// ProjectV2ObjectFragment is an intermediary fragment used for selecting the ProjectV2 object
type ProjectV2ObjectFragment struct {
ProjectFragment `graphql:"...on ProjectV2"`
}
// ProjectFragment represents a ProjectV2 object
type ProjectFragment struct {
Items ProjectItemsFragment `graphql:"items(first:10, after: $cursor)"`
}
// ProjectItemsFragment is used as an embedded struct in ProjectFragment, and represents
// the information about the items in a project
type ProjectItemsFragment struct {
PageInfo `graphql:"pageInfo"`
Edges []ProjectItemEdgeFragment
}
// PageInfo represents pagingation information returned by GitHub's GraphQL API
type PageInfo struct {
EndCursor githubv4.String
HasNextPage bool
}
// ProjectItemEdgeFragment represents the connection between a project and a project item
type ProjectItemEdgeFragment struct {
Cursor githubv4.String
ProjectItemFragment `graphql:"node"`
}
// ProjectItemFragment represents a node at the end of a ProjectItemEdge
type ProjectItemFragment struct {
Id githubv4.ID
IsArchived bool
Type string
UpvotesField struct {
ProjectV2ItemFieldNumberValueFragment `graphql:"...on ProjectV2ItemFieldNumberValue"`
} `graphql:"fieldValueByName(name:\"Upvotes\")"` // todo: reconsider opinionated field name
Content Content
}
// GetContent returns the issue or pull request that is connected to the project item
func (p ProjectItemFragment) GetContent() ContentFragment {
var content ContentFragment
switch p.Content.Type {
case "Issue":
content = p.Content.Issue
case "PullRequest":
content = p.Content.PullRequest
}
return content
}
// Skip returns true if upvotes should not be calculated for the project item. A project item should
// be skipped if it meets any of these criterea:
//
// - It is a draft item
// - The item is archived
// - The issue or pull request connected to the project item is closed
// - There are no new timeline items since the existing cursor
func (p ProjectItemFragment) Skip() bool {
return p.Type == "DraftIssue" || p.IsArchived || p.GetContent().Closed
}
// ProjectV2ItemFieldNumberValueFragment is used to get the value of a number field in a project
type ProjectV2ItemFieldNumberValueFragment struct {
Value float64 `graphql:"number"`
}
// Content is the actual Issue or Pull Request connected to a Project Item
type Content struct {
Type string `graphql:"__typename"`
Issue ContentFragment `graphql:"...on Issue"`
PullRequest ContentFragment `graphql:"...on PullRequest"`
}
// Common content fragment represents an Issue or Pull Request.
type ContentFragment struct {
CommentsAndReactionsFragment
Id githubv4.String
Closed bool
TimelineItems struct {
PageInfo `graphql:"pageInfo"`
Nodes []TimelineItem
} `graphql:"timelineItems(first: 10, after: $timelineCursor, itemTypes: [CONNECTED_EVENT, CROSS_REFERENCED_EVENT, ISSUE_COMMENT, MARKED_AS_DUPLICATE_EVENT, REFERENCED_EVENT, SUBSCRIBED_EVENT])"`
}
// Upvotes returns the total upvotes for the Issue or Pull Request
func (c ContentFragment) Upvotes() int {
upvotes := c.Comments.TotalCount + c.Reactions.TotalCount
for _, node := range c.TimelineItems.Nodes {
upvotes += node.upvotes()
}
return upvotes
}
// CommentsAndReactionsFragment is embedded to add the Comments and Reactions fields
type CommentsAndReactionsFragment struct {
Comments TotalCountFragment
Reactions TotalCountFragment
}
// TotalCountFragment is used as a general purpose fragment when the only needed information is
// the total count of connections.
type TotalCountFragment struct {
TotalCount int
}
// TimelineItem respresents an individual timeline item -- an event in the Issue or Pull
// Request's history.
type TimelineItem struct {
Type githubv4.String `graphql:"__typename"`
ConnectedEvent ConnectedOrCrossReferencedEvent `graphql:"...on ConnectedEvent"`
CrossReferencedEvent ConnectedOrCrossReferencedEvent `graphql:"...on CrossReferencedEvent"`
IssueComment IssueComment `graphql:"...on IssueComment"`
MarkedAsDuplicateEvent MarkedAsDuplicateEvent `graphql:"...on MarkedAsDuplicateEvent"`
}
// Upvotes returns the total upvotes for the given timeline item
func (t TimelineItem) upvotes() int {
// the fact that the timeline item exists means that the minimum upvotes is 1
upvotes := 1
switch t.Type {
case "ConnectedEvent":
upvotes += t.ConnectedEvent.upvotes()
case "CrossReferencedEvent":
upvotes += t.CrossReferencedEvent.upvotes()
case "IssueComment":
upvotes += t.IssueComment.Reactions.TotalCount
case "MarkedAsDuplicateEvent":
upvotes += t.MarkedAsDuplicateEvent.upvotes()
}
return upvotes
}
// IssueOrPullRequestCommentsAndReactionsFragment is embedded in the common case of separate Issue and Pull Request
// fields that are both of type CommentsAndReactionsFragment.
type IssueOrPullRequestCommentsAndReactionsFragment struct {
Type string `graphql:"__typename"`
Issue CommentsAndReactionsFragment `graphql:"...on Issue"`
PullRequest CommentsAndReactionsFragment `graphql:"...on PullRequest"`
}
// upvotes returns the count of comments and reactions to the Issue or Pull Request connected to a TimelineItem
func (i IssueOrPullRequestCommentsAndReactionsFragment) upvotes() int {
var content CommentsAndReactionsFragment
switch i.Type {
case "Issue":
content = i.Issue
case "PullRequest":
content = i.PullRequest
}
return content.Comments.TotalCount + content.Reactions.TotalCount
}
// Represents events when an issue or pull request was connected to, or cross-referenced
// the item.
type ConnectedOrCrossReferencedEvent struct {
IssueOrPullRequestCommentsAndReactionsFragment `graphql:"source"`
}
// Represents an event of someone commenting on the item
type IssueComment struct {
Reactions TotalCountFragment
}
// Represents the item being marked as a duplicate of the canonical item
type MarkedAsDuplicateEvent struct {
IssueOrPullRequestCommentsAndReactionsFragment `graphql:"canonical"`
}
// AdditionalTimelineItemQuery is used to query for additional timeline items when there
// are more than the 100 that are accounted for in the initial ProjectItemsQuery
type AdditionalTimelineItemQuery struct {
Content `graphql:"node(id: $nodeId)"`
RateLimit RateLimit
}
// RateLimit represents information related to the GitHub GraphQL rate limit
type RateLimit struct {
Remaining int
Cost int
}
// ProjectItemQuery is used to list the timeline items for a specific project item
type ProjectItemQuery struct {
ProjectV2ItemObjectFragment `graphql:"node(id: $nodeId)"`
}
// HasNextPage returns true if there are additional timeline items for the project item
func (p ProjectItemQuery) HasNextPage() bool {
return p.GetContent().TimelineItems.HasNextPage
}
// ProjectV2ItemObjectFragment is an intermediary fragment used for selecting the ProjectV2Item object
type ProjectV2ItemObjectFragment struct {
ProjectItemFragment `graphql:"...on ProjectV2Item"`
}
// Update instructs what node to update and the number of votes to update with
type Update struct {
Id githubv4.ID
Upvotes *githubv4.Float
Cursor githubv4.String
}