dashboard/app: support for showing links to build-in-progress status

Update golang/go#9494

Change-Id: I849d9f8ed423d29daede167193704dbda26785b1
Reviewed-on: https://go-review.googlesource.com/2590
Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
Brad Fitzpatrick 2015-01-08 14:48:50 -08:00
Родитель 2a5d0a0069
Коммит 24fcf016e1
5 изменённых файлов: 102 добавлений и 5 удалений

Просмотреть файл

@ -13,7 +13,7 @@ handlers:
static_dir: static
- url: /(|gccgo/|hg/)log/.+
script: _go_app
- url: /(|gccgo/|hg/)(|clear-results|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark)
- url: /(|gccgo/|hg/)(|building|clear-results|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark)
script: _go_app
- url: /(|gccgo/|hg/)(init|buildtest|key|perflearn|_ah/queue/go/delay)
script: _go_app

Просмотреть файл

@ -78,6 +78,10 @@ func GetPackage(c appengine.Context, path string) (*Package, error) {
return p, err
}
type builderAndGoHash struct {
builder, goHash string
}
// A Commit describes an individual commit in a package.
//
// Each Commit entity is a descendant of its associated Package entity.
@ -107,6 +111,8 @@ type Commit struct {
PerfResults []string `datastore:",noindex"`
FailNotificationSent bool
buildingURLs map[builderAndGoHash]string
}
func (com *Commit) Key(c appengine.Context) *datastore.Key {
@ -216,12 +222,24 @@ func min(a, b int) int {
// 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 {
if !strings.HasPrefix(r, builder) {
// Avoid strings.SplitN alloc in the common case.
continue
}
p := strings.SplitN(r, "|", 4)
if len(p) != 4 || p[0] != builder || p[3] != goHash {
continue
}
return partsToResult(c, p)
}
if u, ok := c.buildingURLs[builderAndGoHash{builder, goHash}]; ok {
return &Result{
Builder: builder,
BuildingURL: u,
Hash: c.Hash,
GoHash: goHash,
}
}
return nil
}
@ -409,9 +427,10 @@ type Result struct {
// The Go Commit this was built against (empty for Go commits).
GoHash string
OK bool
Log string `datastore:"-"` // for JSON unmarshaling only
LogHash string `datastore:",noindex"` // Key to the Log record.
BuildingURL string `datastore:"-"` // non-empty if currently building
OK bool
Log string `datastore:"-"` // for JSON unmarshaling only
LogHash string `datastore:",noindex"` // Key to the Log record.
RunTime int64 // time to build+test in nanoseconds
}

Просмотреть файл

@ -17,10 +17,12 @@ import (
"net/http"
"strconv"
"strings"
"time"
"unicode/utf8"
"appengine"
"appengine/datastore"
"appengine/memcache"
"cache"
"key"
@ -516,6 +518,29 @@ func packagesHandler(r *http.Request) (interface{}, error) {
return p, nil
}
// buildingHandler records that a build is in progress.
// The data is only stored in memcache and with a timeout. It's assumed
// that the build system will periodically refresh this if the build
// is slow.
func buildingHandler(r *http.Request) (interface{}, error) {
if r.Method != "POST" {
return nil, errBadMethod(r.Method)
}
c := contextForRequest(r)
key := fmt.Sprintf("building|%s|%s|%s", r.FormValue("hash"), r.FormValue("gohash"), r.FormValue("builder"))
err := memcache.Set(c, &memcache.Item{
Key: key,
Value: []byte(r.FormValue("url")),
Expiration: 15 * time.Minute,
})
if err != nil {
return nil, err
}
return map[string]interface{}{
"key": key,
}, nil
}
// resultHandler records a build result.
// It reads a JSON-encoded Result value from the request body,
// creates a new Result entity, and updates the relevant Commit entity.
@ -909,6 +934,7 @@ func init() {
handleFunc("/key", keyHandler)
// authenticated handlers
handleFunc("/building", AuthHandler(buildingHandler))
handleFunc("/clear-results", AuthHandler(clearResultsHandler))
handleFunc("/commit", AuthHandler(commitHandler))
handleFunc("/packages", AuthHandler(packagesHandler))

Просмотреть файл

@ -27,6 +27,7 @@ import (
"appengine"
"appengine/datastore"
"appengine/memcache"
)
func init() {
@ -97,6 +98,7 @@ func uiHandler(w http.ResponseWriter, r *http.Request) {
p.HasPrev = true
}
data := &uiTemplateData{d, pkg, commits, builders, tipState, p, branch}
data.populateBuildingURLs(c)
switch r.FormValue("mode") {
case "failures":
@ -376,6 +378,54 @@ type uiTemplateData struct {
Branch string
}
// populateBuildingURLs populates each commit in Commits' buildingURLs map with the
// URLs of builds which are currently in progress.
func (td *uiTemplateData) populateBuildingURLs(ctx appengine.Context) {
// need are memcache keys: "building|<hash>|<gohash>|<builder>"
// The hash is of the main "go" repo, or the subrepo commit hash.
// The gohash is empty for the main repo, else it's the Go hash.
var need []string
commit := map[string]*Commit{} // commit hash -> Commit
// TODO(bradfitz): this only populates the main repo, not subpackages currently.
for _, b := range td.Builders {
for _, c := range td.Commits {
if c.Result(b, "") == nil {
commit[c.Hash] = c
need = append(need, "building|"+c.Hash+"||"+b)
}
}
}
if len(need) == 0 {
return
}
m, err := memcache.GetMulti(ctx, need)
if err != nil {
// oh well. this is a cute non-critical feature anyway.
ctx.Debugf("GetMulti of building keys: %v", err)
return
}
for k, it := range m {
f := strings.SplitN(k, "|", 4)
if len(f) != 4 {
continue
}
hash, goHash, builder := f[1], f[2], f[3]
c, ok := commit[hash]
if !ok {
continue
}
m := c.buildingURLs
if m == nil {
m = make(map[builderAndGoHash]string)
c.buildingURLs = m
}
m[builderAndGoHash{builder, goHash}] = string(it.Value)
}
}
var uiTemplate = template.Must(
template.New("ui.html").Funcs(tmplFuncs).ParseFiles("build/ui.html"),
)

Просмотреть файл

@ -96,7 +96,9 @@
{{range $.Builders}}
<td class="result{{if (unsupported .)}} unsupported{{end}}">
{{with $c.Result . $h}}
{{if .OK}}
{{if .BuildingURL}}
<a href="{{.BuildingURL}}"><img src="https://golang.org/favicon.ico" border=0></a>
{{else if .OK}}
<span class="ok">ok</span>
{{else}}
<a href="{{$.Dashboard.Prefix}}/log/{{.LogHash}}" class="fail">fail</a>