x/tools/dashboard/app: update to support git

This adds a "Git" dashboard at "/git/", which has its own namespace for
datastore and memcache. Once we have pushed out the new git repositories
we will spin up a commit watcher and builders that point to the Git
dashboard.

Once we are ready to switch the dashboard over to the new Git builders,
the (*Dashboard).Context method will be changed to return "Git"
as the default namespace. The old builders will be retired, and the
new builders will be configured to report to "/" instead of "/git/".
At that point all our old data will still be available in the default
namespace, but hidden from view.

LGTM=dsymonds, cmang
R=bradfitz, cmang, dsymonds, adg
CC=golang-codereviews
https://golang.org/cl/183050043
This commit is contained in:
Andrew Gerrand 2014-12-04 10:45:11 +11:00
parent 4ed659d592
commit 2d83fa5bf1
15 changed files with 124 additions and 54 deletions

View File

@ -11,11 +11,11 @@ api_version: go1
handlers: handlers:
- url: /static - url: /static
static_dir: static static_dir: static
- url: /(|gccgo/)log/.+ - url: /(|gccgo/|git/)log/.+
script: _go_app script: _go_app
- url: /(|gccgo/)(|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark) - url: /(|gccgo/|git/)(|commit|packages|result|perf-result|tag|todo|perf|perfdetail|perfgraph|updatebenchmark)
script: _go_app script: _go_app
- url: /(|gccgo/)(init|buildtest|key|perflearn|_ah/queue/go/delay) - url: /(|gccgo/|git/)(init|buildtest|key|perflearn|_ah/queue/go/delay)
script: _go_app script: _go_app
login: admin login: admin

View File

