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