about summary refs log tree commit diff
path: root/gerrit/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit/client.go')
-rw-r--r--gerrit/client.go173
1 files changed, 139 insertions, 34 deletions
diff --git a/gerrit/client.go b/gerrit/client.go
index c65b5016c1ff..fd8a244151ab 100644
--- a/gerrit/client.go
+++ b/gerrit/client.go
@@ -1,35 +1,52 @@
 package gerrit
 
 import (
+	"fmt"
+
 	goGerrit "github.com/andygrunwald/go-gerrit"
+	"github.com/apex/log"
 
 	"net/url"
 )
 
 // passed to gerrit when retrieving changesets
-var additionalFields = []string{"LABELS", "CURRENT_REVISION", "CURRENT_COMMIT", "DETAILED_ACCOUNTS"}
+var additionalFields = []string{
+	"LABELS",
+	"CURRENT_REVISION",
+	"CURRENT_COMMIT",
+	"DETAILED_ACCOUNTS",
+}
 
 // IClient defines the gerrit.Client interface
 type IClient interface {
-	SearchChangesets(queryString string) (changesets []*Changeset, Error error)
-	GetHEAD(projectName string, branchName string) (string, error)
-	GetChangeset(changeID string) (*Changeset, error)
+	Refresh() error
+	GetHEAD() string
+	GetBaseURL() string
+	GetChangesetURL(changeset *Changeset) string
 	SubmitChangeset(changeset *Changeset) (*Changeset, error)
 	RebaseChangeset(changeset *Changeset, ref string) (*Changeset, error)
 	RemoveTag(changeset *Changeset, tag string) (*Changeset, error)
-	GetBaseURL() string
+	ChangesetIsRebasedOnHEAD(changeset *Changeset) bool
+	SerieIsRebasedOnHEAD(serie *Serie) bool
+	FilterSeries(filter func(s *Serie) bool) []*Serie
+	FindSerie(filter func(s *Serie) bool) *Serie
 }
 
 var _ IClient = &Client{}
 
 // Client provides some ways to interact with a gerrit instance
 type Client struct {
-	client  *goGerrit.Client
-	baseURL string
+	client      *goGerrit.Client
+	logger      *log.Logger
+	baseURL     string
+	projectName string
+	branchName  string
+	series      []*Serie
+	head        string
 }
 
 // NewClient initializes a new gerrit client
