cmd/gopherbot: consider Kokoro to be a bot
We're using a distinct Gerrit account to post Kokoro CI results.
Add it to the list of known bots to stop treating it as a human
reviewer.
Also future-proof a little by considering any Gerrit account with the
SERVICE_USER tag to be a bot, since all bot accounts are expected¹ to
be a part of that group.
¹ https://gerrit-review.googlesource.com/Documentation/user-attention-set.html#_important_note_for_all_host_owners_project_owners_and_bot_owners
For golang/go#38906.
Change-Id: If33def5b73fdaadec81b6fdc03a0eaf3042f8095
Reviewed-on: https://go-review.googlesource.com/c/build/+/401514
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index 84a9ed8..0edbf3d 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -2291,6 +2291,7 @@
const (
gobotID = 5976
gerritbotID = 12446
+ kokoroID = 37747
)
// 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
@@ -2315,15 +2316,30 @@
log.Printf("Could not list reviewers on change %q: %v", change.ID(), err)
return nil, true
}
- var count int
var ids []string
for _, r := range reviewers {
- if r.NumericID != gobotID && r.NumericID != gerritbotID && r.NumericID != ownerID {
- ids = append(ids, strconv.FormatInt(r.NumericID, 10))
- count++
+ switch id := r.NumericID; {
+ case id == gobotID, id == gerritbotID, id == kokoroID,
+ hasServiceUserTag(r.AccountInfo):
+ // Skip bots.
+ continue
+ case id == ownerID:
+ // Skip owner.
+ continue
+ }
+ ids = append(ids, strconv.FormatInt(r.NumericID, 10))
+ }
+ return ids, len(ids) >= minHumans
+}
+
+// hasServiceUserTag reports whether the account has a SERVICE_USER tag.
+func hasServiceUserTag(a gerrit.AccountInfo) bool {
+ for _, t := range a.Tags {
+ if t == "SERVICE_USER" {
+ return true
}
}
- return ids, count >= minHumans
+ return false
}
// autoSubmitCLs submits CLs which are labelled "Auto-Submit", are submittable according to Gerrit,
@@ -2502,6 +2518,7 @@
var (
gobotEmail = "5976" + gerritInstanceID
gerritbotEmail = "12446" + gerritInstanceID
+ kokoroEmail = "37747" + gerritInstanceID
)
var count int
var ids []string
@@ -2514,7 +2531,8 @@
if !strings.HasPrefix(ln, "Reviewer:") && !strings.HasPrefix(ln, "CC:") {
return nil
}
- if !strings.Contains(ln, gobotEmail) && !strings.Contains(ln, gerritbotEmail) {
+ if !strings.Contains(ln, gobotEmail) && !strings.Contains(ln, gerritbotEmail) &&
+ !strings.Contains(ln, kokoroEmail) {
match := reviewerRe.FindStringSubmatch(ln)
if match == nil {
return nil
diff --git a/gerrit/gerrit.go b/gerrit/gerrit.go
index 9fd2d8f..4b6cccc 100644
--- a/gerrit/gerrit.go
+++ b/gerrit/gerrit.go
@@ -286,17 +286,17 @@
// AccountInfo is a Gerrit data structure. It's used both for getting the details
// for a single account, as well as for querying multiple accounts.
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#account-info.
type AccountInfo struct {
- NumericID int64 `json:"_account_id"`
- Name string `json:"name,omitempty"`
- Email string `json:"email,omitempty"`
- Username string `json:"username,omitempty"`
+ NumericID int64 `json:"_account_id"`
+ Name string `json:"name,omitempty"`
+ Email string `json:"email,omitempty"`
+ Username string `json:"username,omitempty"`
+ Tags []string `json:"tags,omitempty"`
// MoreAccounts is set on the last account from QueryAccounts if
// the result set is truncated by an 'n' parameter (or has more).
MoreAccounts bool `json:"_more_accounts"`
-
- // TODO: "avatars" is also returned, but not added here yet (add if required)
}
func (ai *AccountInfo) Equal(v *AccountInfo) bool {