def command_BUILD(self, args, who): args = shlex.split(args) repos = { 'apiextractor' : None, 'generatorrunner' : None, 'shiboken' : None, 'pyside' : None } if not who in config.gitCustomers: self.send('%s, I\'ll not make this build for you. Do you think I found my genitalia in the trash?' % who) return builder = None for arg in args: try: repo, target = arg.split('=') except: self.send('Usage: ' + PySideContact.command_BUILD.usage) return if repo == 'builder': builder = target else: if not repo in repos: self.send('%s, there\'s no "%s" repository' % (who, repo)) return repos[repo] = target slaves = ['build-pyside-' + arch for arch in config.slavesByArch.keys()] if builder: if builder not in slaves: self.send("%s, the slave '%s' that you asked for doesn't exist." % (who, builder)) return slaves = [builder] for which in slaves: bc = self.getControl(which) build_properties = Properties() build_properties.setProperty('owner', who, 'Build requested from IRC bot on behalf of %s.' % who) for propName, propValue in [(pName, pValue) for pName, pValue in repos.items() if pValue]: build_properties.setProperty(propName + '_hashtag', propValue, 'Build requested from IRC bot.') for repoName, gitUrl in config.gitCustomers[who].items(): build_properties.setProperty(repoName.lower() + '_gitUrl', config.baseGitURL + gitUrl, 'Personal %s repository of %s.' % (repoName, who)) r = "forced: by %s: %s" % (self.describeUser(who), 'He had his reasons.') s = SourceStamp(branch='BRANCH', revision='REVISION') req = BuildRequest(r, s, which, properties=build_properties) try: bc.requestBuildSoon(req) except interfaces.NoSlaveError: self.send("%s, sorry, I can't force a build: all slaves are offline" % who) return ireq = IrcBuildRequest(self) req.subscribe(ireq.started)
def doBuild(self, buildername, reason="forced"): # we need to prevent these builds from being merged, so we create # each of them with a different revision specifier. The revision is # ignored because our build process does not have a source checkout # step. self.revision += 1 br = BuildRequest(reason, SourceStamp(revision=self.revision)) d = br.waitUntilFinished() self.control.getBuilder(buildername).requestBuild(br) return d
def requestBuild(self, builder, locale): # returns a Deferred that fires with an IBuildStatus object when the # build is finished props = Properties() props.setProperty('locale', locale, 'scheduler') props.setProperty('tree', 'app', 'scheduler') req = BuildRequest("forced build", SourceStamp(), builder, properties=props) self.control.getBuilder(builder).requestBuild(req) return req.waitUntilFinished()
def submitBuild(self): ss = SourceStamp() br = BuildRequest("forced build", ss, "dummy") self.control.getBuilder("dummy").requestBuild(br) d = defer.Deferred() def _started(bc): br.unsubscribe(_started) d.callback(bc) br.subscribe(_started) return d
def send(res): # send some build requests ss = SourceStamp() for i in range(5): req = BuildRequest(str(i), ss, "dummy") self.master.botmaster.builders['dummy'].submitBuildRequest(req) req.submittedAt = i def append(build): start_order.append(int(build.reason)) req.subscribe(append) reqs.append(req.waitUntilFinished())
def _send(res): # send some build requests reqs = [] ss = SourceStamp() for i in range(5): req = BuildRequest(str(i), ss, "dummy") self.master.botmaster.builders['dummy'].submitBuildRequest(req) reqs.append(req.waitUntilFinished()) dl = defer.DeferredList(reqs) dl.addCallback(check) return dl
def testPriority(self): self.rmtree("basedir") os.mkdir("basedir") self.master.loadConfig(config_priority) self.master.readConfig = True self.master.startService() # Our fake source stamp # we override canBeMergedWith so that our requests don't get merged together ss = SourceStamp() ss.canBeMergedWith = lambda x: False # Send 10 requests to alternating builders # We fudge the submittedAt field after submitting since they're all # getting submitted so close together according to time.time() # and all we care about is what order they're run in. reqs = [] self.start_order = [] for i in range(10): req = BuildRequest(str(i), ss, "test_builder") j = i % 2 + 1 self.master.botmaster.builders['quick%i' % j].submitBuildRequest(req) req.submittedAt = i # Keep track of what order the builds start in def append(build): self.start_order.append(int(build.reason)) req.subscribe(append) reqs.append(req.waitUntilFinished()) dl = defer.DeferredList(reqs) dl.addCallback(self._all_finished) def _delay(res): d1 = defer.Deferred() reactor.callLater(0.5, d1.callback, None) # this test depends upon this 0.5s delay landing us in the middle # of one of the builds. return d1 def _connect(res, i): return self.connectSlave(slavename="bot%i" % i, builders=["quick1", "quick2"]) # Now add the slaves d = self.connectSlave(slavename="bot0", builders=["quick1", "quick2"]) for i in range(1,5): d.addCallback(_delay) d.addCallback(_connect, i) d.addCallback(lambda x: dl) return d
def _testSlave_1(self, res, t1): self.failUnlessEqual(len(t1.events), 2) self.failUnlessEqual(t1.events[0], ("builderChangedState", "dummy", "idle")) self.failUnlessEqual(t1.events[1], ("builderChangedState", "testdummy", "idle")) t1.events = [] c = interfaces.IControl(self.master) req = BuildRequest("forced build for testing", SourceStamp()) c.getBuilder("dummy").requestBuild(req) d = req.waitUntilFinished() d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") dl = defer.DeferredList([d, d2]) dl.addCallback(self._testSlave_2) return dl
def testDontClaimPingingSlave(self): # have two slaves connect for the same builder. Do something to the # first one so that slavepings are delayed (but do not fail # outright). timers = [] self.slaves['bot1'].debugOpts["stallPings"] = (10, timers) br = BuildRequest("forced", SourceStamp(), 'test_builder') d1 = br.waitUntilFinished() self.master.botmaster.builders["b1"].CHOOSE_SLAVES_RANDOMLY = False self.control.getBuilder("b1").requestBuild(br) s1 = br.status # this is a BuildRequestStatus # give it a chance to start pinging d2 = defer.Deferred() d2.addCallback(self._testDontClaimPingingSlave_1, d1, s1, timers) reactor.callLater(1, d2.callback, None) return d2
def _connected(self, *args): # Our fake source stamp # we override canBeMergedWith so that our requests don't get merged together ss = SourceStamp() ss.canBeMergedWith = lambda x: False # Send one request to tie up the slave before sending future requests req0 = BuildRequest("reason", ss, "test_builder") self.master.botmaster.builders['quick1'].submitBuildRequest(req0) # Send 10 requests to alternating builders # We fudge the submittedAt field after submitting since they're all # getting submitted so close together according to time.time() # and all we care about is what order they're run in. reqs = [] self.finish_order = [] for i in range(10): req = BuildRequest(str(i), ss, "test_builder") j = i % 2 + 1 self.master.botmaster.builders['quick%i' % j].submitBuildRequest(req) req.submittedAt = i # Keep track of what order the builds finished in def append(item, arg): self.finish_order.append(item) req.waitUntilFinished().addCallback(append, req) reqs.append(req.waitUntilFinished()) dl = defer.DeferredList(reqs) dl.addCallback(self._all_finished) # After our first build finishes, we should wait for the rest to finish d = req0.waitUntilFinished() d.addCallback(lambda x: dl) return d
def command_FORCE(self, args, who): args = shlex.split(args) # TODO: this requires python2.3 or newer if not args: raise UsageError("try 'force build WHICH <REASON>'") what = args.pop(0) if what != "build": raise UsageError("try 'force build WHICH <REASON>'") opts = ForceOptions() opts.parseOptions(args) which = opts['builder'] branch = opts['branch'] revision = opts['revision'] reason = opts['reason'] if which is None: raise UsageError("you must provide a Builder, " "try 'force build WHICH <REASON>'") # keep weird stuff out of the branch and revision strings. TODO: # centralize this somewhere. if branch and not re.match(r'^[\w\.\-\/]*$', branch): log.msg("bad branch '%s'" % branch) self.send("sorry, bad branch '%s'" % branch) return if revision and not re.match(r'^[\w\.\-\/]*$', revision): log.msg("bad revision '%s'" % revision) self.send("sorry, bad revision '%s'" % revision) return bc = self.getControl(which) r = "forced: by %s: %s" % (self.describeUser(who), reason) # TODO: maybe give certain users the ability to request builds of # certain branches s = SourceStamp(branch=branch, revision=revision) req = BuildRequest(r, s, which) try: bc.requestBuildSoon(req) except interfaces.NoSlaveError: self.send("sorry, I can't force a build: all slaves are offline") return ireq = IrcBuildRequest(self) req.subscribe(ireq.started)
def send(res): # send some build requests ss = SourceStamp() for i in range(5): req1 = BuildRequest(str(i), ss, "dummy") self.master.botmaster.builders['dummy1'].submitBuildRequest(req1) req2 = BuildRequest(str(i), ss, "dummy") self.master.botmaster.builders['dummy2'].submitBuildRequest(req2) def append(build): builder_names.append(build.builder.name) req1.subscribe(append) req2.subscribe(append) reqs.append(req1.waitUntilFinished()) complete_reqs.append(req1) incomplete_reqs.append(req2)
def testIdle2(self): # now suppose the slave goes missing self.disappearSlave(allowReconnect=False) # forcing a build will work: the build detect that the slave is no # longer available and will be re-queued. Wait 5 seconds, then check # to make sure the build is still in the 'waiting for a slave' queue. req = BuildRequest("forced build", SourceStamp(), "test_builder") self.failUnlessEqual(req.startCount, 0) self.control.getBuilder("dummy").requestBuild(req) # this should ping the slave, which doesn't respond (and eventually # times out). The BuildRequest will be re-queued, and its .startCount # will be incremented. self.killSlave() d = defer.Deferred() d.addCallback(self._testIdle2_1, req) reactor.callLater(3, d.callback, None) return d
def makeBuildStep(basedir, step_class=BuildStep, **kwargs): bss = setupBuildStepStatus(basedir) ss = SourceStamp() setup = { 'name': "builder1", "slavename": "bot1", 'builddir': "builddir", 'factory': None } b0 = Builder(setup, bss.getBuild().getBuilder()) br = BuildRequest("reason", ss) b = Build([br]) b.setBuilder(b0) s = step_class(**kwargs) s.setBuild(b) s.setStepStatus(bss) b.setupStatus(bss.getBuild()) s.slaveVersion = fake_slaveVersion return s
def force(self, req): name = req.args.get("username", ["<unknown>"])[0] reason = req.args.get("comments", ["<no reason specified>"])[0] branch = req.args.get("branch", [""])[0] revision = req.args.get("revision", [""])[0] r = "The web-page 'force build' button was pressed by '%s': %s\n" \ % (name, reason) log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" % (self.builder_status.getName(), branch, revision)) if not self.builder_control: # TODO: tell the web user that their request was denied log.msg("but builder control is disabled") return Redirect("..") # keep weird stuff out of the branch and revision strings. TODO: # centralize this somewhere. if not re.match(r'^[\w\.\-\/]*$', branch): log.msg("bad branch '%s'" % branch) return Redirect("..") if not re.match(r'^[\w\.\-\/]*$', revision): log.msg("bad revision '%s'" % revision) return Redirect("..") if not branch: branch = None if not revision: revision = None # TODO: if we can authenticate that a particular User pushed the # button, use their name instead of None, so they'll be informed of # the results. s = SourceStamp(branch=branch, revision=revision) req = BuildRequest(r, s, self.builder_status.getName()) try: self.builder_control.requestBuildSoon(req) except interfaces.NoSlaveError: # TODO: tell the web user that their request could not be # honored pass return Redirect("../../waterfall")
def perspective_requestBuild(self, buildername, reason, branch, revision): c = interfaces.IControl(self.master) bc = c.getBuilder(buildername) ss = SourceStamp(branch, revision) br = BuildRequest(reason, ss, buildername) bc.requestBuild(br)
def doBuild(self, buildername): br = BuildRequest("forced", SourceStamp()) d = br.waitUntilFinished() self.control.getBuilder(buildername).requestBuild(br) return d
def _testSlave_2(self, res): # t1 subscribes to builds, but not anything lower-level ev = self.t1.events self.failUnlessEqual(len(ev), 4) self.failUnlessEqual(ev[0][0:3], ("builderChangedState", "dummy", "building")) self.failUnlessEqual(ev[1][0], "buildStarted") self.failUnlessEqual(ev[2][0:2] + ev[2][3:4], ("buildFinished", "dummy", builder.SUCCESS)) self.failUnlessEqual(ev[3][0:3], ("builderChangedState", "dummy", "idle")) self.failUnlessEqual( [ev[0] for ev in self.t3.events], [ "builderAdded", "builderChangedState", # offline "builderAdded", "builderChangedState", # idle "builderChangedState", # offline "builderChangedState", # idle "builderChangedState", # building "buildStarted", "stepStarted", "stepETAUpdate", "stepFinished", "stepStarted", "stepETAUpdate", "logStarted", "logFinished", "stepFinished", "buildFinished", "builderChangedState", # idle ]) b = self.s1.getLastFinishedBuild() self.failUnless(b) self.failUnlessEqual(b.getBuilder().getName(), "dummy") self.failUnlessEqual(b.getNumber(), 0) self.failUnlessEqual(b.getSourceStamp().branch, None) self.failUnlessEqual(b.getSourceStamp().patch, None) self.failUnlessEqual(b.getSourceStamp().revision, None) self.failUnlessEqual(b.getReason(), "forced build for testing") self.failUnlessEqual(b.getChanges(), ()) self.failUnlessEqual(b.getResponsibleUsers(), []) self.failUnless(b.isFinished()) self.failUnlessEqual(b.getText(), ['build', 'successful']) self.failUnlessEqual(b.getColor(), "green") self.failUnlessEqual(b.getResults(), builder.SUCCESS) steps = b.getSteps() self.failUnlessEqual(len(steps), 2) eta = 0 st1 = steps[0] self.failUnlessEqual(st1.getName(), "dummy") self.failUnless(st1.isFinished()) self.failUnlessEqual(st1.getText(), ["delay", "1 secs"]) start, finish = st1.getTimes() self.failUnless(0.5 < (finish - start) < 10) self.failUnlessEqual(st1.getExpectations(), []) self.failUnlessEqual(st1.getLogs(), []) eta += finish - start st2 = steps[1] self.failUnlessEqual(st2.getName(), "remote dummy") self.failUnless(st2.isFinished()) self.failUnlessEqual(st2.getText(), ["remote", "delay", "2 secs"]) start, finish = st2.getTimes() self.failUnless(1.5 < (finish - start) < 10) eta += finish - start self.failUnlessEqual(st2.getExpectations(), [('output', 38, None)]) logs = st2.getLogs() self.failUnlessEqual(len(logs), 1) self.failUnlessEqual(logs[0].getName(), "stdio") self.failUnlessEqual(logs[0].getText(), "data") self.eta = eta # now we run it a second time, and we should have an ETA self.t4 = t4 = STarget(["builder", "build", "eta"]) self.master.getStatus().subscribe(t4) c = interfaces.IControl(self.master) req = BuildRequest("forced build for testing", SourceStamp()) c.getBuilder("dummy").requestBuild(req) d = req.waitUntilFinished() d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") dl = defer.DeferredList([d, d2]) dl.addCallback(self._testSlave_3) return dl
def doBuild(self): br = BuildRequest("forced", SourceStamp(), 'test_builder') d = br.waitUntilFinished() self.control.getBuilder('b1').requestBuild(br) return d
def requestBuild(self, builder): # returns a Deferred that fires with an IBuildStatus object when the # build is finished req = BuildRequest("forced build", SourceStamp()) self.control.getBuilder(builder).requestBuild(req) return req.waitUntilFinished()
def _testSlave_2(self, res): # t1 subscribes to builds, but not anything lower-level ev = self.t1.events self.failUnlessEqual(len(ev), 4) self.failUnlessEqual(ev[0][0:3], ("builderChangedState", "dummy", "building")) self.failUnlessEqual(ev[1][0], "buildStarted") self.failUnlessEqual(ev[2][0:2]+ev[2][3:4], ("buildFinished", "dummy", builder.SUCCESS)) self.failUnlessEqual(ev[3][0:3], ("builderChangedState", "dummy", "idle")) self.failUnlessEqual([ev[0] for ev in self.t3.events], ["builderAdded", "builderChangedState", # offline "builderAdded", "builderChangedState", # idle "builderChangedState", # offline "builderChangedState", # idle "builderChangedState", # building "buildStarted", "stepStarted", "stepETAUpdate", "stepFinished", "stepStarted", "stepETAUpdate", "logStarted", "logFinished", "stepFinished", "buildFinished", "builderChangedState", # idle ]) b = self.s1.getLastFinishedBuild() self.failUnless(b) self.failUnlessEqual(b.getBuilder().getName(), "dummy") self.failUnlessEqual(b.getNumber(), 0) self.failUnlessEqual(b.getSourceStamp().branch, None) self.failUnlessEqual(b.getSourceStamp().patch, None) self.failUnlessEqual(b.getSourceStamp().revision, None) self.failUnlessEqual(b.getReason(), "forced build for testing") self.failUnlessEqual(b.getChanges(), ()) self.failUnlessEqual(b.getResponsibleUsers(), []) self.failUnless(b.isFinished()) self.failUnlessEqual(b.getText(), ['build', 'successful']) self.failUnlessEqual(b.getColor(), "green") self.failUnlessEqual(b.getResults(), builder.SUCCESS) steps = b.getSteps() self.failUnlessEqual(len(steps), 2) eta = 0 st1 = steps[0] self.failUnlessEqual(st1.getName(), "dummy") self.failUnless(st1.isFinished()) self.failUnlessEqual(st1.getText(), ["delay", "1 secs"]) start,finish = st1.getTimes() self.failUnless(0.5 < (finish-start) < 10) self.failUnlessEqual(st1.getExpectations(), []) self.failUnlessEqual(st1.getLogs(), []) eta += finish-start st2 = steps[1] self.failUnlessEqual(st2.getName(), "remote dummy") self.failUnless(st2.isFinished()) self.failUnlessEqual(st2.getText(), ["remote", "delay", "2 secs"]) start,finish = st2.getTimes() self.failUnless(1.5 < (finish-start) < 10) eta += finish-start self.failUnlessEqual(st2.getExpectations(), [('output', 38, None)]) logs = st2.getLogs() self.failUnlessEqual(len(logs), 1) self.failUnlessEqual(logs[0].getName(), "stdio") self.failUnlessEqual(logs[0].getText(), "data") self.eta = eta # now we run it a second time, and we should have an ETA self.t4 = t4 = STarget(["builder", "build", "eta"]) self.master.getStatus().subscribe(t4) c = interfaces.IControl(self.master) req = BuildRequest("forced build for testing", SourceStamp()) c.getBuilder("dummy").requestBuild(req) d = req.waitUntilFinished() d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") dl = defer.DeferredList([d, d2]) dl.addCallback(self._testSlave_3) return dl
def force(self, req): """ Custom properties can be passed from the web form. To do this, subclass this class, overriding the force() method. You can then determine the properties (usually from form values, by inspecting req.args), then pass them to this superclass force method. """ name = req.args.get("username", ["<unknown>"])[0] reason = req.args.get("comments", ["<no reason specified>"])[0] branch = req.args.get("branch", [""])[0] revision = req.args.get("revision", [""])[0] r = "The web-page 'force build' button was pressed by '%s': %s\n" \ % (html.escape(name), html.escape(reason)) log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" " by user '%s'" % (self.builder_status.getName(), branch, revision, name)) if not self.builder_control: # TODO: tell the web user that their request was denied log.msg("but builder control is disabled") return Redirect("..") if self.isUsingUserPasswd(req): if not self.authUser(req): return Redirect("../../authfail") # keep weird stuff out of the branch revision, and property strings. # TODO: centralize this somewhere. if not re.match(r'^[\w\.\-\/]*$', branch): log.msg("bad branch '%s'" % branch) return Redirect("..") if not re.match(r'^[\w\.\-\/]*$', revision): log.msg("bad revision '%s'" % revision) return Redirect("..") properties = getAndCheckProperties(req) if properties is None: return Redirect("..") if not branch: branch = None if not revision: revision = None # TODO: if we can authenticate that a particular User pushed the # button, use their name instead of None, so they'll be informed of # the results. # TODO2: we can authenticate that a particular User pushed the button # now, so someone can write this support. but it requires a # buildbot.changes.changes.Change instance which is tedious at this # stage to compute s = SourceStamp(branch=branch, revision=revision) req = BuildRequest(r, s, builderName=self.builder_status.getName(), properties=properties) try: self.builder_control.requestBuildSoon(req) except interfaces.NoSlaveError: # TODO: tell the web user that their request could not be # honored pass # send the user back to the builder page return Redirect(".")