зеркало из https://github.com/golang/build.git
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:
Родитель
2a5d0a0069
Коммит
24fcf016e1
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче