Skip to content

Commit 351ffda

Browse files
committed
cmd/coordinator, maintner/maintnerd/maintapi: consolidate TryBot branch logic
This change reverts the coordinator side to be much simpler, as it was before CL 167382, and consolidates all the version selection in maintapi. This direction is chosen because at this time¹ maintapi is best suited to perform version selection. This is a refactor CL that leaves current behavior unmodified, and test cases provide improved coverage. The following smaller CL will make the desired changes to behavior. Remove TestNewTrySetBuildRepoGo110 because it's no longer needed. It was added when x/build started requiring module mode to build successfully, given that Go 1.10 didn't have module mode support. Background At this time¹ coordinator makes use of maintapi to find TryBot work, and it is a collaborate effort between the two components that results in determining what builds will happen. Coordinator is ultimately responsible for starting and running the builds, but it doesn't have information about the branches in the Go project (the Go revision at refs/heads/master, refs/heads/release-branch.go1.16, etc.). Maintapi has that information via the maintner corpus. So it makes the version information available to coordinator by populating relevant fields in apipb.GoFindTryWorkResponse. Issue golang/go#28891 was about wanting to test golang.org/x repo CLs on release-branch.go1.n with the corresponding Go 1.n version, rather than Go tip. Unfortunately, it was implemented on the coordinator side, resulting in the logic for version selection to be more spread between the coordinator and maintapi components. There were followup issues like golang/go#42127 and golang/go#37512, whose fixes built on top of the coordinator side, and increased complexity there. As a consequence, making and testing further changes became more difficult than it needs to be. ¹ After golang/go#34744 is done, I'd like to move all the TryBot version selection logic into coordinator, the component responsible for TryBots. But not today. For golang/go#46154. Change-Id: I93986acefd4bf66b27ccf0323439966122b7989a Reviewed-on: https://go-review.googlesource.com/c/build/+/319789 Trust: Dmitri Shuralyov <[email protected]> Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent d36eef7 commit 351ffda

File tree

4 files changed

+201
-107
lines changed

4 files changed

+201
-107
lines changed

cmd/coordinator/coordinator.go

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,26 +1218,6 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
12181218
work.GoVersion = []*apipb.MajorMinor{{}}
12191219
}
12201220

1221-
// GoCommit is non-empty for x/* repos (aka "subrepos"). It
1222-
// is the Go revision to use to build & test the x/* repo
1223-
// with. The first element is the master branch. We test the
1224-
// master branch against all the normal builders configured to
1225-
// do subrepos. Any GoCommit values past the first are for older
1226-
// release branches, but we use a limited subset of builders for those.
1227-
var goRev string
1228-
if len(work.GoCommit) > 0 {
1229-
// By default, use the first GoCommit, which represents Go tip (master branch).
1230-
goRev = work.GoCommit[0]
1231-
}
1232-
for i, goBranch := range work.GoBranch {
1233-
// There are two cases where we want to change goRev to work.GoCommit[i]:
1234-
// 1. CL branch is like "master" or "release-branch.go1.15" and matches the Go branch exactly.
1235-
// 2. CL branch is like "release-branch.go1.15-suffix" and its prefix matches.
1236-
if work.Branch == goBranch || strings.HasPrefix(work.Branch, goBranch+"-") {
1237-
goRev = work.GoCommit[i]
1238-
}
1239-
}
1240-
12411221
addBuilderToSet := func(bs *buildStatus, brev buildgo.BuilderRev) {
12421222
bs.trySet = ts
12431223
status[brev] = bs
@@ -1252,6 +1232,15 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
12521232
go ts.awaitTryBuild(idx, bs, brev)
12531233
}
12541234

1235+
var mainBuildGoCommit string
1236+
if key.Project != "go" && len(work.GoCommit) > 0 {
1237+
// work.GoCommit is non-empty when work.Project != "go".
1238+
// For the main build, use the first GoCommit, which represents Go tip (master branch).
1239+
mainBuildGoCommit = work.GoCommit[0]
1240+
}
1241+
1242+
// Start the main TryBot build using the selected builders.
1243+
// There may be additional builds, those are handled below.
12551244
if !testingKnobSkipBuilds {
12561245
go ts.notifyStarting()
12571246
}
@@ -1260,7 +1249,7 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
12601249
if goVersion.Less(bconf.MinimumGoVersion) {
12611250
continue
12621251
}
1263-
brev := tryKeyToBuilderRev(bconf.Name, key, goRev)
1252+
brev := tryKeyToBuilderRev(bconf.Name, key, mainBuildGoCommit)
12641253
bs, err := newBuild(brev, noCommitDetail)
12651254
if err != nil {
12661255
log.Printf("can't create build for %q: %v", brev, err)
@@ -1269,17 +1258,16 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
12691258
addBuilderToSet(bs, brev)
12701259
}
12711260

