diff options
Diffstat (limited to 'misc/dashboard/app')
-rw-r--r-- | misc/dashboard/app/app.yaml | 2 | ||||
-rw-r--r-- | misc/dashboard/app/build/build.go | 46 | ||||
-rw-r--r-- | misc/dashboard/app/build/handler.go | 2 | ||||
-rw-r--r-- | misc/dashboard/app/build/init.go | 9 | ||||
-rw-r--r-- | misc/dashboard/app/build/notify.go | 29 | ||||
-rw-r--r-- | misc/dashboard/app/build/test.go | 33 | ||||
-rw-r--r-- | misc/dashboard/app/build/ui.go | 5 |
7 files changed, 86 insertions, 40 deletions
diff --git a/misc/dashboard/app/app.yaml b/misc/dashboard/app/app.yaml index 6e19db09c..c5a1f6cb8 100644 --- a/misc/dashboard/app/app.yaml +++ b/misc/dashboard/app/app.yaml @@ -6,7 +6,7 @@ application: golang-org version: build runtime: go -api_version: go1beta +api_version: go1 handlers: - url: /static diff --git a/misc/dashboard/app/build/build.go b/misc/dashboard/app/build/build.go index c49fa8bb2..e0c0f0048 100644 --- a/misc/dashboard/app/build/build.go +++ b/misc/dashboard/app/build/build.go @@ -49,6 +49,10 @@ func (p *Package) LastCommit(c appengine.Context) (*Commit, error) { Order("-Time"). Limit(1). GetAll(c, &commits) + if _, ok := err.(*datastore.ErrFieldMismatch); ok { + // Some fields have been removed, so it's okay to ignore this error. + err = nil + } if err != nil { return nil, err } @@ -65,6 +69,10 @@ func GetPackage(c appengine.Context, path string) (*Package, error) { if err == datastore.ErrNoSuchEntity { return nil, fmt.Errorf("package %q not found", path) } + if _, ok := err.(*datastore.ErrFieldMismatch); ok { + // Some fields have been removed, so it's okay to ignore this error. + err = nil + } return p, err } @@ -111,19 +119,35 @@ func (c *Commit) Valid() error { return nil } +// each result line is approx 105 bytes. This constant is a tradeoff between +// build history and the AppEngine datastore limit of 1mb. +const maxResults = 1000 + // AddResult adds the denormalized Reuslt data to the Commit's Result field. // It must be called from inside a datastore transaction. func (com *Commit) AddResult(c appengine.Context, r *Result) error { if err := datastore.Get(c, com.Key(c), com); err != nil { return fmt.Errorf("getting Commit: %v", err) } - com.ResultData = append(com.ResultData, r.Data()) + com.ResultData = trim(append(com.ResultData, r.Data()), maxResults) if _, err := datastore.Put(c, com.Key(c), com); err != nil { return fmt.Errorf("putting Commit: %v", err) } return nil } +func trim(s []string, n int) []string { + l := min(len(s), n) + return s[len(s)-l:] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + // Result returns the build Result for this Commit for the given builder/goHash. func (c *Commit) Result(builder, goHash string) *Result { for _, r := range c.ResultData { @@ -160,20 +184,11 @@ func partsToHash(c *Commit, p []string) *Result { } } -// OK returns the Commit's build state for a specific builder and goHash. -func (c *Commit) OK(builder, goHash string) (ok, present bool) { - r := c.Result(builder, goHash) - if r == nil { - return false, false - } - return r.OK, true -} - // A Result describes a build result for a Commit on an OS/architecture. // // Each Result entity is a descendant of its associated Commit entity. type Result struct { - Builder string // "arch-os[-note]" + Builder string // "os-arch[-note]" Hash string PackagePath string // (empty for Go commits) @@ -184,7 +199,7 @@ type Result struct { Log string `datastore:"-"` // for JSON unmarshaling only LogHash string `datastore:",noindex"` // Key to the Log record. - RunTime int64 // time to build+test in nanoseconds + RunTime int64 // time to build+test in nanoseconds } func (r *Result) Key(c appengine.Context) *datastore.Key { @@ -297,7 +312,12 @@ func Packages(c appengine.Context, kind string) ([]*Package, error) { q := datastore.NewQuery("Package").Filter("Kind=", kind) for t := q.Run(c); ; { pkg := new(Package) - if _, err := t.Next(pkg); err == datastore.Done { + _, err := t.Next(pkg) + if _, ok := err.(*datastore.ErrFieldMismatch); ok { + // Some fields have been removed, so it's okay to ignore this error. + err = nil + } + if err == datastore.Done { break } else if err != nil { return nil, err diff --git a/misc/dashboard/app/build/handler.go b/misc/dashboard/app/build/handler.go index 5d1e3094c..1a1118641 100644 --- a/misc/dashboard/app/build/handler.go +++ b/misc/dashboard/app/build/handler.go @@ -322,7 +322,7 @@ func resultHandler(r *http.Request) (interface{}, error) { // logHandler displays log text for a given hash. // It handles paths like "/log/hash". func logHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-type", "text/plain") + w.Header().Set("Content-type", "text/plain; charset=utf-8") c := appengine.NewContext(r) hash := r.URL.Path[len("/log/"):] key := datastore.NewKey(c, "Log", hash, 0, nil) diff --git a/misc/dashboard/app/build/init.go b/misc/dashboard/app/build/init.go index 5311688b7..85a766b9d 100644 --- a/misc/dashboard/app/build/init.go +++ b/misc/dashboard/app/build/init.go @@ -24,6 +24,8 @@ var subRepos = []string{ "crypto", "image", "net", + "talks", + "exp", } // Put subRepos into defaultPackages. @@ -42,7 +44,12 @@ func initHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) defer cache.Tick(c) for _, p := range defaultPackages { - if err := datastore.Get(c, p.Key(c), new(Package)); err == nil { + err := datastore.Get(c, p.Key(c), new(Package)) + if _, ok := err.(*datastore.ErrFieldMismatch); ok { + // Some fields have been removed, so it's okay to ignore this error. + err = nil + } + if err == nil { continue } else if err != datastore.ErrNoSuchEntity { logErr(w, r, err) diff --git a/misc/dashboard/app/build/notify.go b/misc/dashboard/app/build/notify.go index e02344ca8..52b91f6c1 100644 --- a/misc/dashboard/app/build/notify.go +++ b/misc/dashboard/app/build/notify.go @@ -21,6 +21,13 @@ const ( domain = "build.golang.org" ) +// failIgnore is a set of builders that we don't email about because +// they're too flaky. +var failIgnore = map[string]bool{ + "netbsd-386-bsiegert": true, + "netbsd-amd64-bsiegert": true, +} + // notifyOnFailure checks whether the supplied Commit or the subsequent // Commit (if present) breaks the build for this builder. // If either of those commits break the build an email notification is sent @@ -30,6 +37,10 @@ const ( // This must be run in a datastore transaction, and the provided *Commit must // have been retrieved from the datastore within that transaction. func notifyOnFailure(c appengine.Context, com *Commit, builder string) error { + if failIgnore[builder] { + return nil + } + // TODO(adg): implement notifications for packages if com.PackagePath != "" { return nil @@ -37,15 +48,15 @@ func notifyOnFailure(c appengine.Context, com *Commit, builder string) error { p := &Package{Path: com.PackagePath} var broken *Commit - ok, present := com.OK(builder, "") - if !present { + cr := com.Result(builder, "") + if cr == nil { return fmt.Errorf("no result for %s/%s", com.Hash, builder) } q := datastore.NewQuery("Commit").Ancestor(p.Key(c)) - if ok { + if cr.OK { // This commit is OK. Notify if next Commit is broken. next := new(Commit) - q.Filter("ParentHash=", com.Hash) + q = q.Filter("ParentHash=", com.Hash) if err := firstMatch(c, q, next); err != nil { if err == datastore.ErrNoSuchEntity { // OK at tip, no notification necessary. @@ -53,13 +64,15 @@ func notifyOnFailure(c appengine.Context, com *Commit, builder string) error { } return err } - if ok, present := next.OK(builder, ""); present && !ok { + if nr := next.Result(builder, ""); nr != nil && !nr.OK { + c.Debugf("commit ok: %#v\nresult: %#v", com, cr) + c.Debugf("next commit broken: %#v\nnext result:%#v", next, nr) broken = next } } else { // This commit is broken. Notify if the previous Commit is OK. prev := new(Commit) - q.Filter("Hash=", com.ParentHash) + q = q.Filter("Hash=", com.ParentHash) if err := firstMatch(c, q, prev); err != nil { if err == datastore.ErrNoSuchEntity { // No previous result, let the backfill of @@ -68,7 +81,9 @@ func notifyOnFailure(c appengine.Context, com *Commit, builder string) error { } return err } - if ok, present := prev.OK(builder, ""); present && ok { + if pr := prev.Result(builder, ""); pr != nil && pr.OK { + c.Debugf("commit broken: %#v\nresult: %#v", com, cr) + c.Debugf("previous commit ok: %#v\nprevious result:%#v", prev, pr) broken = com } } diff --git a/misc/dashboard/app/build/test.go b/misc/dashboard/app/build/test.go index d8470fec1..7e5539236 100644 --- a/misc/dashboard/app/build/test.go +++ b/misc/dashboard/app/build/test.go @@ -43,14 +43,15 @@ var testPackages = []*Package{ var tCommitTime = time.Now().Add(-time.Hour * 24 * 7) -func tCommit(hash, parentHash string) *Commit { +func tCommit(hash, parentHash, path string) *Commit { tCommitTime.Add(time.Hour) // each commit should have a different time return &Commit{ - Hash: hash, - ParentHash: parentHash, - Time: tCommitTime, - User: "adg", - Desc: "change description", + PackagePath: path, + Hash: hash, + ParentHash: parentHash, + Time: tCommitTime, + User: "adg", + Desc: "change description " + hash, } } @@ -64,9 +65,9 @@ var testRequests = []struct { {"/packages?kind=subrepo", nil, nil, []*Package{testPackage}}, // Go repo - {"/commit", nil, tCommit("0001", "0000"), nil}, - {"/commit", nil, tCommit("0002", "0001"), nil}, - {"/commit", nil, tCommit("0003", "0002"), nil}, + {"/commit", nil, tCommit("0001", "0000", ""), nil}, + {"/commit", nil, tCommit("0002", "0001", ""), nil}, + {"/commit", nil, tCommit("0003", "0002", ""), nil}, {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, {"/result", nil, &Result{Builder: "linux-386", Hash: "0001", OK: true}, nil}, @@ -81,12 +82,12 @@ var testRequests = []struct { {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0002"}}}, // branches - {"/commit", nil, tCommit("0004", "0003"), nil}, - {"/commit", nil, tCommit("0005", "0002"), nil}, + {"/commit", nil, tCommit("0004", "0003", ""), nil}, + {"/commit", nil, tCommit("0005", "0002", ""), nil}, {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}}, {"/result", nil, &Result{Builder: "linux-386", Hash: "0005", OK: true}, nil}, {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0004"}}}, - {"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: true}, nil}, + {"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: false}, nil}, {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, // logs @@ -98,9 +99,9 @@ var testRequests = []struct { {"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: "test"}, nil}, // non-Go repos - {"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1001", ParentHash: "1000"}, nil}, - {"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1002", ParentHash: "1001"}, nil}, - {"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1003", ParentHash: "1002"}, nil}, + {"/commit", nil, tCommit("1001", "1000", testPkg), nil}, + {"/commit", nil, tCommit("1002", "1001", testPkg), nil}, + {"/commit", nil, tCommit("1003", "1002", testPkg), nil}, {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1003"}}}, {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0001", OK: true}, nil}, {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1002"}}}, @@ -230,7 +231,7 @@ func testHandler(w http.ResponseWriter, r *http.Request) { return } } - fmt.Fprint(w, "PASS") + fmt.Fprint(w, "PASS\nYou should see only one mail notification (for 0003/linux-386) in the dev_appserver logs.") } func nukeEntities(c appengine.Context, kinds []string) error { diff --git a/misc/dashboard/app/build/ui.go b/misc/dashboard/app/build/ui.go index 0337aa306..cc3629a5a 100644 --- a/misc/dashboard/app/build/ui.go +++ b/misc/dashboard/app/build/ui.go @@ -97,7 +97,7 @@ type Pagination struct { func goCommits(c appengine.Context, page int) ([]*Commit, error) { q := datastore.NewQuery("Commit"). Ancestor((&Package{}).Key(c)). - Order("-Time"). + Order("-Num"). Limit(commitsPerPage). Offset(page * commitsPerPage) var commits []*Commit @@ -211,6 +211,9 @@ func builderArch(s string) string { // builderArchShort returns a short arch tag for a builder string func builderArchShort(s string) string { + if s == "linux-amd64-race" { + return "race" + } arch := builderArch(s) switch arch { case "amd64": |