cmd/coordinator: support specifying a builder for x-repo slowbots
Add support for the syntax `x/repo@builder`, as suggested in #39201.
For golang/go#39201
Change-Id: Iac49169f12b90cbdfea626fcb4f5408358639760
Reviewed-on: https://go-review.googlesource.com/c/build/+/342712
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/coordinator/coordinator.go b/cmd/coordinator/coordinator.go
index 53d5e04..d817dd5 100644
--- a/cmd/coordinator/coordinator.go
+++ b/cmd/coordinator/coordinator.go
@@ -1376,14 +1376,26 @@
// For the Go project on the "master" branch,
// use the TRY= syntax to test against x repos.
if branch := key.Branch; key.Project == "go" && branch == "master" {
- // linuxBuilder is the standard builder as it is the fastest and least expensive.
- linuxBuilder := dashboard.Builders["linux-amd64"]
+ // customBuilder optionally specifies the builder to use for the build
+ // (empty string means to use the default builder).
+ addXrepo := func(project, customBuilder string) *buildStatus {
+ // linux-amd64 is the default builder as it is the fastest and least
+ // expensive.
+ builder := dashboard.Builders["linux-amd64"]
+ if customBuilder != "" {
+ b, ok := dashboard.Builders[customBuilder]
+ if !ok {
+ log.Printf("can't resolve requested builder %q", customBuilder)
+ return nil
+ }
+ builder = b
+ }
- addXrepo := func(project string) *buildStatus {
if testingKnobSkipBuilds {
return nil
}
- if !linuxBuilder.BuildsRepoTryBot(project, branch, branch) {
+ if !builder.BuildsRepoTryBot(project, branch, branch) {
+ log.Printf("builder %q isn't configured to build %q@%q as a trybot", builder.Name, project, branch)
return nil
}
rev, err := getRepoHead(project)
@@ -1392,7 +1404,7 @@
return nil
}
brev := buildgo.BuilderRev{
- Name: linuxBuilder.Name,
+ Name: builder.Name,
Rev: work.Commit,
SubName: project,
SubRev: rev,
@@ -1407,17 +1419,17 @@
}
// First, add the opt-in x repos.
- xrepos := xReposFromComments(work)
- for project := range xrepos {
- if bs := addXrepo(project); bs != nil {
+ repoBuilders := xReposFromComments(work)
+ for rb := range repoBuilders {
+ if bs := addXrepo(rb.Project, rb.Builder); bs != nil {
ts.xrepos = append(ts.xrepos, bs)
}
}
- // Always include x/tools. See golang.org/issue/34348.
+ // Always include the default x/tools builder. See golang.org/issue/34348.
// Do not add it to the trySet's list of opt-in x repos, however.
- if !xrepos["tools"] {
- addXrepo("tools")
+ if haveDefaultToolsBuild := repoBuilders[xRepoAndBuilder{Project: "tools"}]; !haveDefaultToolsBuild {
+ addXrepo("tools", "")
}
}
@@ -4193,18 +4205,39 @@
return builders
}
-// xReposFromComments looks at the TRY= comments from Gerrit (in
-// work) and returns any additional subrepos that should be tested.
-// The TRY= comments are expected to be of the format TRY=x/foo,
-// where foo is the name of the subrepo.
-func xReposFromComments(work *apipb.GerritTryWorkItem) map[string]bool {
- xrepos := map[string]bool{}
+type xRepoAndBuilder struct {
+ Project string // "net", "tools", etc.
+ Builder string // Builder to use. Empty string means default builder.
+}
+
+func (rb xRepoAndBuilder) String() string {
+ if rb.Builder == "" {
+ return rb.Project
+ }
+ return rb.Project + "@" + rb.Builder
+}
+
+// xReposFromComments looks at the TRY= comments from Gerrit (in work) and
+// returns any additional subrepos that should be tested. The TRY= comments
+// are expected to be of the format TRY=x/foo or TRY=x/foo@builder where foo is
+// the name of the subrepo and builder is a builder name. If no builder is
+// provided, a default builder is used.
+func xReposFromComments(work *apipb.GerritTryWorkItem) map[xRepoAndBuilder]bool {
+ xrepos := make(map[xRepoAndBuilder]bool)
for _, term := range latestTryTerms(work) {
if len(term) < len("x/_") || term[:2] != "x/" {
continue
}
- xrepo := term[2:]
- xrepos[xrepo] = true
+ parts := strings.SplitN(term, "@", 2)
+ xrepo := parts[0][2:]
+ builder := "" // By convention, this means the default builder.
+ if len(parts) > 1 {
+ builder = parts[1]
+ }
+ xrepos[xRepoAndBuilder{
+ Project: xrepo,
+ Builder: builder,
+ }] = true
}
return xrepos
}
@@ -4219,7 +4252,7 @@
return nil
}
return strings.FieldsFunc(tryMsg, func(c rune) bool {
- return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '-' && c != '_' && c != '/'
+ return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '-' && c != '_' && c != '/' && c != '@'
})
}
diff --git a/cmd/coordinator/coordinator_test.go b/cmd/coordinator/coordinator_test.go
index 8addd8b..e0592d5 100644
--- a/cmd/coordinator/coordinator_test.go
+++ b/cmd/coordinator/coordinator_test.go
@@ -365,15 +365,16 @@
TryMessage: []*apipb.TryVoteMessage{
{
Version: 2,
- Message: "x/build, x/sync x/tools, x/sync",
+ Message: "x/build, x/sync x/tools, x/sync, x/tools@freebsd-amd64-race",
},
},
}
got := xReposFromComments(work)
- want := map[string]bool{
- "build": true,
- "sync": true,
- "tools": true,
+ want := map[xRepoAndBuilder]bool{
+ {"build", ""}: true,
+ {"sync", ""}: true,
+ {"tools", ""}: true,
+ {"tools", "freebsd-amd64-race"}: true,
}
if !reflect.DeepEqual(got, want) {
t.Errorf("mismatch:\n got: %v\nwant: %v\n", got, want)