git-bug/bridge/gitlab/iterator.go
Amine Hilaly 5ca326af83 bridge/core: add context.Context to ImportAll and ExportAll signatures
bridge/core: add ImportResult objects to stream import events

bridge/core: launchpad support asynchronous import

bridge/github: cancellable export and import functions

bridge/gitlab: cancellable export and import functions

commands: bridge pull/push gracefull kill

bridge/github: fix github import

bridge/github: use simple context for imports

bridge/core: name parameters in interfaces

github/core: Add EventError to export and import events types

bridge/gitlab: add context support in gitlab requests functions

bridge/gitlab: remove imported events count from importer logic

bridge/github: remove imported events count from importer logic

bridge/github: add context support in query and muration requets

bridge/github: fix bug duplicate editions after multiple calls

bridge/core: import import and export events String methods
bridge/gitlab: fix error handling in note import events

commands/bridge: Add statistics about imports and exports

bridge/gitlab: properly handle context cancellation

bridge/github: improve error handling

bridge: break iterators on context cancel or timeout

bridge: add context timeout support

bridge: improve event formating and error handling

commands: handle interrupt and switch cases

bridge/github: add export mutation timeouts

bridge: fix race condition bug in the github and gitlab importers
bridge/github: improve context error handling
2019-08-18 00:14:22 +02:00

272 lines
4.5 KiB
Go

package gitlab
import (
"context"
"time"
"github.com/xanzy/go-gitlab"
)
type issueIterator struct {
page int
index int
cache []*gitlab.Issue
}
type noteIterator struct {
page int
index int
cache []*gitlab.Note
}
type labelEventIterator struct {
page int
index int
cache []*gitlab.LabelEvent
}
type iterator struct {
// gitlab api v4 client
gc *gitlab.Client
// if since is given the iterator will query only the issues
// updated after this date
since time.Time
// project id
project string
// number of issues and notes to query at once
capacity int
// shared context
ctx context.Context
// sticky error
err error
// issues iterator
issue *issueIterator
// notes iterator
note *noteIterator
// labelEvent iterator
labelEvent *labelEventIterator
}
// NewIterator create a new iterator
func NewIterator(ctx context.Context, capacity int, projectID, token string, since time.Time) *iterator {
return &iterator{
gc: buildClient(token),
project: projectID,
since: since,
capacity: capacity,
ctx: ctx,
issue: &issueIterator{
index: -1,
page: 1,
},
note: &noteIterator{
index: -1,
page: 1,
},
labelEvent: &labelEventIterator{
index: -1,
page: 1,
},
}
}
// Error return last encountered error
func (i *iterator) Error() error {
return i.err
}
func (i *iterator) getNextIssues() bool {
ctx, cancel := context.WithTimeout(i.ctx, defaultTimeout)
defer cancel()
issues, _, err := i.gc.Issues.ListProjectIssues(
i.project,
&gitlab.ListProjectIssuesOptions{
ListOptions: gitlab.ListOptions{
Page: i.issue.page,
PerPage: i.capacity,
},
Scope: gitlab.String("all"),
UpdatedAfter: &i.since,
Sort: gitlab.String("asc"),
},
gitlab.WithContext(ctx),
)
if err != nil {
i.err = err
return false
}
// if repository doesn't have any issues
if len(issues) == 0 {
return false
}
i.issue.cache = issues
i.issue.index = 0
i.issue.page++
i.note.index = -1
i.note.cache = nil
return true
}
func (i *iterator) NextIssue() bool {
if i.err != nil {
return false
}
if i.ctx.Err() != nil {
return false
}
// first query
if i.issue.cache == nil {
return i.getNextIssues()
}
// move cursor index
if i.issue.index < len(i.issue.cache)-1 {
i.issue.index++
return true
}
return i.getNextIssues()
}
func (i *iterator) IssueValue() *gitlab.Issue {
return i.issue.cache[i.issue.index]
}
func (i *iterator) getNextNotes() bool {
ctx, cancel := context.WithTimeout(i.ctx, defaultTimeout)
defer cancel()
notes, _, err := i.gc.Notes.ListIssueNotes(
i.project,
i.IssueValue().IID,
&gitlab.ListIssueNotesOptions{
ListOptions: gitlab.ListOptions{
Page: i.note.page,
PerPage: i.capacity,
},
Sort: gitlab.String("asc"),
OrderBy: gitlab.String("created_at"),
},
gitlab.WithContext(ctx),
)
if err != nil {
i.err = err
return false
}
if len(notes) == 0 {
i.note.index = -1
i.note.page = 1
i.note.cache = nil
return false
}
i.note.cache = notes
i.note.page++
i.note.index = 0
return true
}
func (i *iterator) NextNote() bool {
if i.err != nil {
return false
}
if i.ctx.Err() != nil {
return false
}
if len(i.note.cache) == 0 {
return i.getNextNotes()
}
// move cursor index
if i.note.index < len(i.note.cache)-1 {
i.note.index++
return true
}
return i.getNextNotes()
}
func (i *iterator) NoteValue() *gitlab.Note {
return i.note.cache[i.note.index]
}
func (i *iterator) getNextLabelEvents() bool {
ctx, cancel := context.WithTimeout(i.ctx, defaultTimeout)
defer cancel()
labelEvents, _, err := i.gc.ResourceLabelEvents.ListIssueLabelEvents(
i.project,
i.IssueValue().IID,
&gitlab.ListLabelEventsOptions{
ListOptions: gitlab.ListOptions{
Page: i.labelEvent.page,
PerPage: i.capacity,
},
},
gitlab.WithContext(ctx),
)
if err != nil {
i.err = err
return false
}
if len(labelEvents) == 0 {
i.labelEvent.page = 1
i.labelEvent.index = -1
i.labelEvent.cache = nil
return false
}
i.labelEvent.cache = labelEvents
i.labelEvent.page++
i.labelEvent.index = 0
return true
}
// because Gitlab
func (i *iterator) NextLabelEvent() bool {
if i.err != nil {
return false
}
if i.ctx.Err() != nil {
return false
}
if len(i.labelEvent.cache) == 0 {
return i.getNextLabelEvents()
}
// move cursor index
if i.labelEvent.index < len(i.labelEvent.cache)-1 {
i.labelEvent.index++
return true
}
return i.getNextLabelEvents()
}
func (i *iterator) LabelEventValue() *gitlab.LabelEvent {
return i.labelEvent.cache[i.labelEvent.index]
}