cmd/gopherbot: table-ify gopherbot tasks, start of daemon mode
Change-Id: I147a806c00e4c0de66b4ae490d838d7a3ac42daf
Reviewed-on: https://go-review.googlesource.com/40971
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index b976519..d412ecd 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -28,6 +28,7 @@
var (
dryRun = flag.Bool("dry-run", false, "just report what would've been done, without changing anything")
+ daemon = flag.Bool("daemon", false, "run in daemon mode")
)
func getGithubToken() (string, error) {
@@ -82,56 +83,29 @@
gorepo: repo,
}
- var fail bool
-
- if err := bot.freezeOldIssues(ctx); err != nil {
- log.Printf("freezing old issues: %v", err)
- fail = true
- }
-
- if err := bot.labelProposals(ctx); err != nil {
- log.Printf("labeling proposals: %v", err)
- fail = true
- }
-
- if err := bot.setSubrepoMilestones(ctx); err != nil {
- log.Printf("setting subrepo milestones: %v", err)
- fail = true
- }
-
- if err := bot.setGccgoMilestones(ctx); err != nil {
- log.Printf("setting gccgo milestones: %v", err)
- fail = true
- }
-
- if err := bot.labelBuildIssues(ctx); err != nil {
- log.Printf("labeling build issues: %v", err)
- fail = true
- }
-
- if err := bot.labelDocumentationIssues(ctx); err != nil {
- log.Printf("labeling documentation issues: %v", err)
- fail = true
- }
-
- if err := bot.closeStaleWaitingForInfo(ctx); err != nil {
- log.Printf("closing stale WaitingForInfo: %v", err)
- fail = true
- }
-
- // "CL nnnn mentions this issue"
- if err := bot.cl2issue(ctx); err != nil {
- log.Printf("cl2issue: %v", err)
- fail = true
- }
-
- if err := bot.checkCherryPicks(ctx); err != nil {
- log.Printf("checking cherry picks: %v", err)
- fail = true
- }
-
- if fail {
- os.Exit(1)
+ for {
+ var nextLoop time.Time
+ err := bot.doTasks(ctx)
+ if err != nil {
+ log.Print(err)
+ nextLoop = time.Now().Add(30 * time.Second)
+ }
+ if !*daemon {
+ if err != nil {
+ os.Exit(1)
+ }
+ return
+ }
+ // TODO: if err != nil, pass a ctx with 30s timeout and retry the doTasks.
+ // Maybe use a better ctx above too.
+ if err := corpus.Update(ctx); err != nil {
+ log.Fatalf("corpus.Update: %v", err)
+ }
+ if nextLoop.After(time.Now()) {
+ sleep := time.Until(nextLoop)
+ log.Printf("Sleeping for %v after previous error.", sleep)
+ time.Sleep(sleep)
+ }
}
}
@@ -141,6 +115,31 @@
gorepo *maintner.GitHubRepo
}
+var tasks = []struct {
+ name string
+ fn func(*gopherbot, context.Context) error
+}{
+ {"freeze old issues", (*gopherbot).freezeOldIssues},
+ {"label proposals", (*gopherbot).labelProposals},
+ {"set subrepo milestones", (*gopherbot).setSubrepoMilestones},
+ {"set gccgo milestones", (*gopherbot).setGccgoMilestones},
+ {"label build issues", (*gopherbot).labelBuildIssues},
+ {"label documentation issues", (*gopherbot).labelDocumentationIssues},
+ {"close stale WaitingForInfo", (*gopherbot).closeStaleWaitingForInfo},
+ {"cl2issue", (*gopherbot).cl2issue},
+ {"check cherry picks", (*gopherbot).checkCherryPicks},
+}
+
+func (b *gopherbot) doTasks(ctx context.Context) error {
+ for _, task := range tasks {
+ if err := task.fn(b, ctx); err != nil {
+ log.Printf("%s: %v", task.name, err)
+ return err
+ }
+ }
+ return nil
+}
+
func (b *gopherbot) addLabel(ctx context.Context, gi *maintner.GitHubIssue, label string) error {
_, _, err := b.ghc.Issues.AddLabelsToIssue(ctx, "golang", "go", int(gi.Number), []string{label})
return err
@@ -467,6 +466,10 @@
return nil
})
if !hasComment {
+ printIssue("cl2issue", gi)
+ if *dryRun {
+ return nil
+ }
if err := b.addGitHubComment(ctx, "golang", "go", gi.Number, fmt.Sprintf("CL https://golang.org/cl/%d mentions this issue.", cl.Number)); err != nil {
return err
}
diff --git a/maintner/maintner.go b/maintner/maintner.go
index 0d3cd87..e3ac6bb 100644
--- a/maintner/maintner.go
+++ b/maintner/maintner.go
@@ -156,7 +156,9 @@
GetMutations(context.Context) <-chan *maintpb.Mutation
}
-// Initialize populates the Corpus using the data from the MutationSource.
+// Initialize populates the Corpus using the data from the
+// MutationSource. It returns once it's up-to-date. To incrementally
+// update it later, use the Update method.
func (c *Corpus) Initialize(ctx context.Context, src MutationSource) error {
ch := src.GetMutations(ctx)
done := ctx.Done()
@@ -180,6 +182,14 @@
}
}
+// Update incrementally updates the corpus from its current state to
+// the latest state from the MutationSource passed earlier to
+// Initialize. It does not return until there's either a new change or
+// the context expires.
+func (c *Corpus) Update(ctx context.Context) error {
+ panic("TODO")
+}
+
// addMutation adds a mutation to the log and immediately processes it.
func (c *Corpus) addMutation(m *maintpb.Mutation) {
if c.Verbose {