cmd/coordinator: style the "trybot status" page

Load style.css so we share some styles with the Go Build Coordinator
homepage. Add some custom styles so text in tables is a little bigger
- there's less of it on the trybot page.

Instead of formatting to the nearest tenth of a minute, we can round
to the nearest second - Duration.Round() is now two Go versions old
- and use more natural duration formatting.

Instead of issuing many small writes to the ResponseWriter, write HTML
to a buffer and then write it to the ResponseWriter all at once. (We
should just use a template but that's a bigger project.)

Add a "/try-dev" handler you can enable with the `-dev` build tag
which makes it easy to view and test the "trybot status" page locally,
without requiring a builder.

Change-Id: I28617d02ed857c28d2bb2d9ccfb05ca9dc572212
Reviewed-on: https://go-review.googlesource.com/103870
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Kevin Burke 2018-04-01 17:47:40 -07:00 коммит произвёл Brad Fitzpatrick
Родитель 5298ba98fb
Коммит d742befa4d
3 изменённых файлов: 103 добавлений и 16 удалений

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

@ -4,9 +4,19 @@
Run
go install golang.org/x/build/cmd/coordinator && coordinator --mode=dev
go install golang.org/x/build/cmd/coordinator && coordinator --mode=dev --env=dev
to start a server on https://localhost:8119. Proceed past the TLS warning and
you should get the homepage. Some features won't work when running locally,
but you should be able to view the homepage and the builders page and do basic
sanity checks.
#### Render the "Trybot Status" page locally
To view/modify the "Trybot Status" page locally, you can build the coordinator
with the `-dev` tag.
go install -tags=dev golang.org/x/build/cmd/coordinator
Then start the coordinator and visit https://localhost:8119/try-dev in your
browser. You should see a trybot status page with some example data.

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

@ -622,21 +622,38 @@ func serveTryStatusJSON(w http.ResponseWriter, r *http.Request, ts *trySet, tss
w.Write(buf.Bytes())
}
// Styles unique to the trybot status page.
const tryStatusCSS = `
<style>
p {
line-height: 1.15em;
}
table {
font-size: 11pt;
}
</style>
`
// tss is a clone that does not require ts' lock.
func serveTryStatusHTML(w http.ResponseWriter, ts *trySet, tss trySetState) {
if ts == nil {
http.Error(w, "TryBot result not found (already done, invalid, or not yet discovered from Gerrit). Check Gerrit for results.", http.StatusNotFound)
return
}
buf := new(bytes.Buffer)
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<!DOCTYPE html><title>trybot status</title>")
fmt.Fprintf(w, "[<a href='/'>overall status</a>] &gt; %s\n", ts.ChangeID)
fmt.Fprintf(w, "<h1>trybot status</h1>")
fmt.Fprintf(w, "Change-ID: <a href='https://go-review.googlesource.com/#/q/%s'>%s</a><br>\n", ts.ChangeID, ts.ChangeID)
fmt.Fprintf(w, "Commit: <a href='https://go-review.googlesource.com/#/q/%s'>%s</a><br>\n", ts.Commit, ts.Commit)
fmt.Fprintf(w, "<p>Builds remain: %d</p>\n", tss.remain)
fmt.Fprintf(w, "<p>Builds</p>\n")
fmt.Fprintf(w, "<table cellpadding=5 border=0>\n")
buf.WriteString("<!DOCTYPE html><head><title>trybot status</title>")
buf.WriteString(`<link rel="stylesheet" href="/style.css"/>`)
buf.WriteString(tryStatusCSS)
buf.WriteString("</head><body>")
fmt.Fprintf(buf, "[<a href='/'>homepage</a>] &gt; %s\n", ts.ChangeID)
fmt.Fprintf(buf, "<h1>Trybot Status</h1>")
fmt.Fprintf(buf, "<p>Change-ID: <a href='https://go-review.googlesource.com/#/q/%s'>%s</a><br />\n", ts.ChangeID, ts.ChangeID)
fmt.Fprintf(buf, "Commit: <a href='https://go-review.googlesource.com/#/q/%s'>%s</a></p>\n", ts.Commit, ts.Commit)
fmt.Fprintf(buf, "<p>Builds remaining: %d</p>\n", tss.remain)
fmt.Fprintf(buf, "<h4>Builds</h4>\n")
fmt.Fprintf(buf, "<table cellpadding=5 border=0>\n")
for _, bs := range tss.builds {
var status string
bs.mu.Lock()
@ -647,13 +664,13 @@ func serveTryStatusHTML(w http.ResponseWriter, ts *trySet, tss trySetState) {
status = "<b>FAIL</b>"
}
} else {
status = fmt.Sprintf("<i>running</i> %.1f min", time.Since(bs.startTime).Minutes())
status = fmt.Sprintf("<i>running</i> %s", time.Since(bs.startTime).Round(time.Second))
}
bs.mu.Unlock()
fmt.Fprintf(w, "<tr><td>%s</td><td>%s</td></tr>\n", bs.Name, status)
fmt.Fprintf(buf, "<tr><td>&#8226; %s</td><td>%s</td></tr>\n", bs.Name, status)
}
fmt.Fprintf(w, "</table>\n")
fmt.Fprintf(w, "<p>Full Detail</p><table cellpadding=5 border=1>\n")
fmt.Fprintf(buf, "</table>\n")
fmt.Fprintf(buf, "<h4>Full Detail</h4><table cellpadding=5 border=1>\n")
for _, bs := range tss.builds {
status := "<i>(running)</i>"
bs.mu.Lock()
@ -665,12 +682,13 @@ func serveTryStatusHTML(w http.ResponseWriter, ts *trySet, tss trySetState) {
}
}
bs.mu.Unlock()
fmt.Fprintf(w, "<tr valign=top><td align=left>%s</td><td align=center>%s</td><td><pre>%s</pre></td></tr>\n",
fmt.Fprintf(buf, "<tr valign=top><td align=left>%s</td><td align=center>%s</td><td><pre>%s</pre></td></tr>\n",
bs.Name,
status,
bs.HTMLStatusLine())
}
fmt.Fprintf(w, "</table>")
fmt.Fprintf(buf, "</table>")
w.Write(buf.Bytes())
}
func trySetOfCommitPrefix(commitPrefix string) *trySet {
@ -3390,7 +3408,7 @@ func (st *buildStatus) htmlStatusLine(full bool) template.HTML {
if t.IsZero() {
t = st.startTime
}
fmt.Fprintf(&buf, ", %v ago", time.Since(t))
fmt.Fprintf(&buf, ", %v ago", time.Since(t).Round(time.Second))
if full {
buf.WriteByte('\n')
st.writeEventsLocked(&buf, true)

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

@ -0,0 +1,59 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file is designed to make it easier to do local development of the styles
// for the trybot status page, by creating a set of builders with dummy data.
// Compile it into the binary by running go install -tags=dev, then load the
// dummy data at /try-dev in your browser.
// +build dev
package main
import (
"net/http"
"time"
"golang.org/x/build/buildlet"
"golang.org/x/build/internal/buildgo"
)
func init() {
ts := &trySet{
tryKey: tryKey{
Project: "go",
Branch: "master",
ChangeID: "I1936e2dbe90634817f1aedabcba3c2b9f94e401b",
Commit: "555cfa3ee5e9f3df4b10c96af487424bfde19125",
},
tryID: "T4bfde19125",
trySetState: trySetState{
failed: []string{"failed-build"},
remain: 1,
builds: []*buildStatus{
&buildStatus{
BuilderRev: buildgo.BuilderRev{
Name: "linux-amd64-race",
Rev: "555cfa3ee5e9f3df4b10c96af487424bfde19125",
},
startTime: time.Now(),
bc: &buildlet.Client{},
},
&buildStatus{
BuilderRev: buildgo.BuilderRev{
Name: "darwin-amd64-race",
Rev: "555cfa3ee5e9f3df4b10c96af487424bfde19125",
},
startTime: time.Now(),
done: time.Now().Add(3 * time.Minute),
bc: &buildlet.Client{},
},
},
},
}
http.HandleFunc("/try-dev", func(w http.ResponseWriter, r *http.Request) {
tss := ts.trySetState.clone()
serveTryStatusHTML(w, ts, tss)
})
}