cmd/gopherbot: add "convert wait-release topic to hashtag" task
The 'wait-release' hashtag has meaning for humans and release tooling.
The 'wait-release' topic can be easy to accidentally apply instead of
the hashtag. Add a task to correct such mistakes automatically.
Change-Id: I290e1b9046c9e18181e41a920c0c02ef9ae72439
Reviewed-on: https://go-review.googlesource.com/c/build/+/588195
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
diff --git a/cmd/gopherbot/gopherbot.go b/cmd/gopherbot/gopherbot.go
index d019dc6..a1b27db 100644
--- a/cmd/gopherbot/gopherbot.go
+++ b/cmd/gopherbot/gopherbot.go
@@ -485,6 +485,7 @@
{"cl2issue", (*gopherbot).cl2issue},
{"congratulate new contributors", (*gopherbot).congratulateNewContributors},
{"un-wait CLs", (*gopherbot).unwaitCLs},
+ {"convert wait-release topic to hashtag", (*gopherbot).topicToHashtag},
}
// gardenIssues reports whether GopherBot should perform general issue
@@ -1627,6 +1628,31 @@
})
}
+// topicToHashtag converts CLs with 'wait-release' topic
+// to the likely intended uses of 'wait-release' hashtag.
+func (b *gopherbot) topicToHashtag(ctx context.Context) error {
+ waitTopicCLs, err := b.gerrit.QueryChanges(ctx, "status:open topic:wait-release")
+ if err != nil {
+ return err
+ }
+ for _, cl := range waitTopicCLs {
+ if *dryRun {
+ log.Printf("[dry run] would replace 'wait-release' topic with hashtag on CL %d (%.32s…)", cl.ChangeNumber, cl.Subject)
+ continue
+ }
+ _, err := b.gerrit.AddHashtags(ctx, cl.ID, "wait-release")
+ if err != nil {
+ return err
+ }
+ err = b.gerrit.DeleteTopic(ctx, cl.ID)
+ if err != nil {
+ return err
+ }
+ log.Printf("https://go.dev/cl/%d: replaced 'wait-release' topic with hashtag", cl.ChangeNumber)
+ }
+ return nil
+}
+
// onLatestCL checks whether cl's metadata is up to date with Gerrit's
// upstream data and, if so, returns f(). If it's out of date, it does
// nothing more and returns nil.
diff --git a/gerrit/gerrit.go b/gerrit/gerrit.go
index de7839b..f626395 100644
--- a/gerrit/gerrit.go
+++ b/gerrit/gerrit.go
@@ -659,7 +659,7 @@
// HashtagsInput is the request body used when modifying a CL's hashtags.
//
-// See https://gerrit-documentation.storage.googleapis.com/Documentation/2.15.1/rest-api-changes.html#hashtags-input
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#hashtags-input
type HashtagsInput struct {
Add []string `json:"add"`
Remove []string `json:"remove"`
@@ -669,7 +669,7 @@
// and removing hashtags in one request. On success it returns the new
// set of hashtags.
//
-// See https://gerrit-documentation.storage.googleapis.com/Documentation/2.15.1/rest-api-changes.html#set-hashtags
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#set-hashtags
func (c *Client) SetHashtags(ctx context.Context, changeID string, hashtags HashtagsInput) ([]string, error) {
var res []string
err := c.do(ctx, &res, "POST", fmt.Sprintf("/changes/%s/hashtags", changeID), reqBodyJSON{&hashtags})
@@ -688,13 +688,20 @@
// GetHashtags returns a CL's current hashtags.
//
-// See https://gerrit-documentation.storage.googleapis.com/Documentation/2.15.1/rest-api-changes.html#get-hashtags
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#get-hashtags
func (c *Client) GetHashtags(ctx context.Context, changeID string) ([]string, error) {
var res []string
err := c.do(ctx, &res, "GET", fmt.Sprintf("/changes/%s/hashtags", changeID))
return res, err
}
+// DeleteTopic deletes the topic of a change.
+//
+// See https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#delete-topic.
+func (c *Client) DeleteTopic(ctx context.Context, changeID string) error {
+ return c.do(ctx, nil, "DELETE", "/changes/"+changeID+"/topic", wantResStatus(http.StatusNoContent))
+}
+
// AbandonChange abandons the given change.
// For the API call, see https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#abandon-change
// The changeID is https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-id
diff --git a/internal/task/version.go b/internal/task/version.go
index a6c01ab..39b05eb 100644
--- a/internal/task/version.go
+++ b/internal/task/version.go
@@ -239,7 +239,7 @@
func (t *VersionTasks) UnwaitWaitReleaseCLs(ctx *workflow.TaskContext) (result struct{}, _ error) {
waitingCLs, err := t.Gerrit.QueryChanges(ctx, "status:open hashtag:wait-release")
if err != nil {
- return struct{}{}, nil
+ return struct{}{}, err
}
ctx.Printf("Processing %d open Gerrit CL with wait-release hashtag.", len(waitingCLs))
for _, cl := range waitingCLs {