Skip to content

Commit a9e5957

Browse files
dmitshurgopherbot
authored andcommitted
cmd/relui, internal/task: add release announcement email workflows
Add workflows for automatically sending Go release announcement emails to the relevant Google Groups mailing lists. Use the Markdown email templates from the previous CL for determining the email content. In the future, these workflows will be merged with the tweet workflows and into workflows that build and publish the release artifacts. Fixes golang/go#47405. Updates golang/go#47404. Fixes golang/go#50864. Change-Id: Id82cd4c18e569a19b9d807125765a31773c5bcca Reviewed-on: https://go-review.googlesource.com/c/build/+/411575 Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Dmitri Shuralyov <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 59c99ab commit a9e5957

File tree

7 files changed

+776
-8
lines changed

7 files changed

+776
-8
lines changed

cmd/relui/deployment-prod.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ spec:
3333
- "--site-title=Go Releases"
3434
- "--site-header-css=Site-header--production"
3535
- "--gerrit-api-secret=secret:symbolic-datum-552/gobot-password"
36+
- "--sendgrid-api-key=secret:symbolic-datum-552/sendgrid-sendonly-api-key"
37+
38+
39+
3640
- "--twitter-api-secret=secret:symbolic-datum-552/twitter-api-secret"
3741
- "--builder-master-key=secret:symbolic-datum-552/builder-master-key"
3842
- "--github-token=secret:symbolic-datum-552/maintner-github-token"

