aboutsummaryrefslogblamecommitdiffstats
path: root/bridge/gitlab/iterator.go
blob: 724d1c73a598712b9d9b4c38420ac9f6ddf58164 (plain) (tree)



















































































































































































































                                                                                    
package gitlab

import (
	"time"

	"github.com/xanzy/go-gitlab"
)

type issueIterator struct {
	page  int
	index int
	cache []*gitlab.Issue
}

type commentIterator struct {
	page  int
	index int
	cache []*gitlab.Note
}

type iterator struct {
	// gitlab api v4 client
	gc *gitlab.Client

	// if since is given the iterator will query only the updated
	// issues after this date
	since time.Time

	// project id
	project string

	// number of issues and notes to query at once
	capacity int

	// sticky error
	err error

	// issues iterator
	issue *issueIterator

	// comments iterator
	comment *commentIterator
}

// NewIterator create a new iterator
func NewIterator(projectID, token string, capacity int, since time.Time) *iterator {
	return &iterator{
		gc:       buildClient(token),
		project:  projectID,
		since:    since,
		capacity: capacity,
		issue: &issueIterator{
			index: -1,
			page:  1,
		},
		comment: &commentIterator{
			index: -1,
			page:  1,
		},
	}
}

// Error return last encountered error
func (i *iterator) Error() error {
	return i.err
}

func (i *iterator) getIssues() ([]*gitlab.Issue, error) {
	scope := "all"
	issues, _, err := i.gc.Issues.ListProjectIssues(
		i.project,
		&gitlab.ListProjectIssuesOptions{
			ListOptions: gitlab.ListOptions{
				Page:    i.issue.page,
				PerPage: i.capacity,
			},
			Scope:        &scope,
			UpdatedAfter: &i.since,
		},
	)

	return issues, err
}

func (i *iterator) NextIssue() bool {
	// first query
	if i.issue.cache == nil {
		issues, err := i.getIssues()
		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++
		return true
	}

	if i.err != nil {
		return false
	}

	// move cursor index
	if i.issue.index < min(i.capacity, len(i.issue.cache)) {
		i.issue.index++
		return true
	}

	// query next issues
	issues, err := i.getIssues()
	if err != nil {
		i.err = err
		return false
	}

	// no more issues to query
	if len(issues) == 0 {
		return false
	}

	i.issue.page++
	i.issue.index = 0
	i.comment.index = 0

	return true
}

func (i *iterator) IssueValue() *gitlab.Issue {
	return i.issue.cache[i.issue.index]
}

func (i *iterator) getComments() ([]*gitlab.Note, error) {
	notes, _, err := i.gc.Notes.ListIssueNotes(
		i.project,
		i.IssueValue().IID,
		&gitlab.ListIssueNotesOptions{
			ListOptions: gitlab.ListOptions{
				Page:    i.issue.page,
				PerPage: i.capacity,
			},
		},
	)

	return notes, err
}

func (i *iterator) NextComment() bool {
	if i.err != nil {
		return false
	}

	if len(i.comment.cache) == 0 {
		// query next issues
		comments, err := i.getComments()
		if err != nil {
			i.err = err
			return false
		}

		if len(comments) == 0 {
			i.comment.index = 0
			i.comment.page = 1
			return false
		}

		i.comment.page++
		i.comment.index = 0

		return true
	}

	// move cursor index
	if i.comment.index < min(i.capacity, len(i.comment.cache)) {
		i.comment.index++
		return true
	}

	// query next issues
	comments, err := i.getComments()
	if err != nil {
		i.err = err
		return false
	}

	if len(comments) == 0 {
		i.comment.index = 0
		i.comment.page = 1
		return false
	}

	i.comment.page++
	i.comment.index = 0

	return false
}

func (i *iterator) CommentValue() *gitlab.Note {
	return i.comment.cache[i.comment.index]
}

func min(a, b int) int {
	if a > b {
		return b
	}

	return a
}