OLD | NEW |
| (Empty) |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | |
2 // Use of this source code is governed under the Apache License, Version 2.0 | |
3 // that can be found in the LICENSE file. | |
4 | |
5 package buildbot | |
6 | |
7 import ( | |
8 "fmt" | |
9 "strings" | |
10 | |
11 ds "github.com/luci/gae/service/datastore" | |
12 "github.com/luci/luci-go/common/clock" | |
13 log "github.com/luci/luci-go/common/logging" | |
14 "github.com/luci/luci-go/common/sync/parallel" | |
15 "github.com/luci/luci-go/milo/api/resp" | |
16 "github.com/luci/luci-go/milo/appengine/common/model" | |
17 | |
18 "golang.org/x/net/context" | |
19 ) | |
20 | |
21 // getFullBuilds fetches all of the recent builds from the datastore. | |
22 func getFullBuilds(c context.Context, masterName, builderName string, finished b
ool) ([]*buildbotBuild, error) { | |
23 // TODO(hinoka): Builder specific structs. | |
24 q := ds.NewQuery("buildbotBuild") | |
25 q = q.Eq("finished", finished) | |
26 q = q.Eq("master", masterName) | |
27 q = q.Eq("builder", builderName) | |
28 q = q.Order("-number") | |
29 q.Finalize() | |
30 // Ignore the cursor, we don't need it. | |
31 buildbots, _, err := runBuildsQuery(c, q, 25) | |
32 return buildbots, err | |
33 } | |
34 | |
35 // GetConsoleBuilds takes commits and builders and returns a matrix of | |
36 // resp.ConsoleBuild objects. The expected format of the result | |
37 // is [len(commits)][len(builders)]*resp.ConsoleBuild. The first level matches | |
38 // 1:1 to a commit, and the second level matches 1:1 to a builder. | |
39 func GetConsoleBuilds( | |
40 c context.Context, builders []resp.BuilderRef, commits []string) ( | |
41 [][]*resp.ConsoleBuild, error) { | |
42 | |
43 results := make([][]*resp.ConsoleBuild, len(commits)) | |
44 for i := range results { | |
45 results[i] = make([]*resp.ConsoleBuild, len(builders)) | |
46 } | |
47 // HACK(hinoka): This fetches 25 full builds and then filters them. Repl
ace this | |
48 // with something more reasonable. | |
49 // This is kind of a hack but it's okay for now. | |
50 err := parallel.FanOutIn(func(taskC chan<- func() error) { | |
51 for i, builder := range builders { | |
52 i := i | |
53 builder := builder | |
54 builderComponents := strings.SplitN(builder.Name, "/", 2
) | |
55 if len(builderComponents) != 2 { | |
56 taskC <- func() error { | |
57 return fmt.Errorf("%s is an invalid buil
der name", builder.Name) | |
58 } | |
59 return | |
60 } | |
61 master := builderComponents[0] | |
62 builderName := builderComponents[1] | |
63 taskC <- func() error { | |
64 t1 := clock.Now(c) | |
65 builds, err := getFullBuilds(c, master, builderN
ame, true) | |
66 if err != nil { | |
67 return err | |
68 } | |
69 t2 := clock.Now(c) | |
70 var currentStatus *model.Status | |
71 for j, commit := range commits { | |
72 for _, build := range builds { | |
73 if build.Sourcestamp.Revision ==
commit { | |
74 results[j][i] = &resp.Co
nsoleBuild{ | |
75 Link: resp.NewLi
nk( | |
76 strings.
Join(build.Text, " "), | |
77 fmt.Spri
ntf("/buildbot/%s/%s/%d", master, builderName, build.Number), | |
78 ), | |
79 Status: build.to
Status(), | |
80 } | |
81 currentStatus = &results
[j][i].Status | |
82 } | |
83 } | |
84 if currentStatus != nil && results[j][i]
== nil { | |
85 results[j][i] = &resp.ConsoleBui
ld{Status: *currentStatus} | |
86 } | |
87 } | |
88 log.Debugf(c, | |
89 "Builder %s took %s to query, %s to comp
ute.", builderName, | |
90 t2.Sub(t1), clock.Since(c, t2)) | |
91 return nil | |
92 } | |
93 } | |
94 }) | |
95 return results, err | |
96 } | |
OLD | NEW |