in cmd/gopherbot/gopherbot.go [1983:2091]
func (b *gopherbot) assignReviewersToCLs(ctx context.Context) error {
const tagNoOwners = "no-owners"
b.corpus.Gerrit().ForeachProjectUnsorted(func(gp *maintner.GerritProject) error {
if gp.Project() == "scratch" || gp.Server() != "go.googlesource.com" {
return nil
}
gp.ForeachOpenCL(func(cl *maintner.GerritCL) error {
if cl.Private || cl.WorkInProgress() || time.Since(cl.Created) < 10*time.Minute {
return nil
}
if assignReviewersOptOut[cl.Owner().Email()] {
return nil
}
// Don't auto-assign reviewers to CLs on shared branches;
// the presumption is that developers there will know which
// reviewers to assign.
if strings.HasPrefix(cl.Branch(), "dev.") {
return nil
}
tags := cl.Meta.Hashtags()
if tags.Contains(tagNoOwners) {
return nil
}
gc := gerritChange{gp.Project(), cl.Number}
if b.deletedChanges[gc] {
return nil
}
if strutil.ContainsFold(cl.Commit.Msg, "do not submit") || strutil.ContainsFold(cl.Commit.Msg, "do not review") {
return nil
}
currentReviewers, ok := b.humanReviewersOnChange(ctx, gc, cl)
if ok {
return nil
}
changeURL := fmt.Sprintf("https://go-review.googlesource.com/c/%s/+/%d", gp.Project(), cl.Number)
log.Printf("No reviewers or cc: %s", changeURL)
files, err := b.gerrit.ListFiles(ctx, gc.ID(), cl.Commit.Hash.String())
if err != nil {
log.Printf("Could not get change %+v: %v", gc, err)
if httpErr, ok := err.(*gerrit.HTTPError); ok && httpErr.Res.StatusCode == http.StatusNotFound {
b.deletedChanges[gc] = true
}
return nil
}
var paths []string
for f := range files {
if f == "/COMMIT_MSG" {
continue
}
paths = append(paths, gp.Project()+"/"+f)
}
entries, err := getCodeOwners(ctx, paths)
if err != nil {
log.Printf("Could not get owners for change %s: %v", changeURL, err)
return nil
}
authorEmail := cl.Commit.Author.Email()
merged := mergeOwnersEntries(entries, authorEmail)
if len(merged.Primary) == 0 && len(merged.Secondary) == 0 {
// No owners found for the change. Add the #no-owners tag.
log.Printf("Adding no-owners tag to change %s...", changeURL)
if *dryRun {
return nil
}
if _, err := b.gerrit.AddHashtags(ctx, gc.ID(), tagNoOwners); err != nil {
log.Printf("Could not add hashtag to change %q: %v", gc.ID(), err)
return nil
}
return nil
}
// Assign reviewers.
var review gerrit.ReviewInput
for _, owner := range merged.Primary {
review.Reviewers = append(review.Reviewers, gerrit.ReviewerInput{Reviewer: owner.GerritEmail})
}
for _, owner := range merged.Secondary {
review.Reviewers = append(review.Reviewers, gerrit.ReviewerInput{Reviewer: owner.GerritEmail, State: "CC"})
}
// If the reviewers that would be set are the same as the existing
// reviewers (minus the bots), there is no work to be done.
if sameReviewers(currentReviewers, review) {
log.Printf("Setting review %+v on %s would have no effect, continuing", review, changeURL)
return nil
}
if *dryRun {
log.Printf("[dry run] Would set review on %s: %+v", changeURL, review)
return nil
}
log.Printf("Setting review on %s: %+v", changeURL, review)
if err := b.gerrit.SetReview(ctx, gc.ID(), "current", review); err != nil {
log.Printf("Could not set review for change %q: %v", gc.ID(), err)
return nil
}
return nil
})
return nil
})
return nil
}