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 iterator
51 labelEvent *labelEventIterator
52}
53
54// NewIterator create a new iterator
55func NewIterator(projectID, token string, since time.Time) *iterator {
56 return &iterator{
57 gc: buildClient(token),
58 project: projectID,
59 since: since,
60 capacity: 20,
61 issue: &issueIterator{
62 index: -1,
63 page: 1,
64 },
65 note: ¬eIterator{
66 index: -1,
67 page: 1,
68 },
69 labelEvent: &labelEventIterator{
70 index: -1,
71 page: 1,
72 },
73 }
74}
75
76// Error return last encountered error
77func (i *iterator) Error() error {
78 return i.err
79}
80
81func (i *iterator) getNextIssues() bool {
82 sort := "asc"
83 scope := "all"
84 issues, _, err := i.gc.Issues.ListProjectIssues(
85 i.project,
86 &gitlab.ListProjectIssuesOptions{
87 ListOptions: gitlab.ListOptions{
88 Page: i.issue.page,
89 PerPage: i.capacity,
90 },
91 Scope: &scope,
92 UpdatedAfter: &i.since,
93 Sort: &sort,
94 },
95 )
96
97 if err != nil {
98 i.err = err
99 return false
100 }
101
102 // if repository doesn't have any issues
103 if len(issues) == 0 {
104 return false
105 }
106
107 i.issue.cache = issues
108 i.issue.index = 0
109 i.issue.page++
110 i.note.index = -1
111 i.note.cache = nil
112
113 return true
114}
115
116func (i *iterator) NextIssue() bool {
117 // first query
118 if i.issue.cache == nil {
119 return i.getNextIssues()
120 }
121
122 if i.err != nil {
123 return false
124 }
125
126 // move cursor index
127 if i.issue.index < len(i.issue.cache)-1 {
128 i.issue.index++
129 return true
130 }
131
132 return i.getNextIssues()
133}
134
135func (i *iterator) IssueValue() *gitlab.Issue {
136 return i.issue.cache[i.issue.index]
137}
138
139func (i *iterator) getNextNotes() bool {
140 sort := "asc"
141 order := "created_at"
142 notes, _, err := i.gc.Notes.ListIssueNotes(
143 i.project,
144 i.IssueValue().IID,
145 &gitlab.ListIssueNotesOptions{
146 ListOptions: gitlab.ListOptions{
147 Page: i.note.page,
148 PerPage: i.capacity,
149 },
150 Sort: &sort,
151 OrderBy: &order,
152 },
153 )
154
155 if err != nil {
156 i.err = err
157 return false
158 }
159
160 if len(notes) == 0 {
161 i.note.index = -1
162 i.note.page = 1
163 i.note.cache = nil
164 return false
165 }
166
167 i.note.cache = notes
168 i.note.page++
169 i.note.index = 0
170 return true
171}
172
173func (i *iterator) NextNote() bool {
174 if i.err != nil {
175 return false
176 }
177
178 if len(i.note.cache) == 0 {
179 return i.getNextNotes()
180 }
181
182 // move cursor index
183 if i.note.index < len(i.note.cache)-1 {
184 i.note.index++
185 return true
186 }
187
188 return i.getNextNotes()
189}
190
191func (i *iterator) NoteValue() *gitlab.Note {
192 return i.note.cache[i.note.index]
193}
194
195func (i *iterator) getNextLabelEvents() bool {
196 labelEvents, _, err := i.gc.ResourceLabelEvents.ListIssueLabelEvents(
197 i.project,
198 i.IssueValue().IID,
199 &gitlab.ListLabelEventsOptions{
200 ListOptions: gitlab.ListOptions{
201 Page: i.labelEvent.page,
202 PerPage: i.capacity,
203 },
204 },
205 )
206
207 if err != nil {
208 i.err = err
209 return false
210 }
211
212 if len(labelEvents) == 0 {
213 i.labelEvent.page = 1
214 i.labelEvent.index = -1
215 i.labelEvent.cache = nil
216 return false
217 }
218
219 i.labelEvent.cache = labelEvents
220 i.labelEvent.page++
221 i.labelEvent.index = 0
222 return true
223}
224
225func (i *iterator) NextLabelEvent() bool {
226 if i.err != nil {
227 return false
228 }
229
230 if len(i.labelEvent.cache) == 0 {
231 return i.getNextLabelEvents()
232 }
233
234 // move cursor index
235 if i.labelEvent.index < len(i.labelEvent.cache)-1 {
236 i.labelEvent.index++
237 return true
238 }
239
240 return i.getNextLabelEvents()
241}
242
243func (i *iterator) LabelEventValue() *gitlab.LabelEvent {
244 return i.labelEvent.cache[i.labelEvent.index]
245}
246
247func min(a, b int) int {
248 if a > b {
249 return b
250 }
251
252 return a
253}