-func NewClient(URL, username, password string) (*Client, error) {
+func NewClient(logger *log.Logger, URL, username, password, projectName, branchName string) (*Client, error) {
 	urlParsed, err := url.Parse(URL)
 	if err != nil {
 		return nil, err
@@ -43,17 +60,58 @@ func NewClient(URL, username, password string) (*Client, error) {
 	return &Client{
 		client:  goGerritClient,
 		baseURL: URL,
+		logger:  logger,
 	}, nil
 }
 
-// SearchChangesets fetches a list of changesets matching a passed query string
-func (gerrit *Client) SearchChangesets(queryString string) (changesets []*Changeset, Error error) {
+// refreshHEAD queries the commit ID of the selected project and branch
+func (c *Client) refreshHEAD() (string, error) {
+	branchInfo, _, err := c.client.Projects.GetBranch(c.projectName, c.branchName)
+	if err != nil {
+		return "", err
+	}
+	return branchInfo.Revision, nil
+}
+
+// GetHEAD returns the internally stored HEAD
+func (c *Client) GetHEAD() string {
+	return c.head
+}
+
+// Refresh causes the client to refresh internal view of gerrit
+func (c *Client) Refresh() error {
+	c.logger.Debug("refreshing from gerrit")
+	HEAD, err := c.refreshHEAD()
+	if err != nil {
+		return err
+	}
+	c.head = HEAD
+
+	var queryString = fmt.Sprintf("status:open project:%s branch:%s", c.projectName, c.branchName)
+	c.logger.Debugf("fetching changesets: %s", queryString)
+	changesets, err := c.fetchChangesets(queryString)
+	if err != nil {
+		return err
+	}
+
+	c.logger.Warnf("assembling series…")
+	series, err := AssembleSeries(changesets, c.logger)
+	if err != nil {
+		return err
+	}
+	series = SortSeries(series)
+	c.series = series
+	return nil
+}
+
+// fetchChangesets fetches a list of changesets matching a passed query string
+func (c *Client) fetchChangesets(queryString string) (changesets []*Changeset, Error error) {
 	opt := &goGerrit.QueryChangeOptions{}
 	opt.Query = []string{
 		queryString,
 	}
-	opt.AdditionalFields = additionalFields //TODO: check DETAILED_ACCOUNTS is needed
-	changes, _, err := gerrit.client.Changes.QueryChanges(opt)
+	opt.AdditionalFields = additionalFields
+	changes, _, err := c.client.Changes.QueryChanges(opt)
 	if err != nil {
 		return nil, err
 	}
@@ -66,22 +124,13 @@ func (gerrit *Client) SearchChangesets(queryString string) (changesets []*Change
 	return changesets, nil
 }
 
-// GetHEAD returns the commit ID of a selected branch
-func (gerrit *Client) GetHEAD(projectName string, branchName string) (string, error) {
-	branchInfo, _, err := gerrit.client.Projects.GetBranch(projectName, branchName)
-	if err != nil {
-		return "", err
-	}
-	return branchInfo.Revision, nil
-}
-
-// GetChangeset downloads an existing Changeset from gerrit, by its ID
+// fetchChangeset downloads an existing Changeset from gerrit, by its ID
 // Gerrit's API is a bit sparse, and only returns what you explicitly ask it
 // This is used to refresh an existing changeset with more data.
-func (gerrit *Client) GetChangeset(changeID string) (*Changeset, error) {
+func (c *Client) fetchChangeset(changeID string) (*Changeset, error) {
 	opt := goGerrit.ChangeOptions{}
 	opt.AdditionalFields = []string{"LABELS", "DETAILED_ACCOUNTS"}
-	changeInfo, _, err := gerrit.client.Changes.GetChange(changeID, &opt)
+	changeInfo, _, err := c.client.Changes.GetChange(changeID, &opt)
 	if err != nil {
 		return nil, err
 	}
@@ -89,28 +138,30 @@ func (gerrit *Client) GetChangeset(changeID string) (*Changeset, error) {
 }
 
 // SubmitChangeset submits a given changeset, and returns a changeset afterwards.
-func (gerrit *Client) SubmitChangeset(changeset *Changeset) (*Changeset, error) {
-	changeInfo, _, err := gerrit.client.Changes.SubmitChange(changeset.ChangeID, &goGerrit.SubmitInput{})
+// TODO: update HEAD
+func (c *Client) SubmitChangeset(changeset *Changeset) (*Changeset, error) {
+	changeInfo, _, err := c.client.Changes.SubmitChange(changeset.ChangeID, &goGerrit.SubmitInput{})
 	if err != nil {
 		return nil, err
 	}
-	return gerrit.GetChangeset(changeInfo.ChangeID)
+	return c.fetchChangeset(changeInfo.ChangeID)
 }
 
 // RebaseChangeset rebases a given changeset on top of a given ref
-func (gerrit *Client) RebaseChangeset(changeset *Changeset, ref string) (*Changeset, error) {
-	changeInfo, _, err := gerrit.client.Changes.RebaseChange(changeset.ChangeID, &goGerrit.RebaseInput{
+// TODO: update HEAD
+func (c *Client) RebaseChangeset(changeset *Changeset, ref string) (*Changeset, error) {
+	changeInfo, _, err := c.client.Changes.RebaseChange(changeset.ChangeID, &goGerrit.RebaseInput{
 		Base: ref,
 	})
 	if err != nil {
 		return changeset, err
 	}
-	return gerrit.GetChangeset(changeInfo.ChangeID)
+	return c.fetchChangeset(changeInfo.ChangeID)
 }
 
 // RemoveTag removes the submit queue tag from a changeset and updates gerrit
 // we never add, that's something users should do in the GUI.
-func (gerrit *Client) RemoveTag(changeset *Changeset, tag string) (*Changeset, error) {
+func (c *Client) RemoveTag(changeset *Changeset, tag string) (*Changeset, error) {
 	hashTags := changeset.HashTags
 	newHashTags := []string{}
 	for _, hashTag := range hashTags {
@@ -118,12 +169,66 @@ func (gerrit *Client) RemoveTag(changeset *Changeset, tag string) (*Changeset, e
 			newHashTags = append(newHashTags, hashTag)
 		}
 	}
-	// TODO: implement set hashtags api in go-gerrit and use here
+	// TODO: implement setting hashtags api in go-gerrit and use here
 	// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#set-hashtags
 	return changeset, nil
 }
 
 // GetBaseURL returns the gerrit base URL
-func (gerrit *Client) GetBaseURL() string {
-	return gerrit.baseURL
+func (c *Client) GetBaseURL() string {
+	return c.baseURL
+}
+
+// GetProjectName returns the configured gerrit project name
+func (c *Client) GetProjectName() string {
+	return c.projectName
+}
+
+// GetBranchName returns the configured gerrit branch name
+func (c *Client) GetBranchName() string {
+	return c.branchName
+}
+
+// GetChangesetURL returns the URL to view a given changeset
+func (c *Client) GetChangesetURL(changeset *Changeset) string {
+	return fmt.Sprintf("%s/c/%s/+/%d", c.GetBaseURL(), c.projectName, changeset.Number)
+}
+
+// ChangesetIsRebasedOnHEAD returns true if the changeset is rebased on the current HEAD
+func (c *Client) ChangesetIsRebasedOnHEAD(changeset *Changeset) bool {
+	if len(changeset.ParentCommitIDs) != 1 {
+		return false
+	}
+	return changeset.ParentCommitIDs[0] == c.head
+}
+
+// SerieIsRebasedOnHEAD returns true if the whole series is rebased on the current HEAD
+// this is already the case if the first changeset in the series is rebased on the current HEAD
+func (c *Client) SerieIsRebasedOnHEAD(serie *Serie) bool {
+	// an empty serie should not exist
+	if len(serie.ChangeSets) == 0 {
+		return false
+	}
+	return c.ChangesetIsRebasedOnHEAD(serie.ChangeSets[0])
+}
+
+// FilterSeries returns a subset of all Series, passing the given filter function
+func (c *Client) FilterSeries(filter func(s *Serie) bool) []*Serie {
+	matchedSeries := []*Serie{}
+	for _, serie := range c.series {
+		if filter(serie) {
+			matchedSeries = append(matchedSeries, serie)
+		}
+	}
+	return matchedSeries
+}
+
+// FindSerie returns the first serie that matches the filter, or nil if none was found
+func (c *Client) FindSerie(filter func(s *Serie) bool) *Serie {
+	for _, serie := range c.series {
+		if filter(serie) {
+			return serie
+		}
+	}
+	return nil
 }