cmd/relui/main.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"log"
1919
"math/rand"
2020
"net/http"
21+
"net/mail"
2122
"net/url"
2223
"strings"
2324
"time"
@@ -57,6 +58,11 @@ func main() {
5758
log.Fatalln(err)
5859
}
5960
gerritAPIFlag := secret.Flag("gerrit-api-secret", "Gerrit API secret to use for workflows that interact with Gerrit.")
61+
var annMail task.AnnounceMailTasks
62+
secret.FlagVar(&annMail.SendGridAPIKey, "sendgrid-api-key", "SendGrid API key for workflows involving sending email.")
63+
addressVarFlag(&annMail.From, "announce-mail-from", "The From address to use for the announcement mail.")
64+
addressVarFlag(&annMail.To, "announce-mail-to", "The To address to use for the announcement mail.")
65+
addressListVarFlag(&annMail.BCC, "announce-mail-bcc", "The BCC address list to use for the announcement mail.")
6066
var twitterAPI secret.TwitterCredentials
6167
secret.JSONVarFlag(&twitterAPI, "twitter-api-secret", "Twitter API secret to use for workflows involving tweeting.")
6268
masterKey := secret.Flag("builder-master-key", "Builder master key")
@@ -102,6 +108,7 @@ func main() {
102108
}
103109
dh := relui.NewDefinitionHolder()
104110
relui.RegisterMailDLCLDefinition(dh, versionTasks)
111+
relui.RegisterAnnounceDefinitions(dh, annMail)
105112
relui.RegisterTweetDefinitions(dh, extCfg)
106113
userPassAuth := buildlet.UserPass{
107114
Username: "user-relui",
@@ -196,3 +203,32 @@ func publishFile(uploadURL string, auth buildlet.UserPass, f *relui.WebsiteFile)
196203
}
197204
return nil
198205
}
206+
207+
// addressVarFlag defines an address flag with specified name and usage string.
208+
// The argument p points to a mail.Address variable in which to store the value of the flag.
209+
func addressVarFlag(p *mail.Address, name, usage string) {
210+
flag.Func(name, usage, func(s string) error {
211+
a, err := mail.ParseAddress(s)
212+
if err != nil {
213+
return err
214+
}
215+
*p = *a
216+
return nil
217+
})
218+
}
219+
220+
// addressListVarFlag defines an address list flag with specified name and usage string.
221+
// The argument p points to a []mail.Address variable in which to store the value of the flag.
222+
func addressListVarFlag(p *[]mail.Address, name, usage string) {
223+
flag.Func(name, usage, func(s string) error {
224+
as, err := mail.ParseAddressList(s)
225+
if err != nil {
226+
return err
227+
}
228+
*p = nil // Clear out the list before appending.
229+
for _, a := range as {
230+
*p = append(*p, *a)
231+
}
232+
return nil
233+
})
234+
}

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ require (
2525
github.com/go-sql-driver/mysql v1.5.0
2626
github.com/golang-migrate/migrate/v4 v4.15.0-beta.3
2727
github.com/golang/protobuf v1.5.2
28-
github.com/google/go-cmp v0.5.7
28+
github.com/google/go-cmp v0.5.8
2929
github.com/google/go-github v17.0.0+incompatible
3030
github.com/google/uuid v1.2.0
3131
github.com/googleapis/gax-go/v2 v2.1.1
@@ -39,8 +39,10 @@ require (
3939
github.com/julienschmidt/httprouter v1.3.0
4040
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
4141
github.com/mattn/go-sqlite3 v1.14.6
42+
github.com/sendgrid/sendgrid-go v3.11.1+incompatible
4243
github.com/shurcooL/githubv4 v0.0.0-20220520033151-0b4e3294ff00
4344
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
45+
github.com/yuin/goldmark v1.4.12
4446
go.opencensus.io v0.23.0
4547
go4.org v0.0.0-20180809161055-417644f6feb5
4648
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
@@ -108,6 +110,7 @@ require (
108110
github.com/prometheus/common v0.15.0 // indirect
109111
github.com/prometheus/procfs v0.2.0 // indirect
110112
github.com/prometheus/statsd_exporter v0.20.0 // indirect
113+
github.com/sendgrid/rest v2.6.9+incompatible // indirect
111114
github.com/shurcooL/graphql v0.0.0-20220520033453-bdb1221e171e // indirect
112115
github.com/sirupsen/logrus v1.8.1 // indirect
113116
go.uber.org/atomic v1.6.0 // indirect

go.sum

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
405405
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
406406
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
407407
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
408-
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
409408
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
409+
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
410+
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
410411
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
411412
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
412413
github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs=
@@ -783,6 +784,10 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
783784
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
784785
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
785786
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
787+
github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0=
788+
github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
789+
github.com/sendgrid/sendgrid-go v3.11.1+incompatible h1:ai0+woZ3r/+tKLQExznak5XerOFoD6S7ePO0lMV8WXo=
790+
github.com/sendgrid/sendgrid-go v3.11.1+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
786791
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
787792
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
788793
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
@@ -843,6 +848,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
843848
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
844849
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
845850
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
851+
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
852+
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
846853
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
847854
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
848855
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=

internal/relui/workflows.go

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (h *DefinitionHolder) Definitions() map[string]*workflow.Definition {
7474
}
7575

7676
// RegisterMailDLCLDefinition registers a workflow definition for mailing a golang.org/dl CL
77-
// onto h, using e for the external service configuration.
77+
// onto h.
7878
func RegisterMailDLCLDefinition(h *DefinitionHolder, tasks *task.VersionTasks) {
7979
versions := workflow.Parameter{
8080
Name: "Versions",
@@ -101,6 +101,108 @@ For example:
101101
h.RegisterDefinition("mail-dl-cl", wd)
102102
}
103103

104+
// RegisterAnnounceDefinitions registers workflow definitions involving announcing
105+
// onto h.
106+
func RegisterAnnounceDefinitions(h *DefinitionHolder, tasks task.AnnounceMailTasks) {
107+
version := workflow.Parameter{
108+
Name: "Version",
109+
Doc: `Version is the Go version that has been released.
110+
111+
The version string must use the same format as Go tags.`,
112+
}
113+
security := workflow.Parameter{
114+
Name: "Security (optional)",
115+
ParameterType: workflow.SliceLong,
116+
Doc: `Security is a list of descriptions, one for each distinct security fix included in this release, in Markdown format.
117+
118+
The empty list means there are no security fixes included.
119+
120+
This field applies only to minor releases.
121+
122+
Past examples:
123+
• "encoding/pem: fix stack overflow in Decode
124+
125+
A large (more than 5 MB) PEM input can cause a stack overflow in Decode,
126+
leading the program to crash.
127+
128+
Thanks to Juho Nurminen of Mattermost who reported the error.
129+
130+
This is CVE-2022-24675 and Go issue https://go.dev/issue/51853."
131+
• "crypto/elliptic: tolerate all oversized scalars in generic P-256
132+
133+
A crafted scalar input longer than 32 bytes can cause P256().ScalarMult
134+
or P256().ScalarBaseMult to panic. Indirect uses through crypto/ecdsa and
135+
crypto/tls are unaffected. amd64, arm64, ppc64le, and s390x are unaffected.
136+
137+
This was discovered thanks to a Project Wycheproof test vector.
138+
139+
This is CVE-2022-28327 and Go issue https://go.dev/issue/52075."`,
140+
Example: `encoding/pem: fix stack overflow in Decode
141+
142+
A large (more than 5 MB) PEM input can cause a stack overflow in Decode,
143+
leading the program to crash.
144+
145+
Thanks to Juho Nurminen of Mattermost who reported the error.
146+
147+
This is CVE-2022-24675 and Go issue https://go.dev/issue/51853.`,
148+
}
149+
names := workflow.Parameter{
150+
Name: "Names (optional)",
151+
ParameterType: workflow.SliceShort,
152+
Doc: `Names is an optional list of release coordinator names to include in the sign-off message.`,
153+
}
154+
155+
{
156+
minorVersion := version
157+
minorVersion.Example = "go1.18.2"
158+
secondaryVersion := workflow.Parameter{
159+
Name: "SecondaryVersion",
160+
Doc: `SecondaryVersion is an older Go version that was also released.`,
161+
Example: "go1.17.10",
162+
}
163+
164+
wd := workflow.New()
165+
sentMail := wd.Task("mail-announcement", func(ctx *workflow.TaskContext, v1, v2 string, sec, names []string) (task.SentMail, error) {
166+
return tasks.AnnounceMinorRelease(ctx, task.ReleaseAnnouncement{Version: v1, SecondaryVersion: v2, Security: sec, Names: names})
167+
}, wd.Parameter(minorVersion), wd.Parameter(secondaryVersion), wd.Parameter(security), wd.Parameter(names))
168+
wd.Output("AnnouncementURL", wd.Task("await-announcement", tasks.AwaitAnnounceMail, sentMail))
169+
h.RegisterDefinition("announce-minor", wd)
170+
}
171+
{
172+
betaVersion := version
173+
betaVersion.Example = "go1.19beta1"
174+
175+
wd := workflow.New()
176+
sentMail := wd.Task("mail-announcement", func(ctx *workflow.TaskContext, v string, names []string) (task.SentMail, error) {
177+
return tasks.AnnounceBetaRelease(ctx, task.ReleaseAnnouncement{Version: v, Names: names})
178+
}, wd.Parameter(betaVersion), wd.Parameter(names))
179+
wd.Output("AnnouncementURL", wd.Task("await-announcement", tasks.AwaitAnnounceMail, sentMail))
180+
h.RegisterDefinition("announce-beta", wd)
181+
}
182+
{
183+
rcVersion := version
184+
rcVersion.Example = "go1.19rc1"
185+
186+
wd := workflow.New()
187+
sentMail := wd.Task("mail-announcement", func(ctx *workflow.TaskContext, v string, names []string) (task.SentMail, error) {
188+
return tasks.AnnounceRCRelease(ctx, task.ReleaseAnnouncement{Version: v, Names: names})
189+
}, wd.Parameter(rcVersion), wd.Parameter(names))
190+
wd.Output("AnnouncementURL", wd.Task("await-announcement", tasks.AwaitAnnounceMail, sentMail))
191+
h.RegisterDefinition("announce-rc", wd)
192+
}
193+
{
194+
majorVersion := version
195+
majorVersion.Example = "go1.19"
196+
197+
wd := workflow.New()
198+
sentMail := wd.Task("mail-announcement", func(ctx *workflow.TaskContext, v string, names []string) (task.SentMail, error) {
199+
return tasks.AnnounceMajorRelease(ctx, task.ReleaseAnnouncement{Version: v, Names: names})
200+
}, wd.Parameter(majorVersion), wd.Parameter(names))
201+
wd.Output("AnnouncementURL", wd.Task("await-announcement", tasks.AwaitAnnounceMail, sentMail))
202+
h.RegisterDefinition("announce-major", wd)
203+
}
204+
}
205+
104206
// RegisterTweetDefinitions registers workflow definitions involving tweeting
105207
// onto h, using e for the external service configuration.
106208
func RegisterTweetDefinitions(h *DefinitionHolder, e task.ExternalConfig) {

0 commit comments

Comments
 (0)