go.tools/dashboard/app: show sub-repository build history

LGTM=cmang
R=adonovan, gobot, cmang
CC=golang-codereviews
https://golang.org/cl/56410043
This commit is contained in:
Andrew Gerrand 2014-01-28 14:30:48 +11:00
parent 4dcb74e810
commit 5cb6365d33
3 changed files with 106 additions and 36 deletions

View File

@ -162,11 +162,11 @@ func (c *Commit) Result(builder, goHash string) *Result {
return nil
}
// Results returns the build Results for this Commit for the given goHash.
func (c *Commit) Results(goHash string) (results []*Result) {
// Results returns the build Results for this Commit.
func (c *Commit) Results() (results []*Result) {
for _, r := range c.ResultData {
p := strings.SplitN(r, "|", 4)
if len(p) != 4 || p[3] != goHash {
if len(p) != 4 {
continue
}
results = append(results, partsToHash(c, p))
@ -174,6 +174,39 @@ func (c *Commit) Results(goHash string) (results []*Result) {
return
}
func (c *Commit) ResultGoHashes() []string {
var hashes []string
for _, r := range c.ResultData {
p := strings.SplitN(r, "|", 4)
if len(p) != 4 {
continue
}
// Append only new results (use linear scan to preserve order).
if !contains(hashes, p[3]) {
hashes = append(hashes, p[3])
}
}
// Return results in reverse order (newest first).
reverse(hashes)
return hashes
}
func contains(t []string, s string) bool {
for _, s2 := range t {
if s2 == s {
return true
}
}
return false
}
func reverse(s []string) {
for i := 0; i < len(s)/2; i++ {
j := len(s) - i - 1
s[i], s[j] = s[j], s[i]
}
}
// partsToHash converts a Commit and ResultData substrings to a Result.
func partsToHash(c *Commit, p []string) *Result {
return &Result{

View File

@ -41,9 +41,11 @@ func uiHandler(w http.ResponseWriter, r *http.Request) {
if page < 0 {
page = 0
}
repo := r.FormValue("repo")
useCache := page == 0 && repo == ""
// Used cached version of front page, if available.
if page == 0 {
if useCache {
var b []byte
if cache.Get(r, now, key, &b) {
w.Write(b)
@ -51,16 +53,25 @@ func uiHandler(w http.ResponseWriter, r *http.Request) {
}
}
commits, err := dashCommits(c, page)
pkg := &Package{} // empty package is the main repository
if repo != "" {
var err error
pkg, err = GetPackage(c, repo)
if err != nil {
logErr(w, r, err)
return
}
}
commits, err := dashCommits(c, pkg, page)
if err != nil {
logErr(w, r, err)
return
}
builders := commitBuilders(commits, "")
builders := commitBuilders(commits)
var tipState *TagState
if page == 0 {
// only show sub-repo state on first page
if pkg.Kind == "" && page == 0 {
// only show sub-repo state on first page of normal repo view
tipState, err = TagStateByName(c, "tip")
if err != nil {
logErr(w, r, err)
@ -76,7 +87,7 @@ func uiHandler(w http.ResponseWriter, r *http.Request) {
p.Prev = page - 1
p.HasPrev = true
}
data := &uiTemplateData{d, commits, builders, tipState, p}
data := &uiTemplateData{d, pkg, commits, builders, tipState, p}
var buf bytes.Buffer
if err := uiTemplate.Execute(&buf, data); err != nil {
@ -85,7 +96,7 @@ func uiHandler(w http.ResponseWriter, r *http.Request) {
}
// Cache the front page.
if page == 0 {
if useCache {
cache.Set(r, now, key, buf.Bytes())
}
@ -99,9 +110,9 @@ type Pagination struct {
// dashCommits gets a slice of the latest Commits to the current dashboard.
// If page > 0 it paginates by commitsPerPage.
func dashCommits(c appengine.Context, page int) ([]*Commit, error) {
func dashCommits(c appengine.Context, pkg *Package, page int) ([]*Commit, error) {
q := datastore.NewQuery("Commit").
Ancestor((&Package{}).Key(c)).
Ancestor(pkg.Key(c)).
Order("-Num").
Limit(commitsPerPage).
Offset(page * commitsPerPage)
@ -112,10 +123,10 @@ func dashCommits(c appengine.Context, page int) ([]*Commit, error) {
// commitBuilders returns the names of the builders that provided
// Results for the provided commits.
func commitBuilders(commits []*Commit, goHash string) []string {
func commitBuilders(commits []*Commit) []string {
builders := make(map[string]bool)
for _, commit := range commits {
for _, r := range commit.Results(goHash) {
for _, r := range commit.Results() {
builders[r.Builder] = true
}
}
@ -211,6 +222,7 @@ func TagStateByName(c appengine.Context, name string) (*TagState, error) {
type uiTemplateData struct {
Dashboard *Dashboard
Package *Package
Commits []*Commit
Builders []string
TipState *TagState

View File

@ -76,11 +76,12 @@
<a href="{{.RelPath}}">{{.Name}}</a>
{{end}}
</nav>
{{with $.Package.Name}}<h2>{{.}}</h2>{{end}}
{{if $.Commits}}
<table class="build">
<colgroup class="col-hash"></colgroup>
<colgroup class="col-hash" {{if $.Package.Path}}span="2"{{end}}></colgroup>
{{range $.Builders | builderSpans}}
<colgroup class="col-result" span="{{.N}}"></colgroup>
{{end}}
@ -91,7 +92,11 @@
<!-- extra row to make alternating colors use dark for first result -->
</tr>
<tr>
{{if $.Package.Path}}
<th colspan="2">revision</th>
{{else}}
<th>&nbsp;</th>
{{end}}
{{range $.Builders | builderSpans}}
<th colspan="{{.N}}">{{.OS}}</th>
{{end}}
@ -100,38 +105,58 @@
<th></th>
</tr>
<tr>
{{if $.Package.Path}}
<th class="result arch">repo</th>
<th class="result arch">{{$.Dashboard.Name}}</th>
{{else}}
<th>&nbsp;</th>
{{end}}
{{range $.Builders}}
<th class="result arch" title="{{.}}">{{builderSubheading .}}</th>
{{end}}
</tr>
{{range $c := $.Commits}}
<tr class="commit">
<td class="hash"><a href="{{repoURL $.Dashboard.Name .Hash ""}}">{{shortHash .Hash}}</a></td>
{{range $.Builders}}
<td class="result">
{{with $c.Result . ""}}
{{if .OK}}
<span class="ok">ok</span>
{{else}}
<a href="{{$.Dashboard.RelPath}}log/{{.LogHash}}" class="fail">fail</a>
{{end}}
{{else}}
&nbsp;
{{end}}
</td>
{{range $i, $h := $c.ResultGoHashes}}
<tr class="commit">
{{if $i}}
<td>&nbsp;</td>
{{else}}
<td class="hash"><a href="{{repoURL $.Dashboard.Name $c.Hash $.Package.Path}}">{{shortHash $c.Hash}}</a></td>
{{end}}
<td class="user" title="{{.User}}">{{shortUser .User}}</td>
<td class="time">{{.Time.Format "Mon 02 Jan 15:04"}}</td>
<td class="desc" title="{{.Desc}}">{{shortDesc .Desc}}</td>
</tr>
{{if $h}}
<td class="hash"><a href="{{repoURL $.Dashboard.Name $h ""}}">{{shortHash $h}}</a></td>
{{end}}
{{range $.Builders}}
<td class="result">
{{with $c.Result . $h}}
{{if .OK}}
<span class="ok">ok</span>
{{else}}
<a href="{{$.Dashboard.RelPath}}log/{{.LogHash}}" class="fail">fail</a>
{{end}}
{{else}}
&nbsp;
{{end}}
</td>
{{end}}
{{if $i}}
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
{{else}}
<td class="user" title="{{$c.User}}">{{shortUser $c.User}}</td>
<td class="time">{{$c.Time.Format "Mon 02 Jan 15:04"}}</td>
<td class="desc" title="{{$c.Desc}}">{{shortDesc $c.Desc}}</td>
{{end}}
</tr>
{{end}}
{{end}}
</table>
{{with $.Pagination}}
<div class="paginate">
<a {{if .HasPrev}}href="?page={{.Prev}}"{{else}}class="inactive"{{end}}>newer</a>
<a {{if .Next}}href="?page={{.Next}}"{{else}}class="inactive"{{end}}>older</a>
<a {{if .HasPrev}}href="?{{with $.Package.Path}}repo={{.}}&{{end}}page={{.Prev}}"{{else}}class="inactive"{{end}}>newer</a>
<a {{if .Next}}href="?{{with $.Package.Path}}repo={{.}}&{{end}}page={{.Next}}"{{else}}class="inactive"{{end}}>older</a>
<a {{if .HasPrev}}href="."{{else}}class="inactive"{{end}}>latest</a>
</div>
{{end}}
@ -182,7 +207,7 @@
</tr>
{{range $pkg := .Packages}}
<tr class="commit">
<td><a title="{{.Package.Path}}">{{.Package.Name}}</a></td>
<td><a title="{{.Package.Path}}" href="?repo={{.Package.Path}}">{{.Package.Name}}</a></td>
<td class="hash">
{{$h := $pkg.Commit.Hash}}
<a href="{{repoURL $.Dashboard.Name $h $pkg.Commit.PackagePath}}">{{shortHash $h}}</a>