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

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

Issue 2978293002: [milo] Add an (uncached) method to get console rows. (Closed)
Patch Set: make manifestkey its own type Created 3 years, 5 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
« no previous file with comments | « milo/frontend/middleware.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "fmt" 19 "fmt"
20 "html/template"
19 "net/http" 21 "net/http"
20 "strings" 22 "strings"
21 23
22 "golang.org/x/net/context" 24 "golang.org/x/net/context"
23 25
24 "github.com/luci/luci-go/common/api/gitiles"
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"
29 "github.com/luci/luci-go/common/proto/google"
28 "github.com/luci/luci-go/server/router" 30 "github.com/luci/luci-go/server/router"
29 "github.com/luci/luci-go/server/templates" 31 "github.com/luci/luci-go/server/templates"
30 32
31 "github.com/luci/luci-go/milo/api/config" 33 "github.com/luci/luci-go/milo/api/config"
32 "github.com/luci/luci-go/milo/api/resp" 34 "github.com/luci/luci-go/milo/api/resp"
35 "github.com/luci/luci-go/milo/buildsource"
33 "github.com/luci/luci-go/milo/common" 36 "github.com/luci/luci-go/milo/common"
34 "github.com/luci/luci-go/milo/common/model" 37 "github.com/luci/luci-go/milo/common/model"
38 "github.com/luci/luci-go/milo/git"
35 ) 39 )
36 40
37 // Returns results of build[commit_index][builder_index]
38 func getConsoleBuilds(
39 c context.Context, builders []resp.BuilderRef, commits []string) (
40 [][]*model.BuildSummary, error) {
41
42 panic("Nothing to see here, check back later.")
43 }
44
45 // getConsoleDef finds the console definition as defined by any project. 41 // getConsoleDef finds the console definition as defined by any project.
46 // If the user is not a reader of the project, this will return a 404. 42 // If the user is not a reader of the project, this will return a 404.
47 // TODO(hinoka): If the user is not a reader of any of of the builders returned, 43 // TODO(hinoka): If the user is not a reader of any of of the builders returned,
48 // that builder will be removed from list of results. 44 // that builder will be removed from list of results.
49 func getConsoleDef(c context.Context, project, name string) (*config.Console, er ror) { 45 func getConsoleDef(c context.Context, project, name string) (*config.Console, er ror) {
50 cs, err := common.GetConsole(c, project, name) 46 cs, err := common.GetConsole(c, project, name)
51 if err != nil { 47 if err != nil {
52 return nil, err 48 return nil, err
53 } 49 }
54 // TODO(hinoka): Remove builders that the user does not have access to. 50 // TODO(hinoka): Remove builders that the user does not have access to.
55 return cs, nil 51 return cs, nil
56 } 52 }
57 53
58 func summaryToConsole(bs []*model.BuildSummary) []*resp.ConsoleBuild {
59 cb := make([]*resp.ConsoleBuild, 0, len(bs))
60 for _, b := range bs {
61 cb = append(cb, &resp.ConsoleBuild{
62 // TODO(hinoka): This should link to the actual build.
63 Link: resp.NewLink(b.BuildKey.String(), "#"),
64 Status: b.Summary.Status,
65 })
66 }
67 return cb
68 }
69
70 func console(c context.Context, project, name string) (*resp.Console, error) { 54 func console(c context.Context, project, name string) (*resp.Console, error) {
71 tStart := clock.Now(c) 55 tStart := clock.Now(c)
72 def, err := getConsoleDef(c, project, name) 56 def, err := getConsoleDef(c, project, name)
73 if err != nil { 57 if err != nil {
74 return nil, err 58 return nil, err
75 } 59 }
76 » commits, err := getCommits(c, def.RepoURL, def.Branch, 25) 60 » commitInfo, err := git.GetHistory(c, def.RepoURL, def.Branch, 25)
77 if err != nil { 61 if err != nil {
78 return nil, err 62 return nil, err
79 } 63 }
80 tGitiles := clock.Now(c) 64 tGitiles := clock.Now(c)
81 logging.Debugf(c, "Loading commits took %s.", tGitiles.Sub(tStart)) 65 logging.Debugf(c, "Loading commits took %s.", tGitiles.Sub(tStart))
82 » commitNames := make([]string, len(commits)) 66
83 » commitLinks := make([]*resp.Link, len(commits)) 67 » builderNames := make([]string, len(def.Builders))
84 » for i, commit := range commits { 68 » builders := make([]resp.BuilderRef, len(def.Builders))
85 » » commitNames[i] = commit.Revision.Label 69 » for i, b := range def.Builders {
86 » » commitLinks[i] = commit.Revision 70 » » builderNames[i] = b.Name
71 » » builders[i].Name = b.Name
72 » » builders[i].Category = strings.Split(b.Category, "|")
73 » » builders[i].ShortName = b.ShortName
87 } 74 }
88 75
89 » // HACK(hinoka): This only supports buildbot.... 76 » commitNames := make([]string, len(commitInfo.Commits))
90 » builders := make([]resp.BuilderRef, len(def.Builders)) 77 » for i, commit := range commitInfo.Commits {
91 » for i, b := range def.Builders { 78 » » commitNames[i] = hex.EncodeToString(commit.Hash)
92 » » builders[i] = resp.BuilderRef{
93 » » » b.Name, strings.Split(b.Category, "|"), b.ShortName,
94 » » }
95 } 79 }
96 » cb, err := getConsoleBuilds(c, builders, commitNames) 80 » rows, err := buildsource.GetConsoleRows(c, project, def, commitNames, bu ilderNames)
97 tConsole := clock.Now(c) 81 tConsole := clock.Now(c)
98 logging.Debugf(c, "Loading the console took a total of %s.", tConsole.Su b(tGitiles)) 82 logging.Debugf(c, "Loading the console took a total of %s.", tConsole.Su b(tGitiles))
99 if err != nil { 83 if err != nil {
100 return nil, err 84 return nil, err
101 } 85 }
102 » ccb := make([]resp.CommitBuild, len(commits)) 86
103 » for i, commit := range commitLinks { 87 » ccb := make([]resp.CommitBuild, len(commitInfo.Commits))
104 » » // TODO(hinoka): Not like this 88 » for row, commit := range commitInfo.Commits {
105 » » ccb[i].Commit = resp.Commit{Revision: commit} 89 » » ccb[row].Build = make([]*model.BuildSummary, len(builders))
106 » » ccb[i].Build = summaryToConsole(cb[i]) 90 » » ccb[row].Commit = resp.Commit{
91 » » » AuthorName: commit.AuthorName,
92 » » » AuthorEmail: commit.AuthorEmail,
93 » » » CommitTime: google.TimeFromProto(commit.CommitTime),
94 » » » Repo: def.RepoURL,
95 » » » Branch: def.Branch,
96 » » » Description: commit.Msg,
97 » » » Revision: resp.NewLink(commitNames[row], def.RepoURL+ "/+/"+commitNames[row]),
98 » » }
99
100 » » for col, b := range builders {
101 » » » name := buildsource.BuilderID(b.Name)
102 » » » if summaries := rows[row].Builds[name]; len(summaries) > 0 {
103 » » » » ccb[row].Build[col] = summaries[0]
104 » » » }
105 » » }
107 } 106 }
108 107
109 » cs := &resp.Console{ 108 » return &resp.Console{
110 Name: def.Name, 109 Name: def.Name,
111 Commit: ccb, 110 Commit: ccb,
112 BuilderRef: builders, 111 BuilderRef: builders,
112 }, nil
113 }
114
115 // consoleRenderer is a wrapper around Console to provide additional methods.
116 type consoleRenderer struct {
117 *resp.Console
118 }
119
120 // Header generates the console header html.
121 func (c consoleRenderer) Header() template.HTML {
122 // First, split things into nice rows and find the max depth.
123 cat := make([][]string, len(c.BuilderRef))
124 depth := 0
125 for i, b := range c.BuilderRef {
126 cat[i] = b.Category
127 if len(cat[i]) > depth {
128 depth = len(cat[i])
129 }
113 } 130 }
114 131
115 » return cs, nil 132 » result := ""
133 » for row := 0; row < depth; row++ {
134 » » result += "<tr><th></th>"
135 » » // "" is the first node, " " is an empty node.
136 » » current := ""
137 » » colspan := 0
138 » » for _, br := range cat {
139 » » » colspan++
140 » » » var s string
141 » » » if row >= len(br) {
142 » » » » s = " "
143 » » » } else {
144 » » » » s = br[row]
145 » » » }
146 » » » if s != current || current == " " {
147 » » » » if current != "" || current == " " {
148 » » » » » result += fmt.Sprintf(`<th colspan="%d"> %s</th>`, colspan, current)
149 » » » » » colspan = 0
150 » » » » }
151 » » » » current = s
152 » » » }
153 » » }
154 » » if colspan != 0 {
155 » » » result += fmt.Sprintf(`<th colspan="%d">%s</th>`, colspa n, current)
156 » » }
157 » » result += "</tr>"
158 » }
159
160 » // Last row: The actual builder shortnames.
161 » result += "<tr><th></th>"
162 » for _, br := range c.BuilderRef {
163 » » result += fmt.Sprintf("<th>%s</th>", br.ShortName)
164 » }
165 » result += "</tr>"
166 » return template.HTML(result)
116 } 167 }
117 168
118 func getCommits(c context.Context, repoURL, treeish string, limit int) ([]resp.C ommit, error) { 169 func (c consoleRenderer) BuilderLink(bs *model.BuildSummary) (*resp.Link, error) {
119 » commits, err := gitiles.Log(c, repoURL, treeish, limit) 170 » _, _, builderName, err := buildsource.BuilderID(bs.BuilderID).Split()
120 if err != nil { 171 if err != nil {
121 return nil, err 172 return nil, err
122 } 173 }
123 » result := make([]resp.Commit, len(commits)) 174 » return resp.NewLink(builderName, "/"+bs.BuilderID), nil
124 » for i, log := range commits {
125 » » result[i] = resp.Commit{
126 » » » AuthorName: log.Author.Name,
127 » » » AuthorEmail: log.Author.Email,
128 » » » Repo: repoURL,
129 » » » Revision: resp.NewLink(log.Commit, repoURL+"/+/"+log. Commit),
130 » » » Description: log.Message,
131 » » » Title: strings.SplitN(log.Message, "\n", 2)[0],
132 » » » // TODO(hinoka): Fill in the rest of resp.Commit and add those details
133 » » » // in the html.
134 » » }
135 » }
136 » return result, nil
137 } 175 }
138 176
139 // ConsoleHandler renders the console page. 177 // ConsoleHandler renders the console page.
140 func ConsoleHandler(c *router.Context) { 178 func ConsoleHandler(c *router.Context) {
141 project := c.Params.ByName("project") 179 project := c.Params.ByName("project")
142 if project == "" { 180 if project == "" {
143 ErrorHandler(c, errors.New("Missing Project", common.CodeParamet erError)) 181 ErrorHandler(c, errors.New("Missing Project", common.CodeParamet erError))
144 return 182 return
145 } 183 }
146 name := c.Params.ByName("name") 184 name := c.Params.ByName("name")
147 185
148 result, err := console(c.Context, project, name) 186 result, err := console(c.Context, project, name)
149 if err != nil { 187 if err != nil {
150 ErrorHandler(c, err) 188 ErrorHandler(c, err)
151 return 189 return
152 } 190 }
153 191
154 templates.MustRender(c.Context, c.Writer, "pages/console.html", template s.Args{ 192 templates.MustRender(c.Context, c.Writer, "pages/console.html", template s.Args{
155 » » "Console": result, 193 » » "Console": consoleRenderer{result},
156 }) 194 })
157 } 195 }
158 196
159 // ConsoleMainHandler is a redirect handler that redirects the user to the main 197 // ConsoleMainHandler is a redirect handler that redirects the user to the main
160 // console for a particular project. 198 // console for a particular project.
161 func ConsoleMainHandler(ctx *router.Context) { 199 func ConsoleMainHandler(ctx *router.Context) {
162 w, r, p := ctx.Writer, ctx.Request, ctx.Params 200 w, r, p := ctx.Writer, ctx.Request, ctx.Params
163 proj := p.ByName("project") 201 proj := p.ByName("project")
164 http.Redirect(w, r, fmt.Sprintf("/console/%s/main", proj), http.StatusMo vedPermanently) 202 http.Redirect(w, r, fmt.Sprintf("/console/%s/main", proj), http.StatusMo vedPermanently)
165 return 203 return
166 } 204 }
OLDNEW
« no previous file with comments | « milo/frontend/middleware.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698