1package gitlab
2
3import (
4 "time"
5
6 "github.com/xanzy/go-gitlab"
7)
8
9type issueIterator struct {
10 page int
11 index int
12 cache []*gitlab.Issue
13}
14
15type noteIterator struct {
16 page int
17 index int
18 cache []*gitlab.Note
19}
20
21type labelEventIterator struct {
22 page int
23 index int
24 cache []*gitlab.LabelEvent
25}
26
27type iterator struct {
28 // gitlab api v4 client
29 gc *gitlab.Client
30
31 // if since is given the iterator will query only the updated
32 // issues after this date
33 since time.Time
34
35 // project id
36 project string
37
38 // number of issues and notes to query at once
39 capacity int
40
41 // sticky error
42 err error
43
44 // issues iterator
45 issue *issueIterator
46
47 // notes iterator
48 note *noteIterator
49
50 labelEvent *labelEventIterator
51}
52
53// NewIterator create a new iterator
54func NewIterator(projectID, token string, capacity int, since time.Time) *iterator {
55 return &iterator{
56 gc: buildClient(token),
57 project: projectID,
58 since: since,
59 capacity: capacity,
60 issue: &issueIterator{
61 index: -1,
62 page: 1,
63 },
64 note: ¬eIterator{
65 index: -1,
66 page: 1,
67 },
68 labelEvent: &labelEventIterator{
69 index: -1,
70 page: 1,
71 },
72 }
73}
74
75// Error return last encountered error
76func (i *iterator) Error() error {
77 return i.err
78}
79
80func (i *iterator) getNextIssues() bool {
81 sort := "asc"
82 scope := "all"
83 issues, _, err := i.gc.Issues.ListProjectIssues(
84 i.project,
85 &gitlab.ListProjectIssuesOptions{
86 ListOptions: gitlab.ListOptions{
87 Page: i.issue.page,
88 PerPage: i.capacity,
89 },
90 Scope: &scope,
91 UpdatedAfter: &i.since,
92 Sort: &sort,
93 },
94 )
95
96 if err != nil {
97 i.err = err
98 return false
99 }
100
101 // if repository doesn't have any issues
102 if len(issues) == 0 {
103 return false
104 }
105
106 i.issue.cache = issues
107 i.issue.index = 0
108 i.issue.page++
109 i.note.index = -1
110 i.note.cache = nil
111
112 return true
113}
114
115func (i *iterator) NextIssue() bool {
116 // first query
117 if i.issue.cache == nil {
118 return i.getNextIssues()
119 }
120
121 if i.err != nil {
122 return false
123 }
124
125 // move cursor index
126 if i.issue.index < min(i.capacity, len(i.issue.cache))-1 {
127 i.issue.index++
128 return true
129 }
130
131 return i.getNextIssues()
132}
133
134func (i *iterator) IssueValue() *gitlab.Issue {
135 return i.issue.cache[i.issue.index]
136}
137
138func (i *iterator) getNextNotes() bool {
139 sort := "asc"
140 order := "created_at"
141 notes, _, err := i.gc.Notes.ListIssueNotes(
142 i.project,
143 i.IssueValue().IID,
144 &gitlab.ListIssueNotesOptions{
145 ListOptions: gitlab.ListOptions{
146 Page: i.note.page,
147 PerPage: i.capacity,
148 },
149 Sort: &sort,
150 OrderBy: &order,
151 },
152 )
153
154 if err != nil {
155 i.err = err
156 return false
157 }
158
159 if len(notes) == 0 {
160 i.note.index = -1
161 i.note.page = 1
162 i.note.cache = nil
163 return false
164 }
165
166 i.note.cache = notes
167 i.note.page++
168 i.note.index = 0
169 return true
170}
171
172func (i *iterator) NextNote() bool {
173 if i.err != nil {
174 return false
175 }
176
177 if len(i.note.cache) == 0 {
178 return i.getNextNotes()
179 }
180
181 // move cursor index
182 if i.note.index < min(i.capacity, len(i.note.cache))-1 {
183 i.note.index++
184 return true
185 }
186
187 return i.getNextNotes()
188}
189
190func (i *iterator) NoteValue() *gitlab.Note {
191 return i.note.cache[i.note.index]
192}
193
194func (i *iterator) getNextLabelEvents() bool {
195 labelEvents, _, err := i.gc.ResourceLabelEvents.ListIssueLabelEvents(
196 i.project,
197 i.IssueValue().IID,
198 &gitlab.ListLabelEventsOptions{
199 ListOptions: gitlab.ListOptions{
200 Page: i.labelEvent.page,
201 PerPage: i.capacity,
202 },
203 },
204 )
205
206 if err != nil {
207 i.err = err
208 return false
209 }
210
211 if len(labelEvents) == 0 {
212 i.labelEvent.page = 1
213 i.labelEvent.index = -1
214 i.labelEvent.cache = nil
215 return false
216 }
217
218 i.labelEvent.cache = labelEvents
219 i.labelEvent.page++
220 i.labelEvent.index = 0
221 return true
222}
223
224func (i *iterator) NextLabelEvent() bool {
225 if i.err != nil {
226 return false
227 }
228
229 if len(i.labelEvent.cache) == 0 {
230 return i.getNextLabelEvents()
231 }
232
233 // move cursor index
234 if i.labelEvent.index < min(i.capacity, len(i.labelEvent.cache))-1 {
235 i.labelEvent.index++
236 return true
237 }
238
239 return i.getNextLabelEvents()
240}
241
242func (i *iterator) LabelEventValue() *gitlab.LabelEvent {
243 return i.labelEvent.cache[i.labelEvent.index]
244}
245
246func min(a, b int) int {
247 if a > b {
248 return b
249 }
250
251 return a
252}