summaryrefslogtreecommitdiff
path: root/misc/dashboard/app
diff options
context:
space:
mode:
Diffstat (limited to 'misc/dashboard/app')
-rw-r--r--misc/dashboard/app/app.yaml2
-rw-r--r--misc/dashboard/app/build/build.go46
-rw-r--r--misc/dashboard/app/build/handler.go2
-rw-r--r--misc/dashboard/app/build/init.go9
-rw-r--r--misc/dashboard/app/build/notify.go29
-rw-r--r--misc/dashboard/app/build/test.go33
-rw-r--r--misc/dashboard/app/build/ui.go5
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":