iterator.go

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