tools: Add more functionality to gerrit package

Add Patchset.RefsChanges(). Returns the 'refs/changes/X/Y/Z' string
for the given patchset.

Add []FileComment parameter to Gerrit.Comment(), allowing the posting
of comments on particular lines of the change.

Bug: dawn:1342
Change-Id: Ia4113a158b285c606b2c6c520cef6c9e8030fae7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/88314
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Ben Clayton
2022-04-29 15:15:43 +00:00
committed by Dawn LUCI CQ
parent ff17945946
commit 526087bde7
4 changed files with 137 additions and 60 deletions

View File

@@ -75,6 +75,18 @@ func (p *Patchset) RegisterFlags(defaultHost, defaultProject string) {
flag.IntVar(&p.Patchset, "ps", 0, "gerrit patchset id")
}
// RefsChanges returns the gerrit 'refs/changes/X/Y/Z' string for the patchset
func (p Patchset) RefsChanges() string {
// https://gerrit-review.googlesource.com/Documentation/intro-user.html
// A change ref has the format refs/changes/X/Y/Z where X is the last two
// digits of the change number, Y is the entire change number, and Z is the
// patch set. For example, if the change number is 263270, the ref would be
// refs/changes/70/263270/2 for the second patch set.
shortChange := fmt.Sprintf("%.2v", p.Change)
shortChange = shortChange[len(shortChange)-2:]
return fmt.Sprintf("refs/changes/%v/%v/%v", shortChange, p.Change, p.Patchset)
}
// LoadCredentials attempts to load the gerrit credentials for the given gerrit
// URL from the git cookies file. Returns an empty Credentials on failure.
func LoadCredentials(url string) Credentials {
@@ -200,19 +212,67 @@ func (g *Gerrit) LatestPatchest(changeID string) (Patchset, error) {
return ps, nil
}
// CommentSide is an enumerator for specifying which side code-comments should
// be shown.
type CommentSide int
const (
// Left is used to specifiy that code comments should appear on the parent
// change
Left CommentSide = iota
// Right is used to specifiy that code comments should appear on the new
// change
Right
)
// FileComment describes a single comment on a file
type FileComment struct {
Path string // The file path
Side CommentSide // Which side the comment should appear
Line int // The 1-based line number for the comment
Message string // The comment message
}
// Comment posts a review comment on the given patchset.
func (g *Gerrit) Comment(ps Patchset, msg string) error {
_, _, err := g.client.Changes.SetReview(
strconv.Itoa(ps.Change),
strconv.Itoa(ps.Patchset),
&gerrit.ReviewInput{
Message: msg,
})
// If comments is an optional list of file-comments to include in the comment.
func (g *Gerrit) Comment(ps Patchset, msg string, comments []FileComment) error {
input := &gerrit.ReviewInput{
Message: msg,
}
if len(comments) > 0 {
input.Comments = map[string][]gerrit.CommentInput{}
for _, c := range comments {
ci := gerrit.CommentInput{
Line: c.Line,
// Updated: &gerrit.Timestamp{Time: time.Now()},
Message: c.Message,
}
if c.Side == Left {
ci.Side = "PARENT"
} else {
ci.Side = "REVISION"
}
input.Comments[c.Path] = append(input.Comments[c.Path], ci)
}
}
_, _, err := g.client.Changes.SetReview(strconv.Itoa(ps.Change), strconv.Itoa(ps.Patchset), input)
if err != nil {
return g.maybeWrapError(err)
}
return nil
}
// SetReadyForReview marks the change as ready for review.
func (g *Gerrit) SetReadyForReview(changeID, message string) error {
resp, err := g.client.Changes.SetReadyForReview(changeID, &gerrit.ReadyForReviewInput{
Message: message,
})
if err != nil && resp.StatusCode != 409 { // 409: already ready
return g.maybeWrapError(err)
}
return nil
}
func (g *Gerrit) maybeWrapError(err error) error {
if err != nil && !g.authenticated {
return fmt.Errorf(`query failed, possibly because of authentication.

View File

@@ -0,0 +1,64 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gerrit_test
import (
"testing"
"dawn.googlesource.com/dawn/tools/src/gerrit"
"github.com/google/go-cmp/cmp"
)
func TestPatchsetRefsChanges(t *testing.T) {
type Test struct {
in gerrit.Patchset
expect string
}
for _, test := range []Test{
{
in: gerrit.Patchset{
Change: 123456,
Patchset: 42,
},
expect: `refs/changes/56/123456/42`,
},
{
in: gerrit.Patchset{
Change: 1234,
Patchset: 42,
},
expect: `refs/changes/34/1234/42`,
},
{
in: gerrit.Patchset{
Change: 12,
Patchset: 42,
},
expect: `refs/changes/12/12/42`,
},
{
in: gerrit.Patchset{
Change: 1,
Patchset: 42,
},
expect: `refs/changes/01/1/42`,
},
} {
got := test.in.RefsChanges()
if diff := cmp.Diff(got, test.expect); diff != "" {
t.Errorf("%v.RefsChanges() was not as expected:\n%v", test.in, diff)
}
}
}