[Buildbot-devel] [PATCH 06/11] Add force/stop buttons that affect all builders.
Benoit Sigoure
tsuna at lrde.epita.fr
Fri Nov 16 17:12:56 UTC 2007
The `Latest Build' and `Recent Builds' pages now have a button to
force or stop a build on all builders. It's more convenient to
trigger a build on all builders (a feature that has frequently been
asked).
* status/web/baseweb.py (OneLinePerBuild.body): Print forms to
force/stop builds on all builders, depending on the state of
builders.
(OneBoxPerBuilder.body): Ditto.
(WebStatus): Document the new `_all/{force,stop}' URLs.
* status/web/builder.py (StatusResourceAllBuilders): New class.
(BuildersResource.getChild): Handle the special child `_all' that
dispatches commands on all builders.
Signed-off-by: Benoit Sigoure <tsuna at lrde.epita.fr>
---
buildbot/status/web/baseweb.py | 41 ++++++++++++++++++++++++++-
buildbot/status/web/builder.py | 60 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/buildbot/status/web/baseweb.py b/buildbot/status/web/baseweb.py
index 9475334..aa9551b 100644
--- a/buildbot/status/web/baseweb.py
+++ b/buildbot/status/web/baseweb.py
@@ -11,7 +11,8 @@ from twisted.spread import pb
from buildbot.interfaces import IControl, IStatusReceiver
from buildbot.status.web.base import HtmlResource, Box, \
- build_get_class, ICurrentBox, OneLineMixin, map_branches
+ build_get_class, ICurrentBox, OneLineMixin, map_branches, \
+ make_stop_form, make_force_build_form
from buildbot.status.web.waterfall import WaterfallStatusResource
from buildbot.status.web.changes import ChangesResource
from buildbot.status.web.builder import BuildersResource
@@ -105,12 +106,28 @@ class OneLinePerBuild(HtmlResource, OneLineMixin):
data += ("<p>of builders: %s</p>\n" % (", ".join(builders)))
data += "<ul>\n"
got = 0
+ building = False
+ online = 0
for build in g:
got += 1
data += " <li>" + self.make_line(req, build) + "</li>\n"
+ builder_status = build.getBuilder().getState()[0]
+ if builder_status == "building":
+ building = True
+ online += 1
+ elif builder_status != "offline":
+ online += 1
if not got:
data += " <li>No matching builds found</li>\n"
data += "</ul>\n"
+
+ if building:
+ stopURL = "builders/_all/stop"
+ data += make_stop_form(stopURL)
+ if online:
+ forceURL = "builders/_all/force"
+ data += make_force_build_form(forceURL)
+
return data
@@ -165,7 +182,7 @@ class OneBoxPerBuilder(HtmlResource):
def body(self, req):
status = self.getStatus(req)
-
+
builders = req.args.get("builder", status.getBuilderNames())
branches = [b for b in req.args.get("branch", []) if b]
@@ -173,6 +190,9 @@ class OneBoxPerBuilder(HtmlResource):
data += "<h2>Latest builds: %s</h2>\n" % ", ".join(branches)
data += "<table>\n"
+
+ building = False
+ online = 0
for bn in builders:
builder = status.getBuilder(bn)
data += "<tr>\n"
@@ -200,7 +220,23 @@ class OneBoxPerBuilder(HtmlResource):
data += '<td class="LastBuild box" >no build</td>\n'
current_box = ICurrentBox(builder).getBox(status)
data += current_box.td(align="center")
+
+ builder_status = builder.getState()[0]
+ if builder_status == "building":
+ building = True
+ online += 1
+ elif builder_status != "offline":
+ online += 1
+
data += "</table>\n"
+
+ if building:
+ stopURL = "builders/_all/stop"
+ data += make_stop_form(stopURL)
+ if online:
+ forceURL = "builders/_all/force"
+ data += make_force_build_form(forceURL)
+
return data
@@ -254,6 +290,7 @@ class WebStatus(service.MultiService):
/builders/BUILDERNAME/builds/NUM/steps/STEPNAME/logs/LOGNAME: a StatusLog
/builders/BUILDERNAME/builds/NUM/tests : summarize test results
/builders/BUILDERNAME/builds/NUM/tests/TEST.NAME: results of one test
+ /builders/_all/{force,stop}: force a build/stop building on all builders.
/changes : summarize all ChangeSources
/changes/CHANGENUM: a page describing a single Change
/schedulers/SCHEDULERNAME: a page describing a Scheduler, including
diff --git a/buildbot/status/web/builder.py b/buildbot/status/web/builder.py
index f67fb45..4ea47cf 100644
--- a/buildbot/status/web/builder.py
+++ b/buildbot/status/web/builder.py
@@ -11,7 +11,7 @@ from buildbot.status.web.base import HtmlResource, make_row, \
from buildbot.process.base import BuildRequest
from buildbot.sourcestamp import SourceStamp
-from buildbot.status.web.build import BuildsResource
+from buildbot.status.web.build import BuildsResource, StatusResourceBuild
# /builders/$builder
class StatusResourceBuilder(HtmlResource, OneLineMixin):
@@ -114,7 +114,7 @@ class StatusResourceBuilder(HtmlResource, OneLineMixin):
pingURL = urllib.quote(req.childLink("ping"))
data += """
<form action="%s" class='command pingbuilder'>
- <p>To ping the buildslave(s), push the 'Ping' button</p>
+ <p>To ping the buildslave(s), click the 'Ping' button</p>
<input type="submit" value="Ping Builder" />
</form>
@@ -151,7 +151,7 @@ class StatusResourceBuilder(HtmlResource, OneLineMixin):
if not revision:
revision = None
- # TODO: if we can authenticate that a particular User pushed the
+ # TODO: if we can authenticate that a particular User clicked the
# button, use their name instead of None, so they'll be informed of
# the results.
s = SourceStamp(branch=branch, revision=revision)
@@ -200,6 +200,57 @@ class StatusResourceBuilder(HtmlResource, OneLineMixin):
return HtmlResource.getChild(self, path, req)
+# /builders/_all
+class StatusResourceAllBuilders(HtmlResource, OneLineMixin):
+
+ def __init__(self, status, control):
+ HtmlResource.__init__(self)
+ self.status = status
+ self.control = control
+
+ def getChild(self, path, req):
+ if path == "force":
+ return self.force(req)
+ if path == "stop":
+ return self.stop(req)
+
+ return HtmlResource.getChild(self, path, req)
+
+ def force(self, req):
+ for bname in self.status.getBuilderNames():
+ builder_status = self.status.getBuilder(bname)
+ builder_control = None
+ c = self.getControl(req)
+ if c:
+ builder_control = c.getBuilder(bname)
+ build = StatusResourceBuilder(builder_status, builder_control)
+ build.force(req)
+ return Redirect("../../waterfall")
+
+ def stop(self, req):
+ for bname in self.status.getBuilderNames():
+ builder_status = self.status.getBuilder(bname)
+ builder_control = None
+ c = self.getControl(req)
+ if c:
+ builder_control = c.getBuilder(bname)
+ (state, current_builds) = builder_status.getState()
+ if state != "building":
+ continue
+ for b in current_builds:
+ build_status = builder_status.getBuild(b.number)
+ if not build_status:
+ continue
+ if builder_control:
+ build_control = builder_control.getBuild(b.number)
+ else:
+ build_control = None
+ build = StatusResourceBuild(build_status, build_control,
+ builder_control)
+ build.stop(req)
+ return Redirect("../../waterfall")
+
+
# /builders
class BuildersResource(HtmlResource):
title = "Builders"
@@ -231,6 +282,9 @@ class BuildersResource(HtmlResource):
if c:
builder_control = c.getBuilder(path)
return StatusResourceBuilder(builder_status, builder_control)
+ if path == "_all":
+ return StatusResourceAllBuilders(self.getStatus(req),
+ self.getControl(req))
return HtmlResource.getChild(self, path, req)
--
1.5.3.5.654.gdd5ec
More information about the devel
mailing list