Ticket #99: first_steps_to_99.patch
| File first_steps_to_99.patch, 16.6 kB (added by nhemingway, 4 months ago) |
|---|
-
a/buildbot/interfaces.py
old new 1006 1006 to a scarcity of build slaves). These upcoming builds can be canceled 1007 1007 through the control object.""" 1008 1008 1009 def cancelBuildRequest(self, request_number): 1010 """If there is a build request with the given number on the builder's queue, 1011 cancel the request""" 1012 1009 1013 def getBuild(number): 1010 1014 """Attempt to return an IBuildControl object for the given build. 1011 1015 Returns None if no such object is available. This will only work for -
a/buildbot/process/base.py
old new 133 133 not yet been started. 134 134 135 135 @return: a boolean indicating if the cancel was successful.""" 136 log.msg("Cancelling %r" % self) 136 137 if self.builder: 137 138 return self.builder.cancelBuildRequest(self) 138 139 return False -
a/buildbot/process/builder.py
old new 333 333 def __repr__(self): 334 334 return "<Builder '%s' at %d>" % (self.name, id(self)) 335 335 336 337 336 def submitBuildRequest(self, req): 338 337 req.submittedAt = now() 339 338 self.buildable.append(req) … … 714 713 return 715 714 716 715 ss = bs.getSourceStamp(absolute=True) 717 req = base.BuildRequest(reason, ss, self.original.name) 716 # The properties need to be passed again 717 req = base.BuildRequest(reason, ss, self.original.name, bs.getProperties()) 718 718 self.requestBuild(req) 719 719 720 720 def getPendingBuilds(self): 721 721 # return IBuildRequestControl objects 722 722 raise NotImplementedError 723 # """Return a list of L{IBuildRequestControl} objects for this Builder. 724 # Each one corresponds to a pending build that has not yet started (due 725 # to a scarcity of build slaves). These upcoming builds can be canceled 726 # through the control object.""" 727 # return self.original.buildable 723 728 724 729 def getBuild(self, number): 725 730 return self.original.getBuild(number) … … 736 741 d.addCallback(self._gatherPingResults) 737 742 return d 738 743 744 def cancelBuildRequest(self, request_number): 745 # Delete the build request from queue 746 for br in self.original.buildable: 747 if br.status.getNumber() == request_number: 748 br.cancel() 749 739 750 def _gatherPingResults(self, res): 740 751 for ignored,success in res: 741 752 if not success: -
a/buildbot/process/properties.py
old new 39 39 40 40 def __getitem__(self, name): 41 41 """Just get the value for this property.""" 42 rv = self.properties[name][0] 43 return rv 42 return self.properties[name][0] 43 44 def __setitem__(self, key, value): 45 self.properties[key] = (value, "Merged") 44 46 45 47 def has_key(self, name): 46 48 return self.properties.has_key(name) -
a/buildbot/status/builder.py
old new 614 614 self.builderName = builderName 615 615 self.builds = [] # list of BuildStatus objects 616 616 self.observers = [] 617 self.number = None 617 618 618 619 def buildStarted(self, build): 619 620 self.builds.append(build) … … 635 636 def unsubscribe(self, observer): 636 637 self.observers.remove(observer) 637 638 639 def setNumber(self, number): 640 self.number = number 641 def getNumber(self): 642 return self.number 643 638 644 639 645 class BuildStepStatus(styles.Versioned): 640 646 """ … … 1370 1376 self.nextBuild = None 1371 1377 self.watchers = [] 1372 1378 self.buildCache = [] # TODO: age builds out of the cache 1379 self.nextRequestNumber = 0 1373 1380 1374 1381 # persistence 1375 1382 … … 1390 1397 del d['basedir'] 1391 1398 del d['status'] 1392 1399 del d['nextBuildNumber'] 1400 del d['nextRequestNumber'] 1393 1401 return d 1394 1402 1395 1403 def __setstate__(self, d): … … 1401 1409 self.pendingBuilds = [] 1402 1410 self.watchers = [] 1403 1411 self.slavenames = [] 1412 self.nextRequestNumber = 0 1404 1413 # self.basedir must be filled in by our parent 1405 1414 # self.status must be filled in by our parent 1406 1415 … … 1656 1665 return s 1657 1666 1658 1667 def addBuildRequest(self, brstatus): 1668 req_number = self.nextRequestNumber 1669 self.nextRequestNumber += 1 1670 brstatus.setNumber(req_number) 1671 1672 log.msg("Adding build request %u" % req_number) 1659 1673 self.pendingBuilds.append(brstatus) 1660 1674 def removeBuildRequest(self, brstatus): 1661 1675 self.pendingBuilds.remove(brstatus) -
a/buildbot/status/web/baseweb.py
old new 20 20 from buildbot.status.web.slaves import BuildSlavesResource 21 21 from buildbot.status.web.xmlrpc import XMLRPCServer 22 22 from buildbot.status.web.about import AboutBuildbot 23 from buildbot.status.web.build import QueueStatusResource 23 24 24 25 # this class contains the status services (WebStatus and the older Waterfall) 25 26 # which can be put in c['status']. It also contains some of the resources -
a/buildbot/status/web/build.py
old new 11 11 from buildbot.status.web.tests import TestsResource 12 12 from buildbot.status.web.step import StepsResource 13 13 from buildbot import version, util 14 from buildbot.status.web.queue import QueueEntryStatusResource 14 15 15 16 # /builders/$builder/builds/$buildnum 16 17 class StatusResourceBuild(HtmlResource): … … 56 57 results = b.getResults() 57 58 data += "<h2>Results:</h2>\n" 58 59 text = " ".join(b.getText()) 59 data += '<span class="%s">%s</span>\n' % (css_classes[results],60 text)60 if results != None: 61 data += '<span class="%s">%s</span>\n' % (css_classes[results], text) 61 62 if b.getTestResults(): 62 63 url = req.childLink("tests") 63 64 data += "<h3><a href=\"%s\">test results</a></h3>\n" % url … … 294 295 build_control = None 295 296 return StatusResourceBuild(build_status, build_control, 296 297 self.builder_control) 298 else: 299 # Probably a build that was not started yet 300 return QueueEntryStatusResource(path, req, num, self.builder_status, self.builder_control) 301 302 return HtmlResource.getChild(self, path, req) 303 304 # /builders/$builder/queue 305 class QueueStatusResource(HtmlResource): 306 addSlash = True 307 308 def __init__(self, builder_status, builder_control): 309 HtmlResource.__init__(self) 310 self.builder_status = builder_status 311 self.builder_control = builder_control 312 313 def getChild(self, path, req): 314 try: 315 num = int(path) 316 except ValueError: 317 num = None 318 if num is not None: 319 return QueueEntryStatusResource(path, req, num, self.builder_status, self.builder_control) 297 320 298 321 return HtmlResource.getChild(self, path, req) 299 322 -
a/buildbot/status/web/builder.py
old new 9 9 from buildbot.status.web.base import HtmlResource, make_row, \ 10 10 make_force_build_form, OneLineMixin 11 11 from buildbot.process.base import BuildRequest 12 from buildbot.process.properties import Properties 12 13 from buildbot.sourcestamp import SourceStamp 13 14 from buildbot import version, util 14 15 15 from buildbot.status.web.build import BuildsResource, StatusResourceBuild 16 from buildbot.status.web.build import BuildsResource, StatusResourceBuild, QueueStatusResource 16 17 17 18 # /builders/$builder 18 19 class StatusResourceBuilder(HtmlResource, OneLineMixin): … … 50 51 <input type="submit" value="Stop Build" /> 51 52 </form>''' % stopURL 52 53 return data 54 55 def makeRemoveFromQueueButton(self, req, req_num): 56 stopURL = urllib.quote(req.childLink("queue/%d/remove" % req_num)) 57 data = ''' 58 <form action="%s" class="command stopbuild" style="display:inline"> 59 <input type="submit" value="Remove Build" /> 60 </form>''' % stopURL 61 return data 53 62 54 63 def body(self, req): 55 64 b = self.builder_status … … 76 85 data += "</ul>\n" 77 86 else: 78 87 data += "<h2>no current builds</h2>\n" 88 89 # Then a section with the queued build requests 90 data += "<h2>Pending Builds:</h2>\n" 91 # Retrieve the builders queue 92 pendingBuilds = b.getPendingBuilds() 93 if pendingBuilds: 94 # Determine the build numbers of the queue builds. 95 # Sadly we cannot remove the build from the queue with this 96 # number as it is not valid yet. 97 data += "<ul>\n" 98 for buildRequestStatus in pendingBuilds: 99 sourceStamp = buildRequestStatus.getSourceStamp() 100 req_number = buildRequestStatus.getNumber() 101 data += "<li>#%u " % req_number 102 data += "Branch: %s " % sourceStamp.branch 103 data += "[rev=%s]" % sourceStamp.revision 104 data += self.makeRemoveFromQueueButton(req, req_number) 105 data += "</li>" 106 data += "</ul>\n" 107 else: 108 data += "No pending builds" 79 109 80 110 # Then a section with the last 5 builds, with the most recent build 81 111 # distinguished from the rest. … … 237 267 return file 238 268 if path == "builds": 239 269 return BuildsResource(self.builder_status, self.builder_control) 270 if path == "queue": 271 return QueueStatusResource(self.builder_status, self.builder_control) 240 272 241 273 return HtmlResource.getChild(self, path, req) 242 274 -
/dev/null
old new 1 from twisted.web.util import Redirect, DeferredResource 2 from twisted.python import log 3 from twisted.internet import defer, reactor 4 from buildbot.status.web.base import HtmlResource 5 6 # Shows the queue of a Builder 7 class QueueEntryStatusResource(HtmlResource): 8 def __init__(self, path, req, num, builder_status, builder_control): 9 HtmlResource.__init__(self) 10 self.path = path 11 self.req = req 12 self.num = num 13 self.builder_status = builder_status 14 self.builder_control = builder_control 15 16 def body(self, request): 17 return "" 18 19 # Removes a build from a builders queue 20 def removeFromQueue(self, req): 21 self.builder_control.cancelBuildRequest(self.num) 22 23 # we're at http://localhost:8080/svn-hello/builds/5/stop?[args] and 24 # we want to go to: http://localhost:8080/svn-hello 25 r = Redirect("../..") 26 d = defer.Deferred() 27 reactor.callLater(1, d.callback, r) 28 return DeferredResource(d) 29 30 def getChild(self, path, req): 31 if path == "remove": 32 return self.removeFromQueue(req) 33 else: 34 return HtmlResource.getChild(self, path, req) -
/dev/null
old new 1 # -*- test-case-name: buildbot.test.test_builder -*- 2 3 from twisted.trial import unittest 4 5 from buildbot.process.base import BuildRequest 6 from buildbot.process.builder import Builder 7 from buildbot.status.builder import BuilderStatus 8 from buildbot.sourcestamp import SourceStamp 9 10 from buildbot.interfaces import IBuilderControl 11 12 def makeABuilderWithNRequests(how_many_requests): 13 b = QueueTest_MockBuilder( 14 setup = { 15 'name': "Builder 1", 16 'builddir': "/tmp", 17 'factory': "NoSuchFactory" 18 }, 19 how_many_requests = how_many_requests 20 ) 21 22 builder_control = IBuilderControl(b) 23 return (builder_control, b) 24 25 class QueueTest_MockBuilder(Builder): 26 def __init__(self, setup, how_many_requests): 27 Builder.__init__(self, setup, BuilderStatus(self)) 28 29 for i in range(how_many_requests): 30 self.submitBuildRequest(BuildRequest("a reason", SourceStamp())) 31 32 def maybeStartBuild(self): 33 pass 34 35 class Queue(unittest.TestCase): 36 def failUnlessPendingBuildsHaveNumbers(self, expected_numbers, builder): 37 pending_builds = builder.buildable 38 request_numbers = map( lambda req : req.status.getNumber(), pending_builds ) 39 self.failUnlessEqual(request_numbers, expected_numbers) 40 41 def testRemoveOnEmptyQueue(self): 42 (builder_control, builder) = makeABuilderWithNRequests(0) 43 self.failUnlessPendingBuildsHaveNumbers([], builder) 44 builder_control.cancelBuildRequest(2) 45 self.failUnlessPendingBuildsHaveNumbers([], builder) 46 47 def testRemoveOnlyQueueEntry(self): 48 (builder_control, builder) = makeABuilderWithNRequests(1) 49 self.failUnlessPendingBuildsHaveNumbers([0], builder) 50 builder_control.cancelBuildRequest(0) 51 self.failUnlessPendingBuildsHaveNumbers([], builder) 52 53 def testRemoveFirstQueueEntry(self): 54 (builder_control, builder) = makeABuilderWithNRequests(3) 55 self.failUnlessPendingBuildsHaveNumbers([0,1,2], builder) 56 builder_control.cancelBuildRequest(0) 57 self.failUnlessPendingBuildsHaveNumbers([1,2], builder) 58 59 def testRemoveQueueEntryFromMiddle(self): 60 (builder_control, builder) = makeABuilderWithNRequests(5) 61 self.failUnlessPendingBuildsHaveNumbers([0,1,2,3,4], builder) 62 builder_control.cancelBuildRequest(1) 63 self.failUnlessPendingBuildsHaveNumbers([0,2,3,4], builder) 64 65 def testRemoveLastQueueEntry(self): 66 (builder_control, builder) = makeABuilderWithNRequests(3) 67 self.failUnlessPendingBuildsHaveNumbers([0,1,2], builder) 68 builder_control.cancelBuildRequest(2) 69 self.failUnlessPendingBuildsHaveNumbers([0,1], builder) 70 71 def testRemoveUnknownQueueEntry(self): 72 (builder_control, builder) = makeABuilderWithNRequests(3) 73 self.failUnlessPendingBuildsHaveNumbers([0,1,2], builder) 74 builder_control.cancelBuildRequest(5) 75 self.failUnlessPendingBuildsHaveNumbers([0,1,2], builder) 76 77 def testRemoveSeveralInTurn(self): 78 (builder_control, builder) = makeABuilderWithNRequests(5) 79 self.failUnlessPendingBuildsHaveNumbers([0,1,2,3,4], builder) 80 builder_control.cancelBuildRequest(1) 81 self.failUnlessPendingBuildsHaveNumbers([0,2,3,4], builder) 82 builder_control.cancelBuildRequest(3) 83 self.failUnlessPendingBuildsHaveNumbers([0,2,4], builder) 84 builder_control.cancelBuildRequest(0) 85 self.failUnlessPendingBuildsHaveNumbers([2,4], builder) -
a/docs/buildbot.texinfo
old new 6789 6789 6790 6790 @item /builders/$BUILDERNAME 6791 6791 6792 This describes the given Builder, and provides buttons to force a build. 6792 This describes the given Builder, and provides buttons to force a 6793 build, and manage the builder's queue. 6793 6794 6794 6795 @item /builders/$BUILDERNAME/builds/$BUILDNUM 6795 6796
![[Buildbot Logo]](/trac/chrome/site/header-text-transparent.png)