[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