diff options
Diffstat (limited to 'third_party/gerrit-queue/gerrit')
-rw-r--r-- | third_party/gerrit-queue/gerrit/changeset.go | 117 | ||||
-rw-r--r-- | third_party/gerrit-queue/gerrit/client.go | 220 | ||||
-rw-r--r-- | third_party/gerrit-queue/gerrit/serie.go | 112 | ||||
-rw-r--r-- | third_party/gerrit-queue/gerrit/series.go | 126 |
4 files changed, 0 insertions, 575 deletions
diff --git a/third_party/gerrit-queue/gerrit/changeset.go b/third_party/gerrit-queue/gerrit/changeset.go deleted file mode 100644 index f71032a567cb..000000000000 --- a/third_party/gerrit-queue/gerrit/changeset.go +++ /dev/null @@ -1,117 +0,0 @@ -package gerrit - -import ( - "bytes" - "fmt" - - goGerrit "github.com/andygrunwald/go-gerrit" - "github.com/apex/log" -) - -// Changeset represents a single changeset -// Relationships between different changesets are described in Series -type Changeset struct { - changeInfo *goGerrit.ChangeInfo - ChangeID string - Number int - Verified int - CodeReviewed int - Autosubmit int - Submittable bool - CommitID string - ParentCommitIDs []string - OwnerName string - Subject string -} - -// MakeChangeset creates a new Changeset object out of a goGerrit.ChangeInfo object -func MakeChangeset(changeInfo *goGerrit.ChangeInfo) *Changeset { - return &Changeset{ - changeInfo: changeInfo, - ChangeID: changeInfo.ChangeID, - Number: changeInfo.Number, - Verified: labelInfoToInt(changeInfo.Labels["Verified"]), - CodeReviewed: labelInfoToInt(changeInfo.Labels["Code-Review"]), - Autosubmit: labelInfoToInt(changeInfo.Labels["Autosubmit"]), - Submittable: changeInfo.Submittable, - CommitID: changeInfo.CurrentRevision, // yes, this IS the commit ID. - ParentCommitIDs: getParentCommitIDs(changeInfo), - OwnerName: changeInfo.Owner.Name, - Subject: changeInfo.Subject, - } -} - -// IsAutosubmit returns true if the changeset is intended to be -// automatically submitted by gerrit-queue. -// -// This is determined by the Change Owner setting +1 on the -// "Autosubmit" label. -func (c *Changeset) IsAutosubmit() bool { - return c.Autosubmit == 1 -} - -// IsVerified returns true if the changeset passed CI, -// that's when somebody left the Approved (+1) on the "Verified" label -func (c *Changeset) IsVerified() bool { - return c.Verified == 1 -} - -// IsCodeReviewed returns true if the changeset passed code review, -// that's when somebody left the Recommended (+2) on the "Code-Review" label -func (c *Changeset) IsCodeReviewed() bool { - return c.CodeReviewed == 2 -} - -func (c *Changeset) String() string { - var b bytes.Buffer - b.WriteString("Changeset") - b.WriteString(fmt.Sprintf("(commitID: %.7s, author: %s, subject: %s, submittable: %v)", - c.CommitID, c.OwnerName, c.Subject, c.Submittable)) - return b.String() -} - -// FilterChangesets filters a list of Changeset by a given filter function -func FilterChangesets(changesets []*Changeset, f func(*Changeset) bool) []*Changeset { - newChangesets := make([]*Changeset, 0) - for _, changeset := range changesets { - if f(changeset) { - newChangesets = append(newChangesets, changeset) - } else { - log.WithField("changeset", changeset.String()).Debug("dropped by filter") - } - } - return newChangesets -} - -// labelInfoToInt converts a goGerrit.LabelInfo to -2…+2 int -func labelInfoToInt(labelInfo goGerrit.LabelInfo) int { - if labelInfo.Recommended.AccountID != 0 { - return 2 - } - if labelInfo.Approved.AccountID != 0 { - return 1 - } - if labelInfo.Disliked.AccountID != 0 { - return -1 - } - if labelInfo.Rejected.AccountID != 0 { - return -2 - } - return 0 -} - -// getParentCommitIDs returns the parent commit IDs of the goGerrit.ChangeInfo -// There is usually only one parent commit ID, except for merge commits. -func getParentCommitIDs(changeInfo *goGerrit.ChangeInfo) []string { - // obtain the RevisionInfo object - revisionInfo := changeInfo.Revisions[changeInfo.CurrentRevision] - - // obtain the Commit object - commit := revisionInfo.Commit - - commitIDs := make([]string, len(commit.Parents)) - for i, commit := range commit.Parents { - commitIDs[i] = commit.Commit - } - return commitIDs -} diff --git a/third_party/gerrit-queue/gerrit/client.go b/third_party/gerrit-queue/gerrit/client.go deleted file mode 100644 index 314f97281c7e..000000000000 --- a/third_party/gerrit-queue/gerrit/client.go +++ /dev/null @@ -1,220 +0,0 @@ -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", - "SUBMITTABLE", -} - -// IClient defines the gerrit.Client interface -type IClient interface { - Refresh() error - GetHEAD() string - GetBaseURL() string - GetChangesetURL(changeset *Changeset) string - SubmitChangeset(changeset *Changeset) (*Changeset, error) - RebaseChangeset(changeset *Changeset, ref string) (*Changeset, error) - 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 - logger *log.Logger - baseURL string - projectName string - branchName string - series []*Serie - head string -} - -// NewClient initializes a new gerrit client -func NewClient(logger *log.Logger, URL, username, password, projectName, branchName string) (*Client, error) { - urlParsed, err := url.Parse(URL) - if err != nil { - return nil, err - } - urlParsed.User = url.UserPassword(username, password) - - goGerritClient, err := goGerrit.NewClient(urlParsed.String(), nil) - if err != nil { - return nil, err - } - return &Client{ - client: goGerritClient, - baseURL: URL, - logger: logger, - projectName: projectName, - branchName: branchName, - }, nil -} - -// 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.Infof("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 - changes, _, err := c.client.Changes.QueryChanges(opt) - if err != nil { - return nil, err - } - - changesets = make([]*Changeset, 0) - for _, change := range *changes { - changesets = append(changesets, MakeChangeset(&change)) - } - - return changesets, nil -} - -// 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 (c *Client) fetchChangeset(changeID string) (*Changeset, error) { - opt := goGerrit.ChangeOptions{} - opt.AdditionalFields = []string{"LABELS", "DETAILED_ACCOUNTS"} - changeInfo, _, err := c.client.Changes.GetChange(changeID, &opt) - if err != nil { - return nil, err - } - return MakeChangeset(changeInfo), nil -} - -// SubmitChangeset submits a given changeset, and returns a changeset afterwards. -func (c *Client) SubmitChangeset(changeset *Changeset) (*Changeset, error) { - changeInfo, _, err := c.client.Changes.SubmitChange(changeset.ChangeID, &goGerrit.SubmitInput{}) - if err != nil { - return nil, err - } - c.head = changeInfo.CurrentRevision - return c.fetchChangeset(changeInfo.ChangeID) -} - -// RebaseChangeset rebases a given changeset on top of a given ref -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 c.fetchChangeset(changeInfo.ChangeID) -} - -// GetBaseURL returns the gerrit base URL -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 -} diff --git a/third_party/gerrit-queue/gerrit/serie.go b/third_party/gerrit-queue/gerrit/serie.go deleted file mode 100644 index 788cf46f4ea6..000000000000 --- a/third_party/gerrit-queue/gerrit/serie.go +++ /dev/null @@ -1,112 +0,0 @@ -package gerrit - -import ( - "fmt" - "strings" - - "github.com/apex/log" -) - -// Serie represents a list of successive changesets with an unbroken parent -> child relation, -// starting from the parent. -type Serie struct { - ChangeSets []*Changeset -} - -// GetParentCommitIDs returns the parent commit IDs -func (s *Serie) GetParentCommitIDs() ([]string, error) { - if len(s.ChangeSets) == 0 { - return nil, fmt.Errorf("Can't return parent on a serie with zero ChangeSets") - } - return s.ChangeSets[0].ParentCommitIDs, nil -} - -// GetLeafCommitID returns the commit id of the last commit in ChangeSets -func (s *Serie) GetLeafCommitID() (string, error) { - if len(s.ChangeSets) == 0 { - return "", fmt.Errorf("Can't return leaf on a serie with zero ChangeSets") - } - return s.ChangeSets[len(s.ChangeSets)-1].CommitID, nil -} - -// CheckIntegrity checks that the series contains a properly ordered and connected chain of commits -func (s *Serie) CheckIntegrity() error { - logger := log.WithField("serie", s) - // an empty serie is invalid - if len(s.ChangeSets) == 0 { - return fmt.Errorf("An empty serie is invalid") - } - - previousCommitID := "" - for i, changeset := range s.ChangeSets { - // we can't really check the parent of the first commit - // so skip verifying that one - logger.WithFields(log.Fields{ - "changeset": changeset.String(), - "previousCommitID": fmt.Sprintf("%.7s", previousCommitID), - }).Debug(" - verifying changeset") - - parentCommitIDs := changeset.ParentCommitIDs - if len(parentCommitIDs) == 0 { - return fmt.Errorf("Changesets without any parent are not supported") - } - // we don't check parents of the first changeset in a series - if i != 0 { - if len(parentCommitIDs) != 1 { - return fmt.Errorf("Merge commits in the middle of a series are not supported (only at the beginning)") - } - if parentCommitIDs[0] != previousCommitID { - return fmt.Errorf("changesets parent commit id doesn't match previous commit id") - } - } - // update previous commit id for the next loop iteration - previousCommitID = changeset.CommitID - } - return nil -} - -// FilterAllChangesets applies a filter function on all of the changesets in the series. -// returns true if it returns true for all changesets, false otherwise -func (s *Serie) FilterAllChangesets(f func(c *Changeset) bool) bool { - for _, changeset := range s.ChangeSets { - if f(changeset) == false { - return false - } - } - return true -} - -func (s *Serie) String() string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf("Serie[%d]", len(s.ChangeSets))) - if len(s.ChangeSets) == 0 { - sb.WriteString("()\n") - return sb.String() - } - parentCommitIDs, err := s.GetParentCommitIDs() - if err == nil { - if len(parentCommitIDs) == 1 { - sb.WriteString(fmt.Sprintf("(parent: %.7s)", parentCommitIDs[0])) - } else { - sb.WriteString("(merge: ") - - for i, parentCommitID := range parentCommitIDs { - sb.WriteString(fmt.Sprintf("%.7s", parentCommitID)) - if i < len(parentCommitIDs) { - sb.WriteString(", ") - } - } - - sb.WriteString(")") - - } - } - sb.WriteString(fmt.Sprintf("(%.7s..%.7s)", - s.ChangeSets[0].CommitID, - s.ChangeSets[len(s.ChangeSets)-1].CommitID)) - return sb.String() -} - -func shortCommitID(commitID string) string { - return commitID[:6] -} diff --git a/third_party/gerrit-queue/gerrit/series.go b/third_party/gerrit-queue/gerrit/series.go deleted file mode 100644 index 295193ee9503..000000000000 --- a/third_party/gerrit-queue/gerrit/series.go +++ /dev/null @@ -1,126 +0,0 @@ -package gerrit - -import ( - "sort" - - "github.com/apex/log" -) - -// AssembleSeries consumes a list of `Changeset`, and groups them together to series -// -// We initially put every Changeset in its own Serie -// -// As we have no control over the order of the passed changesets, -// we maintain a lookup table, mapLeafToSerie, -// which allows to lookup a serie by its leaf commit id -// We concat series in a fixpoint approach -// because both appending and prepending is much more complex. -// Concatenation moves changesets of the later changeset in the previous one -// in a cleanup phase, we remove orphaned series (those without any changesets inside) -// afterwards, we do an integrity check, just to be on the safe side. -func AssembleSeries(changesets []*Changeset, logger *log.Logger) ([]*Serie, error) { - series := make([]*Serie, 0) - mapLeafToSerie := make(map[string]*Serie, 0) - - for _, changeset := range changesets { - l := logger.WithField("changeset", changeset.String()) - - l.Debug("creating initial serie") - serie := &Serie{ - ChangeSets: []*Changeset{changeset}, - } - series = append(series, serie) - mapLeafToSerie[changeset.CommitID] = serie - } - - // Combine series using a fixpoint approach, with a max iteration count. - logger.Debug("glueing together phase") - for i := 1; i < 100; i++ { - didUpdate := false - logger.Debugf("at iteration %d", i) - for j, serie := range series { - l := logger.WithFields(log.Fields{ - "i": i, - "j": j, - "serie": serie.String(), - }) - parentCommitIDs, err := serie.GetParentCommitIDs() - if err != nil { - return series, err - } - if len(parentCommitIDs) != 1 { - // We can't append merge commits to other series - l.Infof("No single parent, skipping.") - continue - } - parentCommitID := parentCommitIDs[0] - l.Debug("Looking for a predecessor.") - // if there's another serie that has this parent as a leaf, glue together - if otherSerie, ok := mapLeafToSerie[parentCommitID]; ok { - if otherSerie == serie { - continue - } - l = l.WithField("otherSerie", otherSerie) - - myLeafCommitID, err := serie.GetLeafCommitID() - if err != nil { - return series, err - } - - // append our changesets to the other serie - l.Debug("Splicing together.") - otherSerie.ChangeSets = append(otherSerie.ChangeSets, serie.ChangeSets...) - - delete(mapLeafToSerie, parentCommitID) - mapLeafToSerie[myLeafCommitID] = otherSerie - - // orphan our serie - serie.ChangeSets = []*Changeset{} - // remove the orphaned serie from the lookup table - delete(mapLeafToSerie, myLeafCommitID) - - didUpdate = true - } else { - l.Debug("Not found.") - } - } - series = removeOrphanedSeries(series) - if !didUpdate { - logger.Infof("converged after %d iterations", i) - break - } - } - - // Check integrity, just to be on the safe side. - for _, serie := range series { - l := logger.WithField("serie", serie.String()) - l.Debugf("checking integrity") - err := serie.CheckIntegrity() - if err != nil { - l.Errorf("checking integrity failed: %s", err) - } - } - return series, nil -} - -// removeOrphanedSeries removes all empty series (that contain zero changesets) -func removeOrphanedSeries(series []*Serie) []*Serie { - newSeries := []*Serie{} - for _, serie := range series { - if len(serie.ChangeSets) != 0 { - newSeries = append(newSeries, serie) - } - } - return newSeries -} - -// SortSeries sorts a list of series by the number of changesets in each serie, descending -func SortSeries(series []*Serie) []*Serie { - newSeries := make([]*Serie, len(series)) - copy(newSeries, series) - sort.Slice(newSeries, func(i, j int) bool { - // the weight depends on the amount of changesets series changeset size - return len(series[i].ChangeSets) > len(series[j].ChangeSets) - }) - return newSeries -} |