Ticket #56: triggerable.patch
| File triggerable.patch, 13.9 KB (added by dustin, 4 years ago) |
|---|
-
buildbot/scheduler.py
Sun Jan 13 21:48:39 EST 2008 dustin@zmanda.com * triggerable.patch diff -rN -u old-trunk/buildbot/scheduler.py new-trunk/buildbot/scheduler.py
old new 681 681 from buildbot.status.client import makeRemote 682 682 return makeRemote(bs.status) 683 683 684 class Triggerable(BaseUpstreamScheduler): 685 """ 686 This scheduler doesn't do anything until it is triggered by 687 a Trigger step in a factory. 688 """ 689 690 def __init__(self, name, builderNames): 691 BaseUpstreamScheduler.__init__(self, name) 692 self.builderNames = builderNames 693 694 def listBuilderNames(self): 695 return self.builderNames 696 697 def getPendingBuildTimes(self): 698 return [] 699 700 def trigger(self, ss): 701 """ 702 Trigger this scheduler. Returns a deferred that will fire when the buildset 703 is finished. 704 """ 705 bs = buildset.BuildSet(self.builderNames, ss) 706 d = bs.waitUntilFinished() 707 self.submit(bs) 708 return d -
buildbot/steps/trigger.py
diff -rN -u old-trunk/buildbot/steps/trigger.py new-trunk/buildbot/steps/trigger.py
old new 1 from buildbot.process.buildstep import LoggingBuildStep, SUCCESS, FAILURE, EXCEPTION 2 from buildbot.steps.shell import WithProperties 3 from buildbot.sourcestamp import SourceStamp 4 from buildbot.scheduler import Triggerable 5 from twisted.internet import defer 6 from twisted.python import log 7 import os 8 9 class Trigger(LoggingBuildStep): 10 """ 11 I trigger a Triggerable. It's fun. 12 """ 13 name = "trigger" 14 15 flunkOnFailure = True 16 17 def __init__(self, 18 schedulers=[], 19 updateSourceStamp=False, 20 waitForFinish=False, 21 **kwargs): 22 """ 23 Trigger the given schedulers when this step is executed. 24 25 @var schedulers: list of schedulers' names that should be triggered. Schedulers 26 can be specified using WithProperties, if desired. 27 28 @var updateSourceStamp: should I update the source stamp to 29 an absolute SourceStamp before triggering a new build? 30 31 @var waitForFinish: should I wait for all of the triggered schedulers to finish 32 their builds? 33 """ 34 assert schedulers, "You must specify a scheduler to trigger" 35 self.schedulers = schedulers 36 self.updateSourceStamp = updateSourceStamp 37 self.waitForFinish = waitForFinish 38 self.running = False 39 LoggingBuildStep.__init__(self, **kwargs) 40 self.addFactoryArguments(schedulers=schedulers, 41 updateSourceStamp=updateSourceStamp, 42 waitForFinish=waitForFinish) 43 44 def interrupt(self, reason): 45 if self.running: 46 self.step_status.setColor("red") 47 self.step_status.setText(["interrupted"]) 48 49 def start(self): 50 self.running = True 51 ss = self.build.getSourceStamp() 52 if self.updateSourceStamp: 53 ss = ss.getAbsoluteSourceStamp(self.build.getProperty('got_revision')) 54 # (is there an easier way to find the BuildMaster?) 55 all_schedulers = self.build.builder.botmaster.parent.allSchedulers() 56 all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) 57 unknown_schedulers = [] 58 triggered_schedulers = [] 59 60 dl = [] 61 for scheduler in self.schedulers: 62 if isinstance(scheduler, WithProperties): 63 scheduler = scheduler.render(self.build) 64 if all_schedulers.has_key(scheduler): 65 sch = all_schedulers[scheduler] 66 if isinstance(sch, Triggerable): 67 dl.append(sch.trigger(ss)) 68 triggered_schedulers.append(scheduler) 69 else: 70 unknown_schedulers.append(scheduler) 71 else: 72 unknown_schedulers.append(scheduler) 73 74 if unknown_schedulers: 75 self.step_status.setColor("red") 76 self.step_status.setText(['no scheduler:'] + unknown_schedulers) 77 rc = FAILURE 78 else: 79 rc = SUCCESS 80 self.step_status.setText(['triggered'] + triggered_schedulers) 81 if self.waitForFinish: 82 self.step_status.setColor("yellow") 83 else: 84 self.step_status.setColor("green") 85 86 if self.waitForFinish: 87 d = defer.DeferredList(dl, consumeErrors=1) 88 else: 89 d = defer.succeed([]) 90 91 def cb(rclist): 92 rc = SUCCESS 93 for was_cb, buildsetstatus in rclist: 94 # TODO: make this algo more configurable 95 if not was_cb: 96 rc = EXCEPTION 97 break 98 if buildsetstatus.getResults() == FAILURE: 99 rc = FAILURE 100 return self.finished(rc) 101 102 def eb(why): 103 return self.finished(FAILURE) 104 105 d.addCallbacks(cb, eb) -
buildbot/test/test_run.py
diff -rN -u old-trunk/buildbot/test/test_run.py new-trunk/buildbot/test/test_run.py
old new 628 628 d = self.master.loadConfig(config_4_newbuilder) 629 629 return d 630 630 631 class Triggers(RunMixin, TestFlagMixin, unittest.TestCase): 632 config_trigger = config_base + """ 633 from buildbot.scheduler import Triggerable, Scheduler 634 from buildbot.steps.trigger import Trigger 635 from buildbot.steps.dummy import Dummy 636 from buildbot.test.runutils import SetTestFlagStep 637 c['schedulers'] = [ 638 Scheduler('triggerer', None, 0.1, ['triggerer']), 639 Triggerable('triggeree', ['triggeree']) 640 ] 641 triggerer = factory.BuildFactory([ 642 s(SetTestFlagStep, flagname='triggerer_started'), 643 s(Trigger, flunkOnFailure=True, @ARGS@), 644 s(SetTestFlagStep, flagname='triggerer_finished'), 645 ]) 646 triggeree = factory.BuildFactory([ 647 s(SetTestFlagStep, flagname='triggeree_started'), 648 s(@DUMMYCLASS@), 649 s(SetTestFlagStep, flagname='triggeree_finished'), 650 ]) 651 c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1', 652 'builddir': 'triggerer', 'factory': triggerer}, 653 {'name': 'triggeree', 'slavename': 'bot1', 654 'builddir': 'triggeree', 'factory': triggeree}] 655 """ 656 657 def mkConfig(self, args, dummyclass="Dummy"): 658 return self.config_trigger.replace("@ARGS@", args).replace("@DUMMYCLASS@", dummyclass) 659 660 def setupTest(self, args, dummyclass, checkFn): 661 self.clearFlags() 662 m = self.master 663 m.loadConfig(self.mkConfig(args, dummyclass)) 664 m.readConfig = True 665 m.startService() 666 667 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") 668 m.change_svc.addChange(c) 669 670 d = self.connectSlave(builders=['triggerer', 'triggeree']) 671 d.addCallback(self.startTimer, 0.5, checkFn) 672 return d 673 674 def startTimer(self, res, time, next_fn): 675 d = defer.Deferred() 676 reactor.callLater(time, d.callback, None) 677 d.addCallback(next_fn) 678 return d 679 680 def testTriggerBuild(self): 681 return self.setupTest("schedulers=['triggeree']", 682 "Dummy", 683 self._checkTriggerBuild) 684 685 def _checkTriggerBuild(self, res): 686 self.failIfFlagNotSet('triggerer_started') 687 self.failIfFlagNotSet('triggeree_started') 688 self.failIfFlagSet('triggeree_finished') 689 self.failIfFlagNotSet('triggerer_finished') 690 691 def testTriggerBuildWait(self): 692 return self.setupTest("schedulers=['triggeree'], waitForFinish=1", 693 "Dummy", 694 self._checkTriggerBuildWait) 695 696 def _checkTriggerBuildWait(self, res): 697 self.failIfFlagNotSet('triggerer_started') 698 self.failIfFlagNotSet('triggeree_started') 699 self.failIfFlagSet('triggeree_finished') 700 self.failIfFlagSet('triggerer_finished') 701 631 702 # TODO: test everything, from Change submission to Scheduler to Build to 632 703 # Status. Use all the status types. Specifically I want to catch recurrences 633 704 # of the bug where I forgot to make Waterfall inherit from StatusReceiver -
docs/buildbot.texinfo
diff -rN -u old-trunk/docs/buildbot.texinfo new-trunk/docs/buildbot.texinfo
old new 2186 2186 scheduler is triggered. The next section (@pxref{Build Dependencies}) 2187 2187 describes this scheduler in more detail. 2188 2188 2189 @item Triggerable 2190 This scheduler does nothing until it is triggered by a Trigger 2191 step in another build. This facilitates a more general form of 2192 build dependencies, as described in the next section (@pxref{Build 2193 Dependencies}). 2194 2189 2195 @item Periodic 2190 2196 This simple scheduler just triggers a build every N seconds. 2191 2197 … … 2212 2218 @cindex Dependent 2213 2219 @cindex Dependencies 2214 2220 @slindex buildbot.scheduler.Dependent 2221 @slindex buildbot.scheduler.Triggerable 2215 2222 2216 2223 It is common to wind up with one kind of build which should only be 2217 2224 performed if the same source code was successfully handled by some … … 2254 2261 @code{Scheduler} @emph{instance}, not a name. This makes it impossible 2255 2262 to create circular dependencies in the config file. 2256 2263 2264 A more general way to coordinate builds is by ``triggering'' schedulers 2265 from builds. The Triggerable waits to be triggered by a 2266 Trigger step in another build. That step can optionally 2267 wait for the scheduler's builds to complete. This provides two 2268 advantages over Dependent schedulers. First, the same scheduler 2269 can be triggered from multiple builds. Second, the ability to wait 2270 for a Triggerable's builds to complete provides a form of 2271 "subroutine call", where one or more builds can "call" a scheduler 2272 to perform some work for them, perhaps on other buildslaves. 2273 2274 @example 2275 from buildbot import scheduler 2276 from buildbot.steps import trigger 2277 checkin = scheduler.Scheduler("checkin", None, 5*60, 2278 ["checkin"]) 2279 nightly = scheduler.Scheduler("nightly", ... 2280 ["nightly"]) 2281 mktarball = scheduler.Triggerable("mktarball", 2282 ["mktarball"]) 2283 build = scheduler.Triggerable("build-all-platforms", 2284 ["build-all-platforms"]) 2285 test = scheduler.Triggerable("distributed-test", 2286 ["distributed-test"]) 2287 package = scheduler.Triggerable("package-all-platforms", 2288 ["package-all-platforms"]) 2289 c['schedulers'] = [checkin, nightly, build, test, package] 2290 2291 checkin_factory = factory.BuildFactory() 2292 f.addStep(trigger.TriggerStep('mktarball', 2293 schedulers=['mktarball'], 2294 waitForFinish=1) 2295 f.addStep(trigger.TriggerStep('build', 2296 schedulers=['build-all-platforms'], 2297 waitForFinish=1) 2298 f.addStep(trigger.TriggerStep('test', 2299 schedulers=['distributed-test'], 2300 waitForFinish=1) 2301 2302 nightly_factory = factory.BuildFactory() 2303 f.addStep(trigger.TriggerStep('mktarball', 2304 schedulers=['mktarball'], 2305 waitForFinish=1) 2306 f.addStep(trigger.TriggerStep('build', 2307 schedulers=['build-all-platforms'], 2308 waitForFinish=1) 2309 f.addStep(trigger.TriggerStep('package', 2310 schedulers=['package-all-platforms'], 2311 waitForFinish=1) 2312 @end example 2257 2313 2258 2314 @node Setting the slaveport, Buildslave Specifiers, Listing Change Sources and Schedulers, Configuration 2259 2315 @section Setting the slaveport … … 3660 3716 * Simple ShellCommand Subclasses:: 3661 3717 * Python BuildSteps:: 3662 3718 * Transferring Files:: 3719 * Triggering Schedulers:: 3663 3720 * Writing New BuildSteps:: 3664 3721 @end menu 3665 3722 … … 4596 4653 4597 4654 @end table 4598 4655 4599 @node Python BuildSteps, Tr ansferring Files, Simple ShellCommand Subclasses, Build Steps4656 @node Python BuildSteps, Triggering Schedulers, Simple ShellCommand Subclasses, Build Steps 4600 4657 @subsection Python BuildSteps 4601 4658 4602 4659 Here are some BuildSteps that are specifcally useful for projects … … 4672 4729 @end example 4673 4730 4674 4731 4675 @node Transferring Files, Writing New BuildSteps, Python BuildSteps, Build Steps4732 @node Transferring Files, Triggering Schedulers, Python BuildSteps, Build Steps 4676 4733 @subsection Transferring Files 4677 4734 4678 4735 @cindex File Transfer … … 4761 4818 creation time (@pxref{Buildslave Options}). 4762 4819 4763 4820 4764 @node Writing New BuildSteps, , Transferring Files, Build Steps 4821 @node Triggering Schedulers, Writing New BuildSteps, Transferring Files, Build Steps 4822 @subsection Triggering Schedulers 4823 4824 The counterpart to the Triggerable described in section 4825 @pxref{Build Dependencies} is the Trigger BuildStep. 4826 4827 @example 4828 from buildbot.steps.trigger import Trigger 4829 f.addStep(Trigger, 4830 schedulers=['build-prep'], 4831 waitForFinish=1, 4832 updateSourceStamp=1) 4833 @end example 4834 4835 The @code{schedulers=} argument lists the Triggerables 4836 that should be triggered when this step is executed. Note that 4837 it is possible, but not advisable, to create a cycle where a build 4838 continually triggers itself, because the schedulers are specified 4839 by name. 4840 4841 If @code{waitForFinish} is true, then the step will not finish until 4842 all of the builds from the triggered schedulers have finished. If this 4843 argument is not given, then the buildstep succeeds immediately after 4844 triggering the schedulers. 4845 4846 If @code{updateSourceStamp} is true, then step updates the SourceStamp 4847 given to the Triggerables to include @code{got_revision} 4848 (the revision actually used in this build) as @code{revision} (the 4849 revision to use in the triggered builds). This is useful to ensure 4850 that all of the builds use exactly the same SourceStamp, even if 4851 other Changes have occurred while the build was running. 4852 4853 @node Writing New BuildSteps, , Triggering Schedulers, Build Steps 4765 4854 @subsection Writing New BuildSteps 4766 4855 4767 4856 While it is a good idea to keep your build process self-contained in
![[Buildbot Logo]](/chrome/site/header-text-transparent.png)