cmd/gopherbot: add manual mode to dump who needs access
Updates golang/go#19572
Change-Id: Ied3fc5f9e4c72eec5a65151f4d44f57119109367
Reviewed-on: https://go-review.googlesource.com/c/build/+/178702
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index 5a3e7cd..45ef734 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -292,6 +292,7 @@
{"apply labels from comments", (*gopherbot).applyLabelsFromComments},
{"assign reviewers to CLs", (*gopherbot).assignReviewersToCLs},
{"abandon scratch reviews", (*gopherbot).abandonScratchReviews},
+ {"access", (*gopherbot).whoNeedsAccess},
}
func (b *gopherbot) initCorpus() {
@@ -1757,6 +1758,71 @@
})
}
+func (b *gopherbot) whoNeedsAccess(ctx context.Context) error {
+ // We only run this task if it was explicitly requested via
+ // the --only-run flag.
+ if *onlyRun == "" {
+ return nil
+ }
+ level := map[int64]int{} // gerrit id -> 1 for try, 2 for submit
+ ais, err := b.gerrit.GetGroupMembers(ctx, "may-start-trybots")
+ if err != nil {
+ return err
+ }
+ for _, ai := range ais {
+ level[ai.NumericID] = 1
+ }
+ ais, err = b.gerrit.GetGroupMembers(ctx, "approvers")
+ if err != nil {
+ return err
+ }
+ for _, ai := range ais {
+ level[ai.NumericID] = 2
+ }
+
+ quarterAgo := time.Now().Add(-90 * 24 * time.Hour)
+ missing := map[string]int{} // "only level N: $WHO" -> number of CLs for that user
+ err = b.corpus.Gerrit().ForeachProjectUnsorted(func(gp *maintner.GerritProject) error {
+ if gp.Server() != "go.googlesource.com" {
+ return nil
+ }
+ return gp.ForeachCLUnsorted(func(cl *maintner.GerritCL) error {
+ if cl.Meta.Commit.AuthorTime.Before(quarterAgo) {
+ return nil
+ }
+ authorID := int64(cl.OwnerID())
+ if authorID == -1 {
+ return nil
+ }
+ if level[authorID] == 2 {
+ return nil
+ }
+ missing[fmt.Sprintf("only level %d: %v", level[authorID], cl.Commit.Author)]++
+ return nil
+ })
+ })
+ if err != nil {
+ return err
+ }
+ var people []string
+ for who := range missing {
+ people = append(people, who)
+ }
+ sort.Slice(people, func(i, j int) bool { return missing[people[j]] < missing[people[i]] })
+ fmt.Println("Number of CLs created in last 90 days | Access (0=none, 1=trybots) | Author")
+ for i, who := range people {
+ num := missing[who]
+ if num < 3 {
+ break
+ }
+ fmt.Printf("%3d: %s\n", num, who)
+ if i == 20 {
+ break
+ }
+ }
+ return nil
+}
+
// humanReviewersOnChange returns true if there are (or were any) human reviewers in the given change.
// 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).