in cmd/coordinator/coordinator.go [1185:1355]
func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
goBranch := work.Branch
if work.Project != "go" && len(work.GoBranch) > 0 {
// work.GoBranch is non-empty when work.Project != "go",
// so prefer work.GoBranch[0] over work.Branch.
goBranch = work.GoBranch[0]
}
tryBots := dashboard.TryBuildersForProject(work.Project, work.Branch, goBranch)
slowBots := slowBotsFromComments(work)
builders := joinBuilders(tryBots, slowBots)
key := tryWorkItemKey(work)
log.Printf("Starting new trybot set for %v", key)
ts := &trySet{
tryKey: key,
tryID: "T" + randHex(9),
trySetState: trySetState{
builds: make([]*buildStatus, 0, len(builders)),
},
slowBots: slowBots,
}
// Defensive check that the input is well-formed.
// Each GoCommit should have a GoBranch and a GoVersion.
// There should always be at least one GoVersion.
if len(work.GoBranch) < len(work.GoCommit) {
log.Printf("WARNING: len(GoBranch) of %d != len(GoCommit) of %d", len(work.GoBranch), len(work.GoCommit))
work.GoCommit = work.GoCommit[:len(work.GoBranch)]
}
if len(work.GoVersion) < len(work.GoCommit) {
log.Printf("WARNING: len(GoVersion) of %d != len(GoCommit) of %d", len(work.GoVersion), len(work.GoCommit))
work.GoCommit = work.GoCommit[:len(work.GoVersion)]
}
if len(work.GoVersion) == 0 {
log.Print("WARNING: len(GoVersion) is zero, want at least one")
work.GoVersion = []*apipb.MajorMinor{{}}
}
addBuilderToSet := func(bs *buildStatus, brev buildgo.BuilderRev) {
bs.trySet = ts
status[brev] = bs
idx := len(ts.builds)
ts.builds = append(ts.builds, bs)
ts.remain++
if testingKnobSkipBuilds {
return
}
go bs.start() // acquires statusMu itself, so in a goroutine
go ts.awaitTryBuild(idx, bs, brev)
}
var mainBuildGoCommit string
if key.Project != "go" && len(work.GoCommit) > 0 {
// work.GoCommit is non-empty when work.Project != "go".
// For the main build, use the first GoCommit, which represents Go tip (master branch).
mainBuildGoCommit = work.GoCommit[0]
}
// Start the main TryBot build using the selected builders.
// There may be additional builds, those are handled below.
if !testingKnobSkipBuilds {
go ts.notifyStarting()
}
for _, bconf := range builders {
goVersion := types.MajorMinor{int(work.GoVersion[0].Major), int(work.GoVersion[0].Minor)}
if goVersion.Less(bconf.MinimumGoVersion) {
continue
}
brev := tryKeyToBuilderRev(bconf.Name, key, mainBuildGoCommit)
bs, err := newBuild(brev, noCommitDetail)
if err != nil {
log.Printf("can't create build for %q: %v", brev, err)
continue
}
addBuilderToSet(bs, brev)
}
// If this is a golang.org/x repo and there's more than one GoCommit,
// that means we're testing against prior releases of Go too.
// The version selection logic is currently in maintapi's GoFindTryWork implementation.
if key.Project != "go" && len(work.GoCommit) >= 2 {
// linuxBuilder is the standard builder for this purpose.
linuxBuilder := dashboard.Builders["linux-amd64"]
for i, goRev := range work.GoCommit {
if i == 0 {
// Skip the i==0 element, which was already handled above.
continue
}
branch := work.GoBranch[i]
if !linuxBuilder.BuildsRepoTryBot(key.Project, "master", branch) {
continue
}
goVersion := types.MajorMinor{int(work.GoVersion[i].Major), int(work.GoVersion[i].Minor)}
if goVersion.Less(linuxBuilder.MinimumGoVersion) {
continue
}
brev := tryKeyToBuilderRev(linuxBuilder.Name, key, goRev)
bs, err := newBuild(brev, noCommitDetail)
if err != nil {
log.Printf("can't create build for %q: %v", brev, err)
continue
}
bs.goBranch = branch
addBuilderToSet(bs, brev)
}
}
// 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" {
// 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
}
if testingKnobSkipBuilds {
return nil
}
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)
if err != nil {
log.Printf("can't determine repo head for %q: %v", project, err)
return nil
}
brev := buildgo.BuilderRev{
Name: builder.Name,
Rev: work.Commit,
SubName: project,
SubRev: rev,
}
bs, err := newBuild(brev, noCommitDetail)
if err != nil {
log.Printf("can't create x/%s trybot build for go/master commit %s: %v", project, rev, err)
return nil
}
addBuilderToSet(bs, brev)
return bs
}
// First, add the opt-in x repos.
repoBuilders := xReposFromComments(work)
for rb := range repoBuilders {
if bs := addXrepo(rb.Project, rb.Builder); bs != nil {
ts.xrepos = append(ts.xrepos, bs)
}
}
// 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 haveDefaultToolsBuild := repoBuilders[xRepoAndBuilder{Project: "tools"}]; !haveDefaultToolsBuild {
addXrepo("tools", "")
}
}
return ts
}