Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: go/buildbot/ingest.go

Issue 796883002: buildbot package: actually find commits for each build during ingestion (Closed) Base URL: https://skia.googlesource.com/buildbot@master
Patch Set: Pretty format the JSON Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « go/buildbot/db.go ('k') | go/buildbot/testdata/builders_android.json » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 package buildbot 1 package buildbot
2 2
3 import ( 3 import (
4 "encoding/json" 4 "encoding/json"
5 "fmt" 5 "fmt"
6 "net/http" 6 "net/http"
7 "sync" 7 "sync"
8 "time" 8 "time"
9
10 "skia.googlesource.com/buildbot.git/go/gitinfo"
9 ) 11 )
10 12
11 var ( 13 var (
12 // TODO(borenet): Avoid hard-coding this list. Instead, obtain it from 14 // TODO(borenet): Avoid hard-coding this list. Instead, obtain it from
13 // checked-in code or the set of masters which are actually running. 15 // checked-in code or the set of masters which are actually running.
14 MASTER_NAMES = []string{"client.skia", "client.skia.android", "client.sk ia.compile", "client.skia.fyi"} 16 MASTER_NAMES = []string{"client.skia", "client.skia.android", "client.sk ia.compile", "client.skia.fyi"}
15 httpGet = http.Get 17 httpGet = http.Get
16 ) 18 )
17 19
18 // get loads data from a buildbot JSON endpoint. 20 // get loads data from a buildbot JSON endpoint.
19 func get(url string, rv interface{}) error { 21 func get(url string, rv interface{}) error {
20 resp, err := httpGet(url) 22 resp, err := httpGet(url)
21 if err != nil { 23 if err != nil {
22 return fmt.Errorf("Failed to GET %s: %v", url, err) 24 return fmt.Errorf("Failed to GET %s: %v", url, err)
23 } 25 }
24 dec := json.NewDecoder(resp.Body) 26 dec := json.NewDecoder(resp.Body)
25 if err := dec.Decode(rv); err != nil { 27 if err := dec.Decode(rv); err != nil {
26 return fmt.Errorf("Failed to decode JSON: %v", err) 28 return fmt.Errorf("Failed to decode JSON: %v", err)
27 } 29 }
28 return nil 30 return nil
29 } 31 }
30 32
33 // findCommitsRecursive is a recursive function called by findCommitsForBuild.
34 // It traces the history to find builds which were first included in the given
35 // build.
36 func findCommitsRecursive(b *Build, hash string, repo *gitinfo.GitInfo) ([]strin g, error) {
37 // Shortcut for empty hashes. This can happen when a commit has no
38 // parents (initial commit) or when a Build has no GotRevision.
39 if hash == "" {
40 return []string{}, nil
41 }
42
43 // Determine whether any build already includes this commit.
44 n, err := GetBuildForCommit(b.MasterName, b.BuilderName, hash)
45 if err != nil {
46 return nil, fmt.Errorf("Could not find build for commit %s: %v", hash, err)
47 }
48 // If so, stop.
49 if n >= 0 {
50 return []string{}, nil
51 }
52
53 // Recurse on the commit's parents.
54 c, err := repo.Details(hash)
55 if err != nil {
56 return nil, fmt.Errorf("Failed to obtain details for %s: %v", ha sh, err)
57 }
58 commits := []string{hash}
59 for _, p := range c.Parents {
60 moreCommits, err := findCommitsRecursive(b, p, repo)
61 if err != nil {
62 return nil, err
63 }
64 commits = append(commits, moreCommits...)
65 }
66 return commits, nil
67 }
68
69 // findCommitsForBuild determines which commits were first included in the
70 // given build. Assumes that all previous builds for the given builder/master
71 // are already in the database.
72 func findCommitsForBuild(b *Build, repo *gitinfo.GitInfo) ([]string, error) {
73 return findCommitsRecursive(b, b.GotRevision, repo)
74 }
75
31 // getBuildFromMaster retrieves the given build from the build master's JSON 76 // getBuildFromMaster retrieves the given build from the build master's JSON
32 // interface as specified by the master, builder, and build number. 77 // interface as specified by the master, builder, and build number.
33 func getBuildFromMaster(master, builder string, buildNumber int) (*Build, error) { 78 func getBuildFromMaster(master, builder string, buildNumber int, repo *gitinfo.G itInfo) (*Build, error) {
34 var build Build 79 var build Build
35 url := fmt.Sprintf("%s%s/json/builders/%s/builds/%d", BUILDBOT_URL, mast er, builder, buildNumber) 80 url := fmt.Sprintf("%s%s/json/builders/%s/builds/%d", BUILDBOT_URL, mast er, builder, buildNumber)
36 err := get(url, &build) 81 err := get(url, &build)
37 if err != nil { 82 if err != nil {
38 return nil, fmt.Errorf("Failed to retrieve build #%v for %v: %v" , buildNumber, builder, err) 83 return nil, fmt.Errorf("Failed to retrieve build #%v for %v: %v" , buildNumber, builder, err)
39 } 84 }
40 build.Branch = build.branch() 85 build.Branch = build.branch()
41 build.GotRevision = build.gotRevision() 86 build.GotRevision = build.gotRevision()
42 build.MasterName = master 87 build.MasterName = master
43 slaveProp := build.GetProperty("slavename").([]interface{}) 88 slaveProp := build.GetProperty("slavename").([]interface{})
(...skipping 18 matching lines...) Expand all
62 s.ResultsRaw[0] = 0.0 107 s.ResultsRaw[0] = 0.0
63 } 108 }
64 s.Results = int(s.ResultsRaw[0].(float64)) 109 s.Results = int(s.ResultsRaw[0].(float64))
65 } else { 110 } else {
66 s.Results = 0 111 s.Results = 0
67 } 112 }
68 s.Started = s.Times[0] 113 s.Started = s.Times[0]
69 s.Finished = s.Times[1] 114 s.Finished = s.Times[1]
70 } 115 }
71 116
72 » // TODO(borenet): Actually find the commits for this build. 117 » // Find the commits for this build.
73 » build.Commits = []string{} 118 » commits, err := findCommitsForBuild(&build, repo)
119 » if err != nil {
120 » » return nil, fmt.Errorf("Could not find commits for build: %v", e rr)
121 » }
122 » build.Commits = commits
74 123
75 return &build, nil 124 return &build, nil
76 } 125 }
77 126
78 // GetBuildFromMaster retrieves the given build from the build master's JSON 127 // retryGetBuildFromMaster retrieves the given build from the build master's JSO N
79 // interface as specified by the master, builder, and build number. Makes 128 // interface as specified by the master, builder, and build number. Makes
80 // multiple attempts in case the master fails to respond. 129 // multiple attempts in case the master fails to respond.
81 func GetBuildFromMaster(master, builder string, buildNumber int) (*Build, error) { 130 func retryGetBuildFromMaster(master, builder string, buildNumber int, repo *giti nfo.GitInfo) (*Build, error) {
82 var b *Build 131 var b *Build
83 var err error 132 var err error
84 for attempt := 0; attempt < 3; attempt++ { 133 for attempt := 0; attempt < 3; attempt++ {
85 » » b, err = getBuildFromMaster(master, builder, buildNumber) 134 » » b, err = getBuildFromMaster(master, builder, buildNumber, repo)
86 if err == nil { 135 if err == nil {
87 break 136 break
88 } 137 }
89 time.Sleep(500 * time.Millisecond) 138 time.Sleep(500 * time.Millisecond)
90 } 139 }
91 return b, err 140 return b, err
92 } 141 }
93 142
94 // IngestBuild retrieves the given build from the build master's JSON interface 143 // IngestBuild retrieves the given build from the build master's JSON interface
95 // and pushes it into the database. 144 // and pushes it into the database.
96 func IngestBuild(master, builder string, buildNumber int) error { 145 func IngestBuild(master, builder string, buildNumber int, repo *gitinfo.GitInfo) error {
97 » b, err := GetBuildFromMaster(master, builder, buildNumber) 146 » b, err := retryGetBuildFromMaster(master, builder, buildNumber, repo)
98 if err != nil { 147 if err != nil {
99 return fmt.Errorf("Failed to load build from master: %v", err) 148 return fmt.Errorf("Failed to load build from master: %v", err)
100 } 149 }
101 return b.ReplaceIntoDB() 150 return b.ReplaceIntoDB()
102 } 151 }
103 152
104 // getLatestBuilds returns a map whose keys are master names and values are 153 // getLatestBuilds returns a map whose keys are master names and values are
105 // sub-maps whose keys are builder names and values are build numbers 154 // sub-maps whose keys are builder names and values are build numbers
106 // representing the newest build for each builder/master pair. 155 // representing the newest build for each builder/master pair.
107 func getLatestBuilds() (map[string]map[string]int, error) { 156 func getLatestBuilds() (map[string]map[string]int, error) {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 } 245 }
197 } 246 }
198 if len(masterMap) > 0 { 247 if len(masterMap) > 0 {
199 unprocessed[m] = masterMap 248 unprocessed[m] = masterMap
200 } 249 }
201 } 250 }
202 return unprocessed, nil 251 return unprocessed, nil
203 } 252 }
204 253
205 // IngestNewBuilds finds the set of uningested builds and ingests them. 254 // IngestNewBuilds finds the set of uningested builds and ingests them.
206 func IngestNewBuilds() error { 255 func IngestNewBuilds(repo *gitinfo.GitInfo) error {
207 // TODO(borenet): Investigate the use of channels here. We should be 256 // TODO(borenet): Investigate the use of channels here. We should be
208 // able to start ingesting builds as the data becomes available rather 257 // able to start ingesting builds as the data becomes available rather
209 // than waiting until the end. 258 // than waiting until the end.
210 buildsToProcess, err := getUningestedBuilds() 259 buildsToProcess, err := getUningestedBuilds()
211 if err != nil { 260 if err != nil {
212 return fmt.Errorf("Failed to obtain the set of uningested builds : %v", err) 261 return fmt.Errorf("Failed to obtain the set of uningested builds : %v", err)
213 } 262 }
214 unfinished, err := getUnfinishedBuilds() 263 unfinished, err := getUnfinishedBuilds()
215 if err != nil { 264 if err != nil {
216 return fmt.Errorf("Failed to obtain the set of unfinished builds : %v", err) 265 return fmt.Errorf("Failed to obtain the set of unfinished builds : %v", err)
217 } 266 }
218 for _, b := range unfinished { 267 for _, b := range unfinished {
219 if _, ok := buildsToProcess[b.MasterName]; !ok { 268 if _, ok := buildsToProcess[b.MasterName]; !ok {
220 buildsToProcess[b.MasterName] = map[string][]int{} 269 buildsToProcess[b.MasterName] = map[string][]int{}
221 } 270 }
222 if _, ok := buildsToProcess[b.BuilderName]; !ok { 271 if _, ok := buildsToProcess[b.BuilderName]; !ok {
223 buildsToProcess[b.MasterName][b.BuilderName] = []int{} 272 buildsToProcess[b.MasterName][b.BuilderName] = []int{}
224 } 273 }
225 buildsToProcess[b.MasterName][b.BuilderName] = append(buildsToPr ocess[b.MasterName][b.BuilderName], b.Number) 274 buildsToProcess[b.MasterName][b.BuilderName] = append(buildsToPr ocess[b.MasterName][b.BuilderName], b.Number)
226 } 275 }
227 // TODO(borenet): Figure out how much of this is safe to parallelize. 276 // TODO(borenet): Figure out how much of this is safe to parallelize.
228 // We can definitely do different masters in parallel, and maybe we can 277 // We can definitely do different masters in parallel, and maybe we can
229 // ingest different builders in parallel as well. 278 // ingest different builders in parallel as well.
230 for m, v := range buildsToProcess { 279 for m, v := range buildsToProcess {
231 for b, w := range v { 280 for b, w := range v {
232 for _, n := range w { 281 for _, n := range w {
233 » » » » if err := IngestBuild(m, b, n); err != nil { 282 » » » » if err := IngestBuild(m, b, n, repo); err != nil {
234 return fmt.Errorf("Failed to ingest buil d: %v", err) 283 return fmt.Errorf("Failed to ingest buil d: %v", err)
235 } 284 }
236 } 285 }
237 } 286 }
238 } 287 }
239 return nil 288 return nil
240 } 289 }
OLDNEW
« no previous file with comments | « go/buildbot/db.go ('k') | go/buildbot/testdata/builders_android.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698