1
2 from twisted.web import html
3 from twisted.web.util import Redirect, DeferredResource
4 from twisted.internet import defer, reactor
5
6 import urllib, time
7 from twisted.python import log
8 from buildbot.status.web.base import HtmlResource, make_row, make_stop_form, \
9 make_extra_property_row, css_classes, path_to_builder, path_to_slave, \
10 make_name_user_passwd_form, getAndCheckProperties
11
12
13 from buildbot.status.web.tests import TestsResource
14 from buildbot.status.web.step import StepsResource
15 from buildbot import version, util
16
17
19 addSlash = True
20
21 - def __init__(self, build_status, build_control, builder_control):
26
31
32 - def body(self, req):
33 b = self.build_status
34 status = self.getStatus(req)
35 projectName = status.getProjectName()
36 projectURL = status.getProjectURL()
37 data = ('<div class="title"><a href="%s">%s</a></div>\n'
38 % (self.path_to_root(req), projectName))
39 builder_name = b.getBuilder().getName()
40 data += ("<h1><a href=\"%s\">Builder %s</a>: Build #%d</h1>\n"
41 % (path_to_builder(req, b.getBuilder()),
42 builder_name, b.getNumber()))
43
44 if not b.isFinished():
45 data += "<h2>Build In Progress</h2>"
46 when = b.getETA()
47 if when is not None:
48 when_time = time.strftime("%H:%M:%S",
49 time.localtime(time.time() + when))
50 data += "<div>ETA %ds (%s)</div>\n" % (when, when_time)
51
52 if self.build_control is not None:
53 stopURL = urllib.quote(req.childLink("stop"))
54 data += make_stop_form(stopURL, self.isUsingUserPasswd(req))
55
56 if b.isFinished():
57
58 results = b.getResults()
59 data += "<h2>Results:</h2>\n"
60 text = " ".join(b.getText())
61 data += '<span class="%s">%s</span>\n' % (css_classes[results],
62 text)
63 if b.getTestResults():
64 url = req.childLink("tests")
65 data += "<h3><a href=\"%s\">test results</a></h3>\n" % url
66
67 ss = b.getSourceStamp()
68 data += "<h2>SourceStamp:</h2>\n"
69 data += " <ul>\n"
70 if ss.branch:
71 data += " <li>Branch: %s</li>\n" % html.escape(ss.branch)
72 if ss.revision:
73 data += " <li>Revision: %s</li>\n" % html.escape(str(ss.revision))
74 if ss.patch:
75 data += " <li>Patch: YES</li>\n"
76 if ss.changes:
77 data += " <li>Changes: see below</li>\n"
78 if (ss.branch is None and ss.revision is None and ss.patch is None
79 and not ss.changes):
80 data += " <li>build of most recent revision</li>\n"
81 got_revision = None
82 try:
83 got_revision = b.getProperty("got_revision")
84 except KeyError:
85 pass
86 if got_revision:
87 got_revision = str(got_revision)
88 if len(got_revision) > 40:
89 got_revision = "[revision string too long]"
90 data += " <li>Got Revision: %s</li>\n" % got_revision
91 data += " </ul>\n"
92
93
94
95 try:
96 slaveurl = path_to_slave(req, status.getSlave(b.getSlavename()))
97 data += "<h2>Buildslave:</h2>\n <a href=\"%s\">%s</a>\n" % (html.escape(slaveurl), html.escape(b.getSlavename()))
98 except KeyError:
99 data += "<h2>Buildslave:</h2>\n %s\n" % html.escape(b.getSlavename())
100 data += "<h2>Reason:</h2>\n%s\n" % html.escape(b.getReason())
101
102 data += "<h2>Steps and Logfiles:</h2>\n"
103
104
105
106
107
108
109 data += "<ol>\n"
110 for s in b.getSteps():
111 name = s.getName()
112 time_to_run = 0
113 (start, end) = s.getTimes()
114 if start and end:
115 time_to_run = end - start
116 if s.isFinished():
117 css_class = css_classes[s.getResults()[0]]
118 elif s.isStarted():
119 css_class = "running"
120 else:
121 css_class = ""
122 data += (' <li><span class="%s"><a href=\"%s\">%s</a> [%s] [%d seconds]</span>\n'
123 % (css_class,
124 req.childLink("steps/%s" % urllib.quote(name)),
125 name,
126 " ".join(s.getText()),
127 time_to_run))
128 data += " <ol>\n"
129 if s.getLogs():
130 for logfile in s.getLogs():
131 logname = logfile.getName()
132 logurl = req.childLink("steps/%s/logs/%s" %
133 (urllib.quote(name),
134 urllib.quote(logname)))
135 data += (" <li><a href=\"%s\">%s</a></li>\n" %
136 (logurl, logfile.getName()))
137 if s.getURLs():
138 for url in s.getURLs().items():
139 logname = url[0]
140 logurl = url[1]
141 data += (' <li><a href="%s">%s</a></li>\n' %
142 (logurl, html.escape(logname)))
143 data += "</ol>\n"
144 data += " </li>\n"
145
146 data += "</ol>\n"
147
148 data += "<h2>Build Properties:</h2>\n"
149 data += "<table><tr><th valign=\"left\">Name</th><th valign=\"left\">Value</th><th valign=\"left\">Source</th></tr>\n"
150 for name, value, source in b.getProperties().asList():
151 value = str(value)
152 if len(value) > 500:
153 value = value[:500] + " .. [property value too long]"
154 data += "<tr>"
155 data += "<td>%s</td>" % html.escape(name)
156 data += "<td>%s</td>" % html.escape(value)
157 data += "<td>%s</td>" % html.escape(source)
158 data += "</tr>\n"
159 data += "</table>"
160
161 data += "<h2>Blamelist:</h2>\n"
162 if list(b.getResponsibleUsers()):
163 data += " <ol>\n"
164 for who in b.getResponsibleUsers():
165 data += " <li>%s</li>\n" % html.escape(who)
166 data += " </ol>\n"
167 else:
168 data += "<div>no responsible users</div>\n"
169
170
171 (start, end) = b.getTimes()
172 data += "<h2>Timing</h2>\n"
173 data += "<table>\n"
174 data += "<tr><td>Start</td><td>%s</td></tr>\n" % time.ctime(start)
175 if end:
176 data += "<tr><td>End</td><td>%s</td></tr>\n" % time.ctime(end)
177 data += "<tr><td>Elapsed</td><td>%s</td></tr>\n" % util.formatInterval(end - start)
178 else:
179 now = util.now()
180 data += "<tr><td>Elapsed</td><td>%s</td></tr>\n" % util.formatInterval(now - start)
181 data += "</table>\n"
182
183 if ss.changes:
184 data += "<h2>All Changes</h2>\n"
185 data += "<ol>\n"
186 for c in ss.changes:
187 data += "<li>" + c.asHTML() + "</li>\n"
188 data += "</ol>\n"
189
190
191 if b.isFinished() and self.builder_control is not None:
192 data += "<h3>Resubmit Build:</h3>\n"
193
194 exactly = (ss.revision is not None) or b.getChanges()
195 if exactly:
196 data += ("<p>This tree was built from a specific set of \n"
197 "source files, and can be rebuilt exactly</p>\n")
198 else:
199 data += ("<p>This tree was built from the most recent "
200 "revision")
201 if ss.branch:
202 data += " (along some branch)"
203 data += (" and thus it might not be possible to rebuild it \n"
204 "exactly. Any changes that have been committed \n"
205 "after this build was started <b>will</b> be \n"
206 "included in a rebuild.</p>\n")
207 rebuildURL = urllib.quote(req.childLink("rebuild"))
208 data += ('<form method="post" action="%s" class="command rebuild">\n'
209 % rebuildURL)
210 data += make_name_user_passwd_form(self.isUsingUserPasswd(req))
211 data += make_extra_property_row(1)
212 data += make_extra_property_row(2)
213 data += make_extra_property_row(3)
214 data += make_row("Reason for re-running build:",
215 "<input type='text' name='comments' />")
216 data += '<input type="submit" value="Rebuild" />\n'
217 data += '</form>\n'
218
219 data += self.footer(status, req)
220
221 return data
222
223 - def stop(self, req):
224 if self.isUsingUserPasswd(req):
225 if not self.authUser(req):
226 return Redirect("../../../authfailed")
227 b = self.build_status
228 c = self.build_control
229 log.msg("web stopBuild of build %s:%s" % \
230 (b.getBuilder().getName(), b.getNumber()))
231 name = req.args.get("username", ["<unknown>"])[0]
232 comments = req.args.get("comments", ["<no reason specified>"])[0]
233
234 reason = ("The web-page 'stop build' button was pressed by "
235 "'%s': %s\n" % (html.escape(name), html.escape(comments)))
236 if c:
237 c.stopBuild(reason)
238
239
240 r = Redirect("../..")
241 d = defer.Deferred()
242 reactor.callLater(1, d.callback, r)
243 return DeferredResource(d)
244
246 if self.isUsingUserPasswd(req):
247 if not self.authUser(req):
248 return Redirect("../../../authfailed")
249 b = self.build_status
250 bc = self.builder_control
251 builder_name = b.getBuilder().getName()
252 log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber()))
253 name = req.args.get("username", ["<unknown>"])[0]
254 comments = req.args.get("comments", ["<no reason specified>"])[0]
255 reason = ("The web-page 'rebuild' button was pressed by "
256 "'%s': %s\n" % (html.escape(name), html.escape(comments)))
257 extraProperties = getAndCheckProperties(req)
258 if not bc or not b.isFinished() or extraProperties is None:
259 log.msg("could not rebuild: bc=%s, isFinished=%s"
260 % (bc, b.isFinished()))
261
262 else:
263 bc.resubmitBuild(b, reason, extraProperties)
264
265
266
267
268
269
270
271
272
273
274 r = Redirect("../..")
275 d = defer.Deferred()
276 reactor.callLater(1, d.callback, r)
277 return DeferredResource(d)
278
290
291
293 addSlash = True
294
295 - def __init__(self, builder_status, builder_control):
296 HtmlResource.__init__(self)
297 self.builder_status = builder_status
298 self.builder_control = builder_control
299
316