Skip to content

Commit

Permalink
cmd/gopherbot: add "close luci-config issues" task
Browse files Browse the repository at this point in the history
The "close luci-config issues" task is based on the "close cherry pick
issues" task and exists for the same reason. For example, the Go issue
go.dev/issue/63482 should've been closed when https://go.dev/cl/586036
was submitted (since it had a "Fixes golang/go#63482." line), but that
didn't happen because it was submitted to the luci-config branch.

While here, update the "close cherry pick issues" task message to note
the CL number in its closing message too. Also access the scratch repo
directly in abandonScratchReviews without using a loop (for simplicity
and consistency).

Tested with go run . -dry-run -only-run="close luci-config issues" but
with the 'monthAgo' optimization temporarily left out.

Change-Id: I363842e97ab8867afb1933ab97a4e64e0aceeb17
Reviewed-on: https://go-review.googlesource.com/c/build/+/597435
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Carlos Amedee <[email protected]>
Auto-Submit: Dmitri Shuralyov <[email protected]>
Reviewed-by: Dmitri Shuralyov <[email protected]>
  • Loading branch information
dmitshur authored and gopherbot committed Jul 12, 2024
1 parent 59576ec commit 0b82a20
Showing 1 changed file with 58 additions and 23 deletions.
81 changes: 58 additions & 23 deletions cmd/gopherbot/gopherbot.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ var tasks = []struct {
{"handle telemetry issues", (*gopherbot).handleTelemetryIssues},
{"open cherry pick issues", (*gopherbot).openCherryPickIssues},
{"close cherry pick issues", (*gopherbot).closeCherryPickIssues},
{"close luci-config issues", (*gopherbot).closeLUCIConfigIssues},
{"set subrepo milestones", (*gopherbot).setSubrepoMilestones},
{"set misc milestones", (*gopherbot).setMiscMilestones},
{"apply minor release milestones", (*gopherbot).setMinorMilestones},
Expand Down Expand Up @@ -1859,7 +1860,7 @@ func (b *gopherbot) setMinorMilestones(ctx context.Context) error {
}

// closeCherryPickIssues closes cherry-pick issues when CLs are merged to
// release branches, as GitHub only does that on merge to master.
// release branches, as GitHub only does that on merge to the main branch.
func (b *gopherbot) closeCherryPickIssues(ctx context.Context) error {
cherryPickIssues := make(map[int32]*maintner.GitHubIssue) // by GitHub Issue Number
b.foreachIssue(b.gorepo, open, func(gi *maintner.GitHubIssue) error {
Expand Down Expand Up @@ -1902,7 +1903,7 @@ func (b *gopherbot) closeCherryPickIssues(ctx context.Context) error {
}
printIssue("close-cherry-pick", ref.Repo.ID(), gi)
if err := b.addGitHubComment(ctx, ref.Repo, gi.Number, fmt.Sprintf(
"Closed by merging %s to %s.", cl.Commit.Hash, cl.Branch())); err != nil {
"Closed by merging [CL %d](https://go.dev/cl/%d) (commit %s) to `%s`.", cl.Number, cl.Number, cl.Commit.Hash, cl.Branch())); err != nil {
return err
}
return b.closeGitHubIssue(ctx, ref.Repo.ID(), gi.Number, completed)
Expand All @@ -1912,6 +1913,43 @@ func (b *gopherbot) closeCherryPickIssues(ctx context.Context) error {
})
}

// closeLUCIConfigIssues closes specified issues when CLs are merged to the
// luci-config branch, as GitHub only does that on merge to the main branch.
func (b *gopherbot) closeLUCIConfigIssues(ctx context.Context) error {
buildProject := b.corpus.Gerrit().Project("go.googlesource.com", "build")
if buildProject == nil {
return fmt.Errorf("no go.googlesource.com/build Gerrit project in corpus")
}
monthAgo := time.Now().Add(-30 * 24 * time.Hour)
return buildProject.ForeachCLUnsorted(func(cl *maintner.GerritCL) error {
if cl.Commit.CommitTime.Before(monthAgo) {
// If the CL was last updated over a month ago, assume (as an
// optimization) that gopherbot already processed this CL.
return nil
}
if cl.Status != "merged" || cl.Private || cl.Branch() != "luci-config" {
return nil
}
for _, ref := range cl.GitHubIssueRefs {
if ref.Repo != b.gorepo {
continue
}
gi := b.gorepo.Issue(ref.Number)
if gi == nil || gi.NotExist || gi.PullRequest || gi.Locked || b.deletedIssues[githubIssue{ref.Repo.ID(), gi.Number}] ||
gi.Closed || gi.HasEvent("reopened") || !strings.Contains(cl.Commit.Msg, fmt.Sprintf("\nFixes golang/go#%d", gi.Number)) {
continue
}
printIssue("close luci-config issues", ref.Repo.ID(), gi)
if err := b.addGitHubComment(ctx, ref.Repo, gi.Number, fmt.Sprintf(
"Closed by merging [CL %d](https://go.dev/cl/%d) (commit %s@%s) to `%s`.", cl.Number, cl.Number, ref.Repo.ID(), cl.Commit.Hash, cl.Branch())); err != nil {
return err
}
return b.closeGitHubIssue(ctx, ref.Repo.ID(), gi.Number, completed)
}
return nil
})
}

type labelCommand struct {
action string // "add" or "remove"
label string // the label name
Expand Down Expand Up @@ -2129,11 +2167,11 @@ var assignReviewersOptOut = map[string]bool{
// using the go.dev/s/owners API.
func (b *gopherbot) assignReviewersToCLs(ctx context.Context) error {
const tagNoOwners = "no-owners"
b.corpus.Gerrit().ForeachProjectUnsorted(func(gp *maintner.GerritProject) error {
return 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 {
return gp.ForeachOpenCL(func(cl *maintner.GerritCL) error {
if cl.Private || cl.WorkInProgress() || time.Since(cl.Created) < 10*time.Minute {
return nil
}
Expand Down Expand Up @@ -2235,9 +2273,7 @@ func (b *gopherbot) assignReviewersToCLs(ctx context.Context) error {
}
return nil
})
return nil
})
return nil
}

func sameReviewers(reviewers []string, review gerrit.ReviewInput) bool {
Expand Down Expand Up @@ -2274,26 +2310,25 @@ outer:

// abandonScratchReviews abandons Gerrit CLs in the "scratch" project if they've been open for over a week.
func (b *gopherbot) abandonScratchReviews(ctx context.Context) error {
scratchProject := b.corpus.Gerrit().Project("go.googlesource.com", "scratch")
if scratchProject == nil {
return fmt.Errorf("no go.googlesource.com/scratch Gerrit project in corpus")
}
tooOld := time.Now().Add(-24 * time.Hour * 7)
return b.corpus.Gerrit().ForeachProjectUnsorted(func(gp *maintner.GerritProject) error {
if gp.Project() != "scratch" || gp.Server() != "go.googlesource.com" {
return scratchProject.ForeachOpenCL(func(cl *maintner.GerritCL) error {
if b.deletedChanges[gerritChange{scratchProject.Project(), cl.Number}] || !cl.Meta.Commit.CommitTime.Before(tooOld) {
return nil
}
return gp.ForeachOpenCL(func(cl *maintner.GerritCL) error {
if b.deletedChanges[gerritChange{gp.Project(), cl.Number}] || !cl.Meta.Commit.CommitTime.Before(tooOld) {
return nil
}
if *dryRun {
log.Printf("[dry-run] would've closed scratch CL https://go.dev/cl/%d ...", cl.Number)
return nil
}
log.Printf("closing scratch CL https://go.dev/cl/%d ...", cl.Number)
err := b.gerrit.AbandonChange(ctx, fmt.Sprint(cl.Number), "Auto-abandoning old scratch review.")
if err != nil && strings.Contains(err.Error(), "404 Not Found") {
return nil
}
return err
})
if *dryRun {
log.Printf("[dry-run] would've closed scratch CL https://go.dev/cl/%d ...", cl.Number)
return nil
}
log.Printf("closing scratch CL https://go.dev/cl/%d ...", cl.Number)
err := b.gerrit.AbandonChange(ctx, fmt.Sprint(cl.Number), "Auto-abandoning old scratch review.")
if err != nil && strings.Contains(err.Error(), "404 Not Found") {
return nil
}
return err
})
}

Expand Down

0 comments on commit 0b82a20

Please sign in to comment.