Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(617)

Side by Side Diff: milo/frontend/view_console.go

Issue 2991243002: Milo: Console improvements (Closed)
Patch Set: Small fixes Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The LUCI Authors. 1 // Copyright 2017 The LUCI Authors.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 package frontend 15 package frontend
16 16
17 import ( 17 import (
18 "encoding/hex" 18 "encoding/hex"
19 "fmt" 19 "fmt"
20 "html/template" 20 "html/template"
21 "net/http" 21 "net/http"
22 "strings"
22 23
23 "golang.org/x/net/context" 24 "golang.org/x/net/context"
24 25
25 "github.com/luci/luci-go/common/clock" 26 "github.com/luci/luci-go/common/clock"
26 "github.com/luci/luci-go/common/errors" 27 "github.com/luci/luci-go/common/errors"
27 "github.com/luci/luci-go/common/logging" 28 "github.com/luci/luci-go/common/logging"
28 "github.com/luci/luci-go/common/proto/google" 29 "github.com/luci/luci-go/common/proto/google"
29 "github.com/luci/luci-go/server/router" 30 "github.com/luci/luci-go/server/router"
30 "github.com/luci/luci-go/server/templates" 31 "github.com/luci/luci-go/server/templates"
31 32
(...skipping 10 matching lines...) Expand all
42 // that builder will be removed from list of results. 43 // that builder will be removed from list of results.
43 func getConsoleDef(c context.Context, project, name string) (*common.Console, er ror) { 44 func getConsoleDef(c context.Context, project, name string) (*common.Console, er ror) {
44 cs, err := common.GetConsole(c, project, name) 45 cs, err := common.GetConsole(c, project, name)
45 if err != nil { 46 if err != nil {
46 return nil, err 47 return nil, err
47 } 48 }
48 // TODO(hinoka): Remove builders that the user does not have access to. 49 // TODO(hinoka): Remove builders that the user does not have access to.
49 return cs, nil 50 return cs, nil
50 } 51 }
51 52
52 func console(c context.Context, project, name string) (*resp.Console, error) { 53 // shortname returns the short if given, otherwise tries to calculate
54 // a short name out of a long.
55 func shortname(short, long string) string {
dnj 2017/08/02 23:33:04 This "short" logic is weird. IMO, just have the ca
dnj 2017/08/02 23:33:04 What is "short" and "long" expected to be? Can you
Ryan Tseng 2017/08/03 00:46:12 Done.
56 » if short != "" {
57 » » return short
58 » }
59 » builderName := strings.SplitN(long, "/", 3)[2]
dnj 2017/08/02 23:33:05 This makes the assumption that "long" has at least
Ryan Tseng 2017/08/03 00:46:12 Done.
60 » tokens := strings.FieldsFunc(builderName, func(r rune) bool {
61 » » switch r {
62 » » case '_', '-', ' ':
63 » » » return true
64 » » }
65 » » return false
66 » })
67 » numLetters := len(tokens)
68 » if numLetters > 3 {
69 » » numLetters = 3
70 » }
71 » for i := 0; i < numLetters; i++ {
72 » » short += string(tokens[i][0])
dnj 2017/08/02 23:33:05 If the string has two delimiters (e.g., "--"), wou
dnj 2017/08/02 23:33:05 Why the string cast?
Ryan Tseng 2017/08/03 00:46:12 Done. And apparently the index of a string is a r
73 » }
74 » return strings.ToLower(short)
75 }
76
77 func console(c context.Context, project, name string, limit int) (*resp.Console, error) {
53 tStart := clock.Now(c) 78 tStart := clock.Now(c)
54 def, err := getConsoleDef(c, project, name) 79 def, err := getConsoleDef(c, project, name)
55 if err != nil { 80 if err != nil {
56 return nil, err 81 return nil, err
57 } 82 }
58 » commitInfo, err := git.GetHistory(c, def.RepoURL, def.Ref, 25) 83 » commitInfo, err := git.GetHistory(c, def.RepoURL, def.Ref, limit)
59 if err != nil { 84 if err != nil {
60 return nil, err 85 return nil, err
61 } 86 }
62 tGitiles := clock.Now(c) 87 tGitiles := clock.Now(c)
63 logging.Debugf(c, "Loading commits took %s.", tGitiles.Sub(tStart)) 88 logging.Debugf(c, "Loading commits took %s.", tGitiles.Sub(tStart))
64 89
65 builderNames := make([]string, len(def.Builders))
66 builders := make([]resp.BuilderRef, len(def.Builders))
67 for i, b := range def.Builders {
68 builderNames[i] = b
69 builders[i].Name = b
70 _, _, builders[i].ShortName, _ = buildsource.BuilderID(b).Split( )
71 // TODO(hinoka): Add Categories back in.
72 }
73
74 commitNames := make([]string, len(commitInfo.Commits)) 90 commitNames := make([]string, len(commitInfo.Commits))
75 for i, commit := range commitInfo.Commits { 91 for i, commit := range commitInfo.Commits {
76 commitNames[i] = hex.EncodeToString(commit.Hash) 92 commitNames[i] = hex.EncodeToString(commit.Hash)
77 } 93 }
78 » rows, err := buildsource.GetConsoleRows(c, project, def, commitNames, bu ilderNames) 94
95 » builderRefs := make([]resp.BuilderRef, len(def.Builders))
dnj 2017/08/02 23:33:05 Define this down near the "for" loop that uses it?
Ryan Tseng 2017/08/03 00:46:12 Done.
96 » rows, err := buildsource.GetConsoleRows(c, project, def, commitNames, de f.Builders)
79 tConsole := clock.Now(c) 97 tConsole := clock.Now(c)
80 logging.Debugf(c, "Loading the console took a total of %s.", tConsole.Su b(tGitiles)) 98 logging.Debugf(c, "Loading the console took a total of %s.", tConsole.Su b(tGitiles))
81 if err != nil { 99 if err != nil {
82 return nil, err 100 return nil, err
83 } 101 }
84 102
85 ccb := make([]resp.CommitBuild, len(commitInfo.Commits)) 103 ccb := make([]resp.CommitBuild, len(commitInfo.Commits))
86 for row, commit := range commitInfo.Commits { 104 for row, commit := range commitInfo.Commits {
87 » » ccb[row].Build = make([]*model.BuildSummary, len(builders)) 105 » » ccb[row].Build = make([]*model.BuildSummary, len(def.Builders))
88 ccb[row].Commit = resp.Commit{ 106 ccb[row].Commit = resp.Commit{
89 AuthorName: commit.AuthorName, 107 AuthorName: commit.AuthorName,
90 AuthorEmail: commit.AuthorEmail, 108 AuthorEmail: commit.AuthorEmail,
91 CommitTime: google.TimeFromProto(commit.CommitTime), 109 CommitTime: google.TimeFromProto(commit.CommitTime),
92 Repo: def.RepoURL, 110 Repo: def.RepoURL,
93 Branch: def.Ref, // TODO(hinoka): Actually this doe sn't match, change branch to ref. 111 Branch: def.Ref, // TODO(hinoka): Actually this doe sn't match, change branch to ref.
94 Description: commit.Msg, 112 Description: commit.Msg,
95 Revision: resp.NewLink(commitNames[row], def.RepoURL+ "/+/"+commitNames[row]), 113 Revision: resp.NewLink(commitNames[row], def.RepoURL+ "/+/"+commitNames[row]),
96 } 114 }
97 115
98 » » for col, b := range builders { 116 » » for col, b := range def.Builders {
99 » » » name := buildsource.BuilderID(b.Name) 117 » » » meta := def.BuilderMetas[col]
118 » » » builderRefs[col] = resp.BuilderRef{
119 » » » » Name: b,
120 » » » » Category: strings.Split(meta.Category, "|"),
121 » » » » ShortName: shortname(meta.ShortName, b),
122 » » » }
123 » » » name := buildsource.BuilderID(b)
100 if summaries := rows[row].Builds[name]; len(summaries) > 0 { 124 if summaries := rows[row].Builds[name]; len(summaries) > 0 {
101 ccb[row].Build[col] = summaries[0] 125 ccb[row].Build[col] = summaries[0]
102 } 126 }
103 } 127 }
104 } 128 }
105 129
106 return &resp.Console{ 130 return &resp.Console{
107 Name: def.ID, 131 Name: def.ID,
108 Commit: ccb, 132 Commit: ccb,
109 » » BuilderRef: builders, 133 » » BuilderRef: builderRefs,
110 }, nil 134 }, nil
111 } 135 }
112 136
113 // consoleRenderer is a wrapper around Console to provide additional methods. 137 // consoleRenderer is a wrapper around Console to provide additional methods.
114 type consoleRenderer struct { 138 type consoleRenderer struct {
115 *resp.Console 139 *resp.Console
116 } 140 }
117 141
118 // Header generates the console header html. 142 // Header generates the console header html.
119 func (c consoleRenderer) Header() template.HTML { 143 func (c consoleRenderer) Header() template.HTML {
(...skipping 29 matching lines...) Expand all
149 current = s 173 current = s
150 } 174 }
151 } 175 }
152 if colspan != 0 { 176 if colspan != 0 {
153 result += fmt.Sprintf(`<th colspan="%d">%s</th>`, colspa n, current) 177 result += fmt.Sprintf(`<th colspan="%d">%s</th>`, colspa n, current)
154 } 178 }
155 result += "</tr>" 179 result += "</tr>"
156 } 180 }
157 181
158 // Last row: The actual builder shortnames. 182 // Last row: The actual builder shortnames.
159 result += "<tr><th></th><th></th>" 183 result += "<tr><th></th><th></th>"
dnj 2017/08/02 23:33:04 nit: for this sort of construction, it's better to
Ryan Tseng 2017/08/03 00:46:13 Done.
160 for _, br := range c.BuilderRef { 184 for _, br := range c.BuilderRef {
161 » » result += fmt.Sprintf("<th>%s</th>", br.ShortName) 185 » » _, _, builderName, err := buildsource.BuilderID(br.Name).Split()
186 » » if err != nil {
187 » » » builderName = err.Error()
dnj 2017/08/02 23:33:05 This seems not very user-friendly :x Perhaps set t
Ryan Tseng 2017/08/03 00:46:13 Good idea. Done.
188 » » }
189 » » result += fmt.Sprintf(
190 » » » "<th><a href=\"/%s\" title=\"%s\">%s</a></th>",
191 » » » br.Name, builderName, br.ShortName)
162 } 192 }
163 result += "</tr>" 193 result += "</tr>"
164 return template.HTML(result) 194 return template.HTML(result)
165 } 195 }
166 196
167 func (c consoleRenderer) BuilderLink(bs *model.BuildSummary) (*resp.Link, error) { 197 func (c consoleRenderer) BuilderLink(bs *model.BuildSummary) (*resp.Link, error) {
168 _, _, builderName, err := buildsource.BuilderID(bs.BuilderID).Split() 198 _, _, builderName, err := buildsource.BuilderID(bs.BuilderID).Split()
169 if err != nil { 199 if err != nil {
170 return nil, err 200 return nil, err
171 } 201 }
172 return resp.NewLink(builderName, "/"+bs.BuilderID), nil 202 return resp.NewLink(builderName, "/"+bs.BuilderID), nil
173 } 203 }
174 204
175 // ConsoleHandler renders the console page. 205 // ConsoleHandler renders the console page.
176 func ConsoleHandler(c *router.Context) { 206 func ConsoleHandler(c *router.Context) {
177 project := c.Params.ByName("project") 207 project := c.Params.ByName("project")
178 if project == "" { 208 if project == "" {
179 ErrorHandler(c, errors.New("Missing Project", common.CodeParamet erError)) 209 ErrorHandler(c, errors.New("Missing Project", common.CodeParamet erError))
180 return 210 return
181 } 211 }
182 name := c.Params.ByName("name") 212 name := c.Params.ByName("name")
213 limit := 25
dnj 2017/08/02 23:33:04 Define this as a constant at the top?
Ryan Tseng 2017/08/03 00:46:12 If it's not reused it's better to be defined close
dnj 2017/08/03 01:02:58 Meh fine, then you can inline: const maxLimit = 1
214 if tLimit := GetLimit(c.Request, -1); tLimit >= 0 {
215 limit = tLimit
dnj 2017/08/02 23:33:05 Should we apply an upper bound here?
Ryan Tseng 2017/08/03 00:46:12 Okay 1000 it is
216 }
183 217
184 » result, err := console(c.Context, project, name) 218 » result, err := console(c.Context, project, name, limit)
185 if err != nil { 219 if err != nil {
186 ErrorHandler(c, err) 220 ErrorHandler(c, err)
187 return 221 return
188 } 222 }
189 223
190 templates.MustRender(c.Context, c.Writer, "pages/console.html", template s.Args{ 224 templates.MustRender(c.Context, c.Writer, "pages/console.html", template s.Args{
191 "Console": consoleRenderer{result}, 225 "Console": consoleRenderer{result},
192 }) 226 })
193 } 227 }
194 228
195 // ConsoleMainHandler is a redirect handler that redirects the user to the main 229 // ConsoleMainHandler is a redirect handler that redirects the user to the main
196 // console for a particular project. 230 // console for a particular project.
197 func ConsoleMainHandler(ctx *router.Context) { 231 func ConsoleMainHandler(ctx *router.Context) {
198 w, r, p := ctx.Writer, ctx.Request, ctx.Params 232 w, r, p := ctx.Writer, ctx.Request, ctx.Params
199 proj := p.ByName("project") 233 proj := p.ByName("project")
200 http.Redirect(w, r, fmt.Sprintf("/console/%s/main", proj), http.StatusMo vedPermanently) 234 http.Redirect(w, r, fmt.Sprintf("/console/%s/main", proj), http.StatusMo vedPermanently)
201 return 235 return
202 } 236 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698