@ -13,18 +13,27 @@ import (
"appengine" "appengine"
) )
func handleFunc(path string, h http.HandlerFunc) {
for _, d := range dashboards {
http.HandleFunc(d.Prefix+path, h)
}
}
// Dashboard describes a unique build dashboard. // Dashboard describes a unique build dashboard.
type Dashboard struct { type Dashboard struct {
Name string // This dashboard's name and namespace Name string // This dashboard's name and namespace
RelPath string // The relative url path Prefix string // The path prefix (no trailing /)
Packages []*Package // The project's packages to build Packages []*Package // The project's packages to build
} }
// dashboardForRequest returns the appropriate dashboard for a given URL path. // dashboardForRequest returns the appropriate dashboard for a given URL path.
func dashboardForRequest(r *http.Request) *Dashboard { func dashboardForRequest(r *http.Request) *Dashboard {
if strings.HasPrefix(r.URL.Path, gccgoDash.RelPath) { if strings.HasPrefix(r.URL.Path, gccgoDash.Prefix) {
return gccgoDash return gccgoDash
} }
if strings.HasPrefix(r.URL.Path, gitDash.Prefix) {
return gitDash
}
return goDash return goDash
} }
@ -43,12 +52,12 @@ func (d *Dashboard) Context(c appengine.Context) appengine.Context {
} }
// the currently known dashboards. // the currently known dashboards.
var dashboards = []*Dashboard{goDash, gccgoDash} var dashboards = []*Dashboard{goDash, gitDash, gccgoDash}
// goDash is the dashboard for the main go repository. // goDash is the dashboard for the main go repository.
var goDash = &Dashboard{ var goDash = &Dashboard{
Name: "Go", Name: "Go",
RelPath: "/", Prefix: "",
Packages: goPackages, Packages: goPackages,
} }
@ -105,10 +114,71 @@ var goPackages = []*Package{
}, },
} }
// gitDash is the dashboard for the main go repository on git.
var gitDash = &Dashboard{
Name: "Git",
Prefix: "/git",
Packages: gitPackages,
}
// gitPackages is a list of all of the packages built by the main go repository
// on git.
var gitPackages = []*Package{
{
Kind: "go",
Name: "Go",
},
{
Kind: "subrepo",
Name: "blog",
Path: "golang.org/x/blog",
},
{
Kind: "subrepo",
Name: "codereview",
Path: "golang.org/x/codereview",
},
{
Kind: "subrepo",
Name: "crypto",
Path: "golang.org/x/crypto",
},
{
Kind: "subrepo",
Name: "exp",
Path: "golang.org/x/exp",
},
{
Kind: "subrepo",
Name: "image",
Path: "golang.org/x/image",
},
{
Kind: "subrepo",
Name: "net",
Path: "golang.org/x/net",
},
{
Kind: "subrepo",
Name: "sys",
Path: "golang.org/x/sys",
},
{
Kind: "subrepo",
Name: "talks",
Path: "golang.org/x/talks",
},
{
Kind: "subrepo",
Name: "tools",
Path: "golang.org/x/tools",
},
}
// gccgoDash is the dashboard for gccgo. // gccgoDash is the dashboard for gccgo.
var gccgoDash = &Dashboard{ var gccgoDash = &Dashboard{
Name: "Gccgo", Name: "Gccgo",
RelPath: "/gccgo/", Prefix: "/gccgo",
Packages: []*Package{ Packages: []*Package{
{ {
Kind: "gccgo", Kind: "gccgo",

View File

@ -841,22 +841,20 @@ func keyHandler(w http.ResponseWriter, r *http.Request) {
} }
func init() { func init() {
for _, d := range dashboards { // admin handlers
// admin handlers handleFunc("/init", initHandler)
http.HandleFunc(d.RelPath+"init", initHandler) handleFunc("/key", keyHandler)
http.HandleFunc(d.RelPath+"key", keyHandler)
// authenticated handlers // authenticated handlers
http.HandleFunc(d.RelPath+"commit", AuthHandler(commitHandler)) handleFunc("/commit", AuthHandler(commitHandler))
http.HandleFunc(d.RelPath+"packages", AuthHandler(packagesHandler)) handleFunc("/packages", AuthHandler(packagesHandler))
http.HandleFunc(d.RelPath+"result", AuthHandler(resultHandler)) handleFunc("/result", AuthHandler(resultHandler))
http.HandleFunc(d.RelPath+"perf-result", AuthHandler(perfResultHandler)) handleFunc("/perf-result", AuthHandler(perfResultHandler))
http.HandleFunc(d.RelPath+"tag", AuthHandler(tagHandler)) handleFunc("/tag", AuthHandler(tagHandler))
http.HandleFunc(d.RelPath+"todo", AuthHandler(todoHandler)) handleFunc("/todo", AuthHandler(todoHandler))
// public handlers // public handlers
http.HandleFunc(d.RelPath+"log/", logHandler) handleFunc("/log/", logHandler)
}
} }
func validHash(hash string) bool { func validHash(hash string) bool {

View File

@ -33,6 +33,7 @@ func initHandler(w http.ResponseWriter, r *http.Request) {
logErr(w, r, err) logErr(w, r, err)
return return
} }
p.NextNum = 1 // So we can add the first commit.
if _, err := datastore.Put(c, p.Key(c), p); err != nil { if _, err := datastore.Put(c, p.Key(c), p); err != nil {
logErr(w, r, err) logErr(w, r, err)
return return

View File

@ -19,7 +19,7 @@ import (
) )
func init() { func init() {
http.HandleFunc("/perf", perfChangesHandler) handleFunc("/perf", perfChangesHandler)
} }
// perfSummaryHandler draws the main benchmarking page. // perfSummaryHandler draws the main benchmarking page.

View File

@ -8,9 +8,9 @@
<header id="topbar"> <header id="topbar">
<h1>Go Dashboard</h1> <h1>Go Dashboard</h1>
<nav> <nav>
<a href="{{$.Dashboard.RelPath}}">Test</a> <a href="{{$.Dashboard.Prefix}}/">Test</a>
<a href="{{$.Dashboard.RelPath}}perf">Perf</a> <a href="{{$.Dashboard.Prefix}}/perf">Perf</a>
<a href="{{$.Dashboard.RelPath}}perfgraph">Graphs</a> <a href="{{$.Dashboard.Prefix}}/perfgraph">Graphs</a>
</nav> </nav>
<div class="clear"></div> <div class="clear"></div>
</header> </header>

View File

@ -20,9 +20,7 @@ import (
) )
func init() { func init() {
for _, d := range dashboards { handleFunc("/perfdetail", perfDetailUIHandler)
http.HandleFunc(d.RelPath+"perfdetail", perfDetailUIHandler)
}
} }
func perfDetailUIHandler(w http.ResponseWriter, r *http.Request) { func perfDetailUIHandler(w http.ResponseWriter, r *http.Request) {

View File

@ -21,9 +21,9 @@
<header id="topbar"> <header id="topbar">
<h1>Go Dashboard</h1> <h1>Go Dashboard</h1>
<nav> <nav>
<a href="{{$.Dashboard.RelPath}}">Test</a> <a href="{{$.Dashboard.Prefix}}/">Test</a>
<a href="{{$.Dashboard.RelPath}}perf">Perf</a> <a href="{{$.Dashboard.Prefix}}/perf">Perf</a>
<a href="{{$.Dashboard.RelPath}}perfgraph">Graphs</a> <a href="{{$.Dashboard.Prefix}}/perfgraph">Graphs</a>
</nav> </nav>
<div class="clear"></div> <div class="clear"></div>
</header> </header>
@ -74,12 +74,12 @@
<tr> <tr>
<td class="metric">{{$m.Name}}</td> <td class="metric">{{$m.Name}}</td>
{{if $m.Link0}} {{if $m.Link0}}
<td><a href="{{$.Dashboard.RelPath}}{{$m.Link0}}">{{$m.Val0}}</td> <td><a href="{{$.Dashboard.Prefix}}/{{$m.Link0}}">{{$m.Val0}}</td>
{{else}} {{else}}
<td>{{$m.Val0}}</td> <td>{{$m.Val0}}</td>
{{end}} {{end}}
{{if $m.Link1}} {{if $m.Link1}}
<td><a href="{{$.Dashboard.RelPath}}{{$m.Link1}}">{{$m.Val1}}</td> <td><a href="{{$.Dashboard.Prefix}}/{{$m.Link1}}">{{$m.Val1}}</td>
{{else}} {{else}}
<td>{{$m.Val1}}</td> <td>{{$m.Val1}}</td>
{{end}} {{end}}

View File

@ -18,9 +18,7 @@ import (
) )
func init() { func init() {
for _, d := range dashboards { handleFunc("/perfgraph", perfGraphHandler)
http.HandleFunc(d.RelPath+"perfgraph", perfGraphHandler)
}
} }
func perfGraphHandler(w http.ResponseWriter, r *http.Request) { func perfGraphHandler(w http.ResponseWriter, r *http.Request) {

View File

@ -53,9 +53,9 @@
<header id="topbar"> <header id="topbar">
<h1>Go Dashboard</h1> <h1>Go Dashboard</h1>
<nav> <nav>
<a href="{{$.Dashboard.RelPath}}">Test</a> <a href="{{$.Dashboard.Prefix}}/">Test</a>
<a href="{{$.Dashboard.RelPath}}perf">Perf</a> <a href="{{$.Dashboard.Prefix}}/perf">Perf</a>
<a href="{{$.Dashboard.RelPath}}perfgraph">Graphs</a> <a href="{{$.Dashboard.Prefix}}/perfgraph">Graphs</a>
</nav> </nav>
<div class="clear"></div> <div class="clear"></div>
</header> </header>

View File

@ -18,7 +18,7 @@ import (
) )
func init() { func init() {
http.HandleFunc("/perflearn", perfLearnHandler) handleFunc("/perflearn", perfLearnHandler)
} }
const ( const (

View File

@ -26,7 +26,7 @@ import (
) )
func init() { func init() {
http.HandleFunc("/buildtest", testHandler) handleFunc("/buildtest", testHandler)
} }
var testEntityKinds = []string{ var testEntityKinds = []string{

View File

@ -27,9 +27,7 @@ import (
) )
func init() { func init() {
for _, d := range dashboards { handleFunc("/", uiHandler)
http.HandleFunc(d.RelPath, uiHandler)
}
} }
// uiHandler draws the build status page. // uiHandler draws the build status page.
@ -437,7 +435,14 @@ func repoURL(dashboard, hash, packagePath string) (string, error) {
if dashboard == "Gccgo" { if dashboard == "Gccgo" {
return "https://code.google.com/p/gofrontend/source/detail?r=" + hash, nil return "https://code.google.com/p/gofrontend/source/detail?r=" + hash, nil
} }
return "https://code.google.com/p/go/source/detail?r=" + hash, nil if dashboard == "Git" {
return "https://go.googlesource.com/go/+/" + hash, nil
}
return "https://golang.org/change/" + hash, nil
}
if dashboard == "Git" {
repo := strings.TrimPrefix(packagePath, "golang.org/x/")
return "https://go.googlesource.com/" + repo + "/+/" + hash, nil
} }
m := repoRe.FindStringSubmatch(packagePath) m := repoRe.FindStringSubmatch(packagePath)
if m == nil { if m == nil {

View File

@ -22,16 +22,16 @@
<header id="topbar"> <header id="topbar">
<h1>Go Dashboard</h1> <h1>Go Dashboard</h1>
<nav> <nav>
<a href="{{$.Dashboard.RelPath}}">Test</a> <a href="{{$.Dashboard.Prefix}}/">Test</a>
<a href="{{$.Dashboard.RelPath}}perf">Perf</a> <a href="{{$.Dashboard.Prefix}}/perf">Perf</a>
<a href="{{$.Dashboard.RelPath}}perfgraph">Graphs</a> <a href="{{$.Dashboard.Prefix}}/perfgraph">Graphs</a>
</nav> </nav>
<div class="clear"></div> <div class="clear"></div>
</header> </header>
<nav class="dashboards"> <nav class="dashboards">
{{range buildDashboards}} {{range buildDashboards}}
<a href="{{.RelPath}}">{{.Name}}</a> <a href="{{.Prefix}}/">{{.Name}}</a>
{{end}} {{end}}
<label> <label>
<input type=checkbox id="showshort"> <input type=checkbox id="showshort">
@ -99,7 +99,7 @@
{{if .OK}} {{if .OK}}
<span class="ok">ok</span> <span class="ok">ok</span>
{{else}} {{else}}
<a href="{{$.Dashboard.RelPath}}log/{{.LogHash}}" class="fail">fail</a> <a href="{{$.Dashboard.Prefix}}/log/{{.LogHash}}" class="fail">fail</a>
{{end}} {{end}}
{{else}} {{else}}
&nbsp; &nbsp;
@ -187,7 +187,7 @@
{{if .OK}} {{if .OK}}
<span class="ok">ok</span> <span class="ok">ok</span>
{{else}} {{else}}
<a href="{{$.Dashboard.RelPath}}log/{{.LogHash}}" class="fail">fail</a> <a href="{{$.Dashboard.Prefix}}/log/{{.LogHash}}" class="fail">fail</a>
{{end}} {{end}}
{{else}} {{else}}
&nbsp; &nbsp;

View File

@ -16,7 +16,7 @@ import (
) )
func init() { func init() {
http.HandleFunc("/updatebenchmark", updateBenchmark) handleFunc("/updatebenchmark", updateBenchmark)
} }
func updateBenchmark(w http.ResponseWriter, r *http.Request) { func updateBenchmark(w http.ResponseWriter, r *http.Request) {