Skip to content

Commit 4e92a35

Browse files
committed
cmd/releasebot: add modes for making a release tweet programmatically
This allows exercising (and benefiting from improvements offered by) the programmatic tweet creation tasks as soon as the next minor release. The same task will be added and used by relui when possible. For golang/go#40279. Updates golang/go#47403. Change-Id: I8b47f86489e753bea6a767990ff98dd525e668df Reviewed-on: https://go-review.googlesource.com/c/build/+/358899 Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Dmitri Shuralyov <[email protected]> Trust: Alexander Rakoczy <[email protected]> Reviewed-by: Alexander Rakoczy <[email protected]>
1 parent c9fe2cc commit 4e92a35

File tree

1 file changed

+84
-5
lines changed

1 file changed

+84
-5
lines changed

cmd/releasebot/main.go

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"context"
1212
"crypto/sha1"
1313
"crypto/sha256"
14+
"encoding/json"
1415
"errors"
1516
"flag"
1617
"fmt"
@@ -30,6 +31,7 @@ import (
3031
"golang.org/x/build/buildenv"
3132
"golang.org/x/build/internal/envutil"
3233
"golang.org/x/build/internal/task"
34+
"golang.org/x/build/internal/workflow"
3335
"golang.org/x/build/maintner"
3436
)
3537

@@ -69,13 +71,19 @@ var releaseTargets = []Target{
6971
}
7072

7173
var releaseModes = map[string]bool{
72-
"prepare": true,
73-
"release": true,
74+
"prepare": true,
75+
"release": true,
76+
7477
"mail-dl-cl": true,
78+
79+
"tweet-minor": true,
80+
"tweet-beta": true,
81+
"tweet-rc": true,
82+
"tweet-major": true,
7583
}
7684

7785
func usage() {
78-
fmt.Fprintln(os.Stderr, "usage: releasebot -mode {prepare|release|mail-dl-cl} [-security] [-dry-run] {go1.8.5|go1.10beta2|go1.11rc1}")
86+
fmt.Fprintln(os.Stderr, "usage: releasebot -mode {prepare|release|mail-dl-cl|tweet-{minor,beta,rc,major}} [-security] [-dry-run] {go1.8.5|go1.10beta2|go1.11rc1}")
7987
flag.PrintDefaults()
8088
os.Exit(2)
8189
}
@@ -101,6 +109,10 @@ func main() {
101109
} else if *modeFlag == "mail-dl-cl" {
102110
mailDLCL()
103111
return
112+
} else if strings.HasPrefix(*modeFlag, "tweet-") {
113+
kind := (*modeFlag)[len("tweet-"):]
114+
postTweet(kind)
115+
return
104116
} else if flag.NArg() != 1 {
105117
fmt.Fprintln(os.Stderr, "need to provide a release name")
106118
usage()
@@ -200,9 +212,11 @@ func mailDLCL() {
200212
}
201213
changeURL, err := task.MailDLCL(context.Background(), versions)
202214
if err != nil {
203-
log.Fatalf(`task.MailDLCL(ctx, %#v) failed: %v
215+
log.Fatalf(`task.MailDLCL(ctx, %#v) failed:
216+
217+
%v
204218
205-
If it's neccessary to perform it manually as a workaround,
219+
If it's necessary to perform it manually as a workaround,
206220
consider the following steps:
207221
208222
git clone https://go.googlesource.com/dl && cd dl
@@ -216,6 +230,71 @@ Discuss with the secondary release coordinator as needed.`, versions, err)
216230
fmt.Printf("\nPlease review and submit %s\nand then refer to the playbook for the next steps.\n\n", changeURL)
217231
}
218232

233+
// postTweet parses command-line arguments for the tweet-* modes,
234+
// and runs it.
235+
// kind must be one of "minor", "beta", "rc", or "major".
236+
func postTweet(kind string) {
237+
if flag.NArg() != 1 {
238+
fmt.Fprintln(os.Stderr, "need to provide 1 release tweet JSON object")
239+
usage()
240+
}
241+
var tweet task.ReleaseTweet
242+
err := json.Unmarshal([]byte(flag.Arg(0)), &tweet)
243+
if err != nil {
244+
log.Fatalln("error parsing release tweet JSON object:", err)
245+
}
246+
247+
versions := []string{tweet.Version}
248+
if tweet.SecondaryVersion != "" {
249+
versions = append(versions, tweet.SecondaryVersion+" (secondary)")
250+
}
251+
fmt.Printf("About to tweet about the release of the following Go versions:\n\n\t• %s\n\n", strings.Join(versions, "\n\t• "))
252+
if tweet.Security != "" {
253+
fmt.Printf("with the following security sentence (%d characters long):\n\n\t%s\n\n", len([]rune(tweet.Security)), tweet.Security)
254+
} else {
255+
fmt.Print("with no security fixes being mentioned,\n\n")
256+
}
257+
if tweet.Announcement != "" {
258+
fmt.Printf("and with the following announcement URL:\n\n\t%s\n\n", tweet.Announcement)
259+
}
260+
fmt.Print("Ok? (Y/n) ")
261+
var response string
262+
_, err = fmt.Scanln(&response)
263+
if err != nil {
264+
log.Fatalln(err)
265+
}
266+
if response != "Y" && response != "y" {
267+
log.Fatalln("stopped as requested")
268+
}
269+
tweetRelease := map[string]func(workflow.TaskContext, task.ReleaseTweet, bool) (string, error){
270+
"minor": task.TweetMinorRelease,
271+
"beta": task.TweetBetaRelease,
272+
"rc": task.TweetRCRelease,
273+
"major": task.TweetMajorRelease,
274+
}[kind]
275+
tweetURL, err := tweetRelease(workflow.TaskContext{Context: context.Background(), Logger: log.Default()}, tweet, dryRun)
276+
if errors.Is(err, task.ErrTweetTooLong) && len([]rune(tweet.Security)) > 120 {
277+
log.Fatalf(`A tweet was not created because it's too long.
278+
279+
The provided security sentence is somewhat long (%d characters),
280+
so try making it shorter to avoid exceeding Twitter's limits.`, len([]rune(tweet.Security)))
281+
} else if err != nil {
282+
log.Fatalf(`tweetRelease(ctx, %#v) failed:
283+
284+
%v
285+
286+
If it's necessary to perform it manually as a workaround,
287+
consider the following options:
288+
289+
• use the template displayed in the log above (if any)
290+
• use the same format as the last tweet for the release
291+
of the same kind
292+
293+
Discuss with the secondary release coordinator as needed.`, tweet, err)
294+
}
295+
fmt.Printf("\nPlease check that %s looks okay\nand then refer to the playbook for the next steps.\n\n", tweetURL)
296+
}
297+
219298
// checkForGitCodereview exits the program if git-codereview is not installed
220299
// in the user's path.
221300
func checkForGitCodereview() {

0 commit comments

Comments
 (0)