Skip to content

Commit 84c8bc5

Browse files
authored
[rayci] add buildkite notification (#237)
Add buildkite notification upon build failures. Notification is sent to the owner of the build (buildkite syntax: https://buildkite.com/docs/pipelines/notifications). Enable notification for microcheck for now. This will allow folks to know build issues faster. Test: - CI - I added a failure into rayci CI in a previous commit and check that I get notified Signed-off-by: can <[email protected]>
1 parent fc14165 commit 84c8bc5

File tree

7 files changed

+89
-22
lines changed

7 files changed

+89
-22
lines changed

raycicmd/bk_pipeline.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import (
55
"time"
66
)
77

8+
type bkNotify struct {
9+
Email string `yaml:"email,omitempty"`
10+
If string `yaml:"if,omitempty"`
11+
}
12+
813
type bkPipelineGroup struct {
914
Group string `yaml:"group,omitempty"`
1015
Key string `yaml:"key,omitempty"`
@@ -13,7 +18,8 @@ type bkPipelineGroup struct {
1318
}
1419

1520
type bkPipeline struct {
16-
Steps []*bkPipelineGroup `yaml:"steps,omitempty"`
21+
Steps []*bkPipelineGroup `yaml:"steps,omitempty"`
22+
Notify []*bkNotify `yaml:"notify,omitempty"`
1723
}
1824

1925
func (p *bkPipeline) totalSteps() int {
@@ -28,6 +34,13 @@ func newBkAgents(queue string) map[string]any {
2834
return map[string]any{"queue": queue}
2935
}
3036

37+
func makeBuildFailureBkNotify(email string) *bkNotify {
38+
return &bkNotify{
39+
Email: email,
40+
If: `build.state == "failing"`,
41+
}
42+
}
43+
3144
func makeNoopBkPipeline(q string) *bkPipeline {
3245
step := map[string]any{"command": "echo no pipeline steps"}
3346
if q != "" {

raycicmd/build_info.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import (
1010
)
1111

1212
type buildInfo struct {
13-
buildID string
14-
launcherBranch string
15-
gitCommit string
16-
selects []string
13+
buildID string
14+
buildAuthorEmail string
15+
launcherBranch string
16+
gitCommit string
17+
selects []string
1718
}
1819

1920
func makeBuildID(envs Envs) (string, error) {

raycicmd/config.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ type config struct {
126126
// Optional.
127127
MaxParallelism int `yaml:"max_parallelism"`
128128

129+
// NotifyOwnerOnFailure sets if the owner of the build should be notified
130+
// when a build fails.
131+
//
132+
// Optional.
133+
NotifyOwnerOnFailure bool `yaml:"notify_owner_on_failure"`
134+
129135
// DockerPlugin contains additional docker plugin configs, to fine tune
130136
// the docker plugin's behavior.
131137
//
@@ -283,11 +289,14 @@ func ciDefaultConfig(envs Envs) *config {
283289
case rayPRPipeline, rayV2PremergePipeline, rayDevPipeline:
284290
return prPipelineConfig("ray-pr", nil, -1)
285291
case rayV2MicrocheckPipeline:
286-
return prPipelineConfig(
292+
mcPipelineConfig := prPipelineConfig(
287293
"ray-pr-microcheck",
288294
map[string]string{"RAYCI_MICROCHECK_RUN": "1"},
289295
1,
290296
)
297+
mcPipelineConfig.NotifyOwnerOnFailure = true
298+
299+
return mcPipelineConfig
291300
}
292301

293302
// By default, assume it is less privileged.

raycicmd/main.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,19 @@ func makeBuildInfo(flags *Flags, envs Envs) (*buildInfo, error) {
104104
}
105105

106106
rayciBranch, _ := envs.Lookup("RAYCI_BRANCH")
107+
108+
// buildAuthorEmail is the email of the user who triggered the buildkite webhook
109+
// event; for most parts, it is the same as the github author email.
110+
buildAuthorEmail, _ := envs.Lookup("BUILDKITE_BUILD_CREATOR_EMAIL")
107111
commit := gitCommit(envs)
108112
selects := stepSelects(flags.Select, envs)
109113

110114
return &buildInfo{
111-
buildID: buildID,
112-
launcherBranch: rayciBranch,
113-
gitCommit: commit,
114-
selects: selects,
115+
buildID: buildID,
116+
buildAuthorEmail: buildAuthorEmail,
117+
launcherBranch: rayciBranch,
118+
gitCommit: commit,
119+
selects: selects,
115120
}, nil
116121
}
117122

raycicmd/main_test.go

+15-12
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ func TestExecWithInput(t *testing.T) {
5858
func TestMakeBuildInfo(t *testing.T) {
5959
flags := &Flags{}
6060
envs := newEnvsMap(map[string]string{
61-
"RAYCI_BUILD_ID": "fake-build-id",
62-
"BUILDKITE_COMMIT": "abc123",
63-
"RAYCI_BRANCH": "foobar",
64-
"RAYCI_SELECT": "foo,bar,taz",
61+
"RAYCI_BUILD_ID": "fake-build-id",
62+
"BUILDKITE_COMMIT": "abc123",
63+
"BUILDKITE_BUILD_CREATOR_EMAIL": "[email protected]",
64+
"RAYCI_BRANCH": "foobar",
65+
"RAYCI_SELECT": "foo,bar,taz",
6566
})
6667

6768
info, err := makeBuildInfo(flags, envs)
@@ -70,10 +71,11 @@ func TestMakeBuildInfo(t *testing.T) {
7071
}
7172

7273
want := &buildInfo{
73-
buildID: "fake-build-id",
74-
launcherBranch: "foobar",
75-
gitCommit: "abc123",
76-
selects: []string{"foo", "bar", "taz"},
74+
buildID: "fake-build-id",
75+
buildAuthorEmail: "[email protected]",
76+
launcherBranch: "foobar",
77+
gitCommit: "abc123",
78+
selects: []string{"foo", "bar", "taz"},
7779
}
7880
if !reflect.DeepEqual(info, want) {
7981
t.Errorf("got %+v, want %+v", info, want)
@@ -85,10 +87,11 @@ func TestMakeBuildInfo(t *testing.T) {
8587
t.Fatal("make build info with selects overwrite: ", err)
8688
}
8789
want = &buildInfo{
88-
buildID: "fake-build-id",
89-
launcherBranch: "foobar",
90-
gitCommit: "abc123",
91-
selects: []string{"gee", "goo"},
90+
buildID: "fake-build-id",
91+
buildAuthorEmail: "[email protected]",
92+
launcherBranch: "foobar",
93+
gitCommit: "abc123",
94+
selects: []string{"gee", "goo"},
9295
}
9396
if !reflect.DeepEqual(info, want) {
9497
t.Errorf("got %+v, want %+v", info, want)

raycicmd/make.go

+4
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,9 @@ func makePipeline(repoDir string, config *config, info *buildInfo) (
141141
return makeNoopBkPipeline(q), nil
142142
}
143143

144+
if email := info.buildAuthorEmail; email != "" && config.NotifyOwnerOnFailure {
145+
pl.Notify = append(pl.Notify, makeBuildFailureBkNotify(email))
146+
}
147+
144148
return pl, nil
145149
}

raycicmd/make_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,38 @@ func TestMakePipeline(t *testing.T) {
293293
t.Errorf("got step keys %v, want %v", keys, want)
294294
}
295295
})
296+
297+
t.Run("notify", func(t *testing.T) {
298+
buildID := "fakebuild"
299+
info := &buildInfo{
300+
buildID: buildID,
301+
}
302+
303+
config := *commonConfig
304+
config.NotifyOwnerOnFailure = false
305+
306+
got, err := makePipeline(tmp, &config, info)
307+
if err != nil {
308+
t.Fatalf("makePipeline: %v", err)
309+
}
310+
if len(got.Notify) != 0 {
311+
t.Errorf("got %d notify, want 0", len(got.Notify))
312+
}
313+
314+
const email = "[email protected]"
315+
infoWithEmail := &buildInfo{
316+
buildID: buildID,
317+
buildAuthorEmail: email,
318+
}
319+
config.NotifyOwnerOnFailure = true
320+
got, err = makePipeline(tmp, &config, infoWithEmail)
321+
if err != nil {
322+
t.Fatalf("makePipeline: %v", err)
323+
}
324+
if len(got.Notify) == 0 || got.Notify[0].Email != email || got.Notify[0].If != `build.state == "failing"` {
325+
t.Errorf(`got %v, want email %v, want if build.state == "failing"`, got.Notify, email)
326+
}
327+
})
296328
}
297329

298330
func TestSortPipelineGroups(t *testing.T) {

0 commit comments

Comments
 (0)