1272-
// For subrepos on the "master" branch, test against prior releases of Go too.
1273-
if key.Project != "go" && key.Branch == "master" {
1274-
// linuxBuilder is the standard builder we run for when testing x/* repos against
1275-
// the past two Go releases.
1261+
// If this is a golang.org/x repo and there's more than one GoCommit,
1262+
// that means we're testing against prior releases of Go too.
1263+
// The version selection logic is currently in maintapi's GoFindTryWork implementation.
1264+
if key.Project != "go" && len(work.GoCommit) >= 2 {
1265+
// linuxBuilder is the standard builder for this purpose.
12761266
linuxBuilder := dashboard.Builders["linux-amd64"]
12771267

1278-
// If there's more than one GoCommit, that means this is an x/* repo
1279-
// and we're testing against previous releases of Go.
12801268
for i, goRev := range work.GoCommit {
12811269
if i == 0 {
1282-
// Skip the i==0 element, which is handled above.
1270+
// Skip the i==0 element, which was already handled above.
12831271
continue
12841272
}
12851273
branch := work.GoBranch[i]

cmd/coordinator/coordinator_test.go

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -161,23 +161,23 @@ func TestStagingClusterBuilders(t *testing.T) {
161161
func TestIssue28891(t *testing.T) {
162162
testingKnobSkipBuilds = true
163163

164-
work := &apipb.GerritTryWorkItem{ // Roughly based on https://go-review.googlesource.com/c/tools/+/150577/1.
165-
Project: "tools",
166-
Branch: "release-branch.go1.11",
167-
ChangeId: "Ice719ab807ce3922b885a800ac873cdbf165a8f7",
168-
Commit: "9d66f1bfdbed72f546df963194a19d56180c4ce7",
169-
GoCommit: []string{"a2e79571a9d3dbe3cf10dcaeb1f9c01732219869", "e39e43d7349555501080133bb426f1ead4b3ef97", "f5ff72d62301c4e9d0a78167fab5914ca12919bd"},
170-
GoBranch: []string{"master", "release-branch.go1.11", "release-branch.go1.10"},
171-
GoVersion: []*apipb.MajorMinor{{1, 12}, {1, 11}, {1, 10}},
164+
work := &apipb.GerritTryWorkItem{ // Based on what maintapi's GoFindTryWork does for x/net CL 258478.
165+
Project: "net",
166+
Branch: "release-branch.go1.15",
167+
ChangeId: "I546597cedf3715e6617babcb3b62140bf1857a27",
168+
Commit: "a5fa9d4b7c91aa1c3fecbeb6358ec1127b910dd6",
169+
GoCommit: []string{"72ccabc99449b2cb5bb1438eb90244d55f7b02f5"},
170+
GoBranch: []string{"release-branch.go1.15"},
171+
GoVersion: []*apipb.MajorMinor{{1, 15}},
172172
}
173173
ts := newTrySet(work)
174174
if len(ts.builds) == 0 {
175175
t.Fatal("no builders in try set, want at least 1")
176176
}
177177
for i, bs := range ts.builds {
178-
const go111Revision = "e39e43d7349555501080133bb426f1ead4b3ef97"
179-
if bs.BuilderRev.Rev != go111Revision {
180-
t.Errorf("build[%d]: %s: x/tools on release-branch.go1.11 branch should be tested with Go 1.11, but isn't", i, bs.NameAndBranch())
178+
const go115Revision = "72ccabc99449b2cb5bb1438eb90244d55f7b02f5"
179+
if bs.BuilderRev.Rev != go115Revision {
180+
t.Errorf("build[%d]: %s: x/net on release-branch.go1.15 branch should be tested with Go 1.15, but isn't", i, bs.NameAndBranch())
181181
}
182182
}
183183
}
@@ -188,63 +188,40 @@ func TestIssue28891(t *testing.T) {
188188
func TestIssue42127(t *testing.T) {
189189
testingKnobSkipBuilds = true
190190

191-
work := &apipb.GerritTryWorkItem{ // Roughly based on https://go-review.googlesource.com/c/net/+/264058/1.
191+
work := &apipb.GerritTryWorkItem{ // Based on what maintapi's GoFindTryWork does for x/net CL 264058.
192192
Project: "net",
193193
Branch: "release-branch.go1.15-bundle",
194194
ChangeId: "I546597cedf3715e6617babcb3b62140bf1857a27",
195-
Commit: "286322bb8662ddff3686e42a01c33a1d47d25153",
196-
GoCommit: []string{"b2a8317b31d652b3ee293a313269b8290bcdf96c", "3b1f07fff774f86f13316f7bec6552566568fc10", "768b64711ae4292bd9a02c9cc8d44282f5fac66b"},
197-
GoBranch: []string{"master", "release-branch.go1.15", "release-branch.go1.14"},
198-
GoVersion: []*apipb.MajorMinor{{1, 16}, {1, 15}, {1, 14}},
195+
Commit: "abf26a14a65b111d492067f407f32455c5b1048c",
196+
GoCommit: []string{"72ccabc99449b2cb5bb1438eb90244d55f7b02f5"},
197+
GoBranch: []string{"release-branch.go1.15"},
198+
GoVersion: []*apipb.MajorMinor{{1, 15}},
199199
}
200200
ts := newTrySet(work)
201201
if len(ts.builds) == 0 {
202202
t.Fatal("no builders in try set, want at least 1")
203203
}
204204
for i, bs := range ts.builds {
205-
const go115Revision = "3b1f07fff774f86f13316f7bec6552566568fc10"
205+
const go115Revision = "72ccabc99449b2cb5bb1438eb90244d55f7b02f5"
206206
if bs.BuilderRev.Rev != go115Revision {
207207
t.Errorf("build[%d]: %s: x/net on release-branch.go1.15-bundle branch should be tested with Go 1.15, but isn't", i, bs.NameAndBranch())
208208
}
209209
}
210210
}
211211

212-
// tests that we don't test Go 1.10 for the build repo
213-
func TestNewTrySetBuildRepoGo110(t *testing.T) {
214-
testingKnobSkipBuilds = true
215-
216-
work := &apipb.GerritTryWorkItem{
217-
Project: "build",
218-
Branch: "master",
219-
ChangeId: "I6f05da2186b38dc8056081252563a82c50f0ce05",
220-
Commit: "a62e6a3ab11cc9cc2d9e22a50025dd33fc35d22f",
221-
GoCommit: []string{"a2e79571a9d3dbe3cf10dcaeb1f9c01732219869", "e39e43d7349555501080133bb426f1ead4b3ef97", "f5ff72d62301c4e9d0a78167fab5914ca12919bd"},
222-
GoBranch: []string{"master", "release-branch.go1.11", "release-branch.go1.10"},
223-
GoVersion: []*apipb.MajorMinor{{1, 12}, {1, 11}, {1, 10}},
224-
}
225-
ts := newTrySet(work)
226-
for i, bs := range ts.builds {
227-
v := bs.NameAndBranch()
228-
if strings.Contains(v, "Go 1.10.x") {
229-
t.Errorf("unexpected builder: %v", v)
230-
}
231-
t.Logf("build[%d]: %s", i, v)
232-
}
233-
}
234-
235212
// Tests that TryBots run on branches of the x/ repositories, other than
236213
// "master" and "release-branch.go1.N". See golang.org/issue/37512.
237214
func TestXRepoBranches(t *testing.T) {
238215
testingKnobSkipBuilds = true
239216

240-
work := &apipb.GerritTryWorkItem{
217+
work := &apipb.GerritTryWorkItem{ // Based on what maintapi's GoFindTryWork does for x/tools CL 227356.
241218
Project: "tools",
242219
Branch: "gopls-release-branch.0.4",
243220
ChangeId: "Ica799fcf117bf607c0c59f41b08a78552339dc53",
244-
Commit: "6af4ce83c61d0f3e616b410b53b51982798c4d73",
245-
GoVersion: []*apipb.MajorMinor{{1, 15}},
246-
GoCommit: []string{"74d6de03fd7db2c6faa7794620a9bcf0c4f018f2"},
221+
Commit: "13af72af5ccdfe6f1e75b57b02cfde3bb0a77a76",
222+
GoCommit: []string{"9995c6b50aa55c1cc1236d1d688929df512dad53"},
247223
GoBranch: []string{"master"},
224+
GoVersion: []*apipb.MajorMinor{{1, 17}},
248225
}
249226
ts := newTrySet(work)
250227
for i, bs := range ts.builds {

maintner/maintnerd/maintapi/api.go

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ var tryCommentRx = regexp.MustCompile(`(?m)^TRY=(.*)$`)
104104

105105
// tryWorkItem creates a GerritTryWorkItem for
106106
// the Gerrit CL specified by cl, ci, comments.
107-
func tryWorkItem(cl *maintner.GerritCL, ci *gerrit.ChangeInfo, comments map[string][]gerrit.CommentInfo) *apipb.GerritTryWorkItem {
107+
//
108+
// goProj is the state of the main Go repository.
109+
// develVersion is the version of Go in development at HEAD of master branch.
110+
// supportedReleases are the supported Go releases per https://golang.org/doc/devel/release.html#policy.
111+
func tryWorkItem(
112+
cl *maintner.GerritCL, ci *gerrit.ChangeInfo, comments map[string][]gerrit.CommentInfo,
113+
goProj refer, develVersion apipb.MajorMinor, supportedReleases []*apipb.GoRelease,
114+
) (*apipb.GerritTryWorkItem, error) {
108115
w := &apipb.GerritTryWorkItem{
109116
Project: cl.Project.Project(),
110117
Branch: strings.TrimPrefix(cl.Branch(), "refs/heads/"),
@@ -116,6 +123,7 @@ func tryWorkItem(cl *maintner.GerritCL, ci *gerrit.ChangeInfo, comments map[stri
116123
w.Commit = ci.CurrentRevision
117124
w.Version = int32(ci.Revisions[ci.CurrentRevision].PatchSetNumber)
118125
}
126+
119127
// Look for "TRY=" comments. Only consider messages that are accompanied
120128
// by a Run-TryBot+1 vote, as a way of confirming the comment author has
121129
// Trybot Access (see https://golang.org/wiki/GerritAccess#trybot-access-may-start-trybots).
@@ -153,7 +161,64 @@ func tryWorkItem(cl *maintner.GerritCL, ci *gerrit.ChangeInfo, comments map[stri
153161
})
154162
}
155163
}
156-
return w
164+
165+
// Populate GoCommit, GoBranch, GoVersion fields
166+
// according to what's being tested. Coordinator
167+
// will use these to run corresponding tests.
168+
if w.Project == "go" {
169+
// TryBot on Go repo. Set the GoVersion field based on branch name.
170+
if major, minor, ok := parseReleaseBranchVersion(w.Branch); ok {
171+
// A release branch like release-branch.goX.Y.
172+
// Use the major-minor Go version determined from the branch name.
173+
w.GoVersion = []*apipb.MajorMinor{{major, minor}}
174+
} else {
175+
// A branch that is not release-branch.goX.Y: maybe
176+
// "master" or a development branch like "dev.link".
177+
// There isn't a way to determine the version from its name,
178+
// so use the development Go version until we need to do more.
179+
// TODO(golang.org/issue/42376): This can be made more precise.
180+
w.GoVersion = []*apipb.MajorMinor{&develVersion}
181+
}
182+
} else {
183+
// TryBot on a subrepo.
184+
trimBundleSuffix := func(branch string) string {
185+
// There was only one branch with a suffix, release-branch.go1.15-bundle in x/net, so just hardcode it.
186+
// TODO: This special case can be removed when Go 1.17 is out and 1.15 is no longer supported.
187+
return strings.TrimSuffix(branch, "-bundle")
188+
}
189+
if major, minor, ok := parseReleaseBranchVersion(trimBundleSuffix(w.Branch)); ok {
190+
// An release-branch.goX.Y (or one with a -suffix) branch is used for internal needs
191+
// of goX.Y only, so no reason to test it on other Go versions.
192+
goBranch := fmt.Sprintf("release-branch.go%d.%d", major, minor)
193+
goCommit := goProj.Ref("refs/heads/" + goBranch)
194+
if goCommit == "" {
195+
return nil, fmt.Errorf("branch %q doesn't exist", goBranch)
196+
}
197+
w.GoCommit = []string{goCommit.String()}
198+
w.GoBranch = []string{goBranch}
199+
w.GoVersion = []*apipb.MajorMinor{{major, minor}}
200+
} else if w.Branch == "master" {
201+
// For subrepos on the "master" branch, use the default policy
202+
// of testing it with Go tip and the supported releases.
203+
w.GoCommit = []string{goProj.Ref("refs/heads/master").String()}
204+
w.GoBranch = []string{"master"}
205+
w.GoVersion = []*apipb.MajorMinor{&develVersion}
206+
for _, r := range supportedReleases {
207+
w.GoCommit = append(w.GoCommit, r.BranchCommit)
208+
w.GoBranch = append(w.GoBranch, r.BranchName)
209+
w.GoVersion = append(w.GoVersion, &apipb.MajorMinor{r.Major, r.Minor})
210+
}
211+
} else {
212+
// A branch that is neither release-branch.goX.Y nor "master":
213+
// maybe some custom branch like "dev.go2go".
214+
// Test it against Go tip only until we want to do more.
215+
w.GoCommit = []string{goProj.Ref("refs/heads/master").String()}
216+
w.GoBranch = []string{"master"}
217+
w.GoVersion = []*apipb.MajorMinor{&develVersion}
218+
}
219+
}
220+
221+
return w, nil
157222
}
158223

159224
func firstLine(s string) string {
@@ -251,7 +316,8 @@ func goFindTryWork(ctx context.Context, gerritc *gerrit.Client, maintc *maintner
251316
return nil, err
252317
}
253318
// If Go X.Y is the latest supported release, the version in development is likely Go X.(Y+1).
254-
develVersion := &apipb.MajorMinor{
319+
// TODO(golang.org/issue/42376): This can be made more precise.
320+
develVersion := apipb.MajorMinor{
255321
Major: supportedReleases[0].Major,
256322
Minor: supportedReleases[0].Minor + 1,
257323
}
@@ -273,31 +339,10 @@ func goFindTryWork(ctx context.Context, gerritc *gerrit.Client, maintc *maintner
273339
if err != nil {
274340
return nil, fmt.Errorf("gerritc.ListChangeComments(ctx, %q): %v", changeID, err)
275341
}
276-
work := tryWorkItem(cl, ci, comments)
277-
if work.Project == "go" {
278-
// Trybot on Go repo. Set the GoVersion field based on branch name.
279-
if major, minor, ok := parseReleaseBranchVersion(work.Branch); ok {
280-
// A release branch like release-branch.goX.Y.
281-
// Use the major-minor Go version determined from the branch name.
282-
work.GoVersion = []*apipb.MajorMinor{{major, minor}}
283-
} else {
284-
// A branch that is not release-branch.goX.Y: maybe
285-
// "master" or a development branch like "dev.link".
286-
// There isn't a way to determine the version from its name,
287-
// so use the development Go version until we need to do more.
288-
// TODO(golang.org/issue/42376): This can be made more precise.
289-
work.GoVersion = []*apipb.MajorMinor{develVersion}
290-
}
291-
} else {
292-
// Trybot on a subrepo. Set the Go fields to master and the supported releases.
293-
work.GoCommit = []string{goProj.Ref("refs/heads/master").String()}
294-
work.GoBranch = []string{"master"}
295-
work.GoVersion = []*apipb.MajorMinor{develVersion}
296-
for _, r := range supportedReleases {
297-
work.GoCommit = append(work.GoCommit, r.BranchCommit)
298-
work.GoBranch = append(work.GoBranch, r.BranchName)
299-
work.GoVersion = append(work.GoVersion, &apipb.MajorMinor{r.Major, r.Minor})
300-
}
342+
work, err := tryWorkItem(cl, ci, comments, goProj, develVersion, supportedReleases)
343+
if err != nil {
344+
log.Printf("goFindTryWork: skipping CL %v because %v\n", ci.ChangeNumber, err)
345+
continue
301346
}
302347
res.Waiting = append(res.Waiting, work)
303348
}
@@ -355,6 +400,17 @@ func (s apiService) ListGoReleases(ctx context.Context, req *apipb.ListGoRelease
355400
}, nil
356401
}
357402

403+
// refer is implemented by *maintner.GerritProject,
404+
// or something that acts like it for testing.
405+
type refer interface {
406+
// Ref returns a non-change ref, such as "HEAD", "refs/heads/master",
407+
// or "refs/tags/v0.8.0",
408+
// Change refs of the form "refs/changes/*" are not supported.
409+
// The returned hash is the zero value (an empty string) if the ref
410+
// does not exist.
411+
Ref(ref string) maintner.GitHash
412+
}
413+
358414
// nonChangeRefLister is implemented by *maintner.GerritProject,
359415
// or something that acts like it for testing.
360416
type nonChangeRefLister interface {

0 commit comments

Comments
 (0)