cmd/gopherbot: fix reviewer assignment for CLs imported from PRs
golang/go#30265 causes Gerrit to add the authors of PRs as reviewers on
the imported CLs. Then, when Gopherbot assigns reviewers to the PR, it
seems a human reviewer already listed, meaning that a lot of CLs never
get assigned reviewers and are then never replied to.
As a work-around for these issues, require two reviewers on all PRs.
Fixes golang/go#31658
Change-Id: I7b3f62194450cba61493d8c4c0ad14320443e641
Reviewed-on: https://go-review.googlesource.com/c/build/+/227977
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index 74a79a3..dcdf684 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -1973,7 +1973,22 @@
// The gerritChange passed must be used because it’s used as a key to deletedChanges and the ID returned
// by cl.ChangeID() can be associated with multiple changes (cherry-picks, for example).
func (b *gopherbot) humanReviewersOnChange(ctx context.Context, change gerritChange, cl *maintner.GerritCL) bool {
- if found := humanReviewersInMetas(cl.Metas); found {
+ const (
+ gobotID = 5976
+ gerritbotID = 12446
+ )
+ // The CL's owner will be GerritBot if it is imported from a PR.
+ // In that case, if the CL's author has a Gerrit account, they will be
+ // added as a reviewer (golang.org/issue/30265). Otherwise, no reviewers
+ // will be added. Work around this by requiring 2 human reviewers on PRs.
+ ownerID := int64(cl.OwnerID())
+ isPR := ownerID == gerritbotID
+ minHumans := 1
+ if isPR {
+ minHumans = 2
+ }
+
+ if found := humanReviewersInMetas(cl.Metas, minHumans); found {
return true
}
@@ -1985,27 +2000,27 @@
log.Printf("Could not list reviewers on change %q: %v", change.ID(), err)
return true
}
-
- const (
- gobotID = 5976
- gerritbotID = 12446
- )
+ var count int
for _, r := range reviewers {
- if r.NumericID != gobotID && r.NumericID != gerritbotID {
- return true
+ if r.NumericID != gobotID && r.NumericID != gerritbotID && r.NumericID != ownerID {
+ count++
+ if count == minHumans {
+ return true
+ }
}
}
return false
}
-func humanReviewersInMetas(metas []*maintner.GerritMeta) bool {
+// humanReviewersInMetas reports whether there are at least minHumans human
+// reviewers in the given metas.
+func humanReviewersInMetas(metas []*maintner.GerritMeta, minHumans int) bool {
// Emails as they appear in maintner (<numeric ID>@<instance ID>)
var (
gobotEmail = "5976@62eb7196-b449-3ce5-99f1-c037f21e1705"
gerritbotEmail = "12446@62eb7196-b449-3ce5-99f1-c037f21e1705"
-
- hasHuman bool
)
+ var count int
for _, m := range metas {
if !strings.Contains(m.Commit.Msg, "Reviewer:") && !strings.Contains(m.Commit.Msg, "CC:") {
continue
@@ -2017,17 +2032,19 @@
}
if !strings.Contains(ln, gobotEmail) && !strings.Contains(ln, gerritbotEmail) {
// A human is already on the change.
- hasHuman = true
- return errStopIteration
+ count++
+ if count == minHumans {
+ return errStopIteration
+ }
}
return nil
})
if err != nil && err != errStopIteration {
log.Printf("humanReviewersInMetas: got unexpected error from foreach.LineStr: %v", err)
- return hasHuman
+ return count >= minHumans
}
}
- return hasHuman
+ return count >= minHumans
}
func getCodeOwners(ctx context.Context, paths []string) ([]*owners.Entry, error) {
diff --git a/cmd/gopherbot/gopherbot_test.go b/cmd/gopherbot/gopherbot_test.go
index 642407c..5af4a08 100644
--- a/cmd/gopherbot/gopherbot_test.go
+++ b/cmd/gopherbot/gopherbot_test.go
@@ -356,33 +356,54 @@
testCases := []struct {
commitMsg string
hasHuman bool
+ atLeast int
}{
{`Patch-set: 6
Reviewer: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
`,
true,
+ 1,
},
{`Patch-set: 6
CC: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
`,
true,
+ 1,
},
{`Patch-set: 6
Reviewer: Gobot Gobot <5976@62eb7196-b449-3ce5-99f1-c037f21e1705>
`,
false,
+ 1,
},
{`Patch-set: 6
Reviewer: Gobot Gobot <5976@62eb7196-b449-3ce5-99f1-c037f21e1705>
CC: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
`,
true,
+ 1,
},
{`Patch-set: 6
Reviewer: Gobot Gobot <5976@62eb7196-b449-3ce5-99f1-c037f21e1705>
Reviewer: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
`,
true,
+ 1,
+ },
+ {`Patch-set: 6
+Reviewer: Gobot Gobot <5976@62eb7196-b449-3ce5-99f1-c037f21e1705>
+Reviewer: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
+ `,
+ false,
+ 2,
+ },
+ {`Patch-set: 6
+Reviewer: Gobot Gobot <5976@62eb7196-b449-3ce5-99f1-c037f21e1705>
+Reviewer: Andrew Bonventre <22285@62eb7196-b449-3ce5-99f1-c037f21e1705>
+Reviewer: Rebecca Stambler <16140@62eb7196-b449-3ce5-99f1-c037f21e1705>
+ `,
+ true,
+ 2,
},
}
@@ -390,7 +411,7 @@
metas := []*maintner.GerritMeta{
{Commit: &maintner.GitCommit{Msg: tc.commitMsg}},
}
- if got, want := humanReviewersInMetas(metas), tc.hasHuman; got != want {
+ if got, want := humanReviewersInMetas(metas, tc.atLeast), tc.hasHuman; got != want {
t.Errorf("Unexpected result for meta commit message: got %v; want %v for\n%s", got, want, tc.commitMsg)
}
}