| OLD | NEW |
| (Empty) |
| 1 from buildbot.process.buildstep import LoggingBuildStep, SUCCESS, FAILURE, EXCEP
TION | |
| 2 from buildbot.process.properties import Properties | |
| 3 from buildbot.scheduler import Triggerable | |
| 4 from twisted.internet import defer | |
| 5 | |
| 6 class Trigger(LoggingBuildStep): | |
| 7 """I trigger a scheduler.Triggerable, to use one or more Builders as if | |
| 8 they were a single buildstep (like a subroutine call). | |
| 9 """ | |
| 10 name = "trigger" | |
| 11 | |
| 12 flunkOnFailure = True | |
| 13 | |
| 14 def __init__(self, schedulerNames=[], updateSourceStamp=True, | |
| 15 waitForFinish=False, set_properties={}, copy_properties=[], **k
wargs): | |
| 16 """ | |
| 17 Trigger the given schedulers when this step is executed. | |
| 18 | |
| 19 @param schedulerNames: A list of scheduler names that should be | |
| 20 triggered. Schedulers can be specified using | |
| 21 WithProperties, if desired. | |
| 22 | |
| 23 @param updateSourceStamp: If True (the default), I will try to give | |
| 24 the schedulers an absolute SourceStamp for | |
| 25 their builds, so that a HEAD build will use | |
| 26 the same revision even if more changes have | |
| 27 occurred since my build's update step was | |
| 28 run. If False, I will use the original | |
| 29 SourceStamp unmodified. | |
| 30 | |
| 31 @param waitForFinish: If False (the default), this step will finish | |
| 32 as soon as I've started the triggered | |
| 33 schedulers. If True, I will wait until all of | |
| 34 the triggered schedulers have finished their | |
| 35 builds. | |
| 36 | |
| 37 @param set_properties: A dictionary of properties to set for any | |
| 38 builds resulting from this trigger. These | |
| 39 properties will override properties set in the | |
| 40 Triggered scheduler's constructor. | |
| 41 | |
| 42 @param copy_properties: a list of property names to copy verbatim | |
| 43 into any builds resulting from this trigger. | |
| 44 | |
| 45 """ | |
| 46 assert schedulerNames, "You must specify a scheduler to trigger" | |
| 47 self.schedulerNames = schedulerNames | |
| 48 self.updateSourceStamp = updateSourceStamp | |
| 49 self.waitForFinish = waitForFinish | |
| 50 self.set_properties = set_properties | |
| 51 self.copy_properties = copy_properties | |
| 52 self.running = False | |
| 53 LoggingBuildStep.__init__(self, **kwargs) | |
| 54 self.addFactoryArguments(schedulerNames=schedulerNames, | |
| 55 updateSourceStamp=updateSourceStamp, | |
| 56 waitForFinish=waitForFinish, | |
| 57 set_properties=set_properties, | |
| 58 copy_properties=copy_properties) | |
| 59 | |
| 60 def interrupt(self, reason): | |
| 61 # TODO: this doesn't actually do anything. | |
| 62 if self.running: | |
| 63 self.step_status.setText(["interrupted"]) | |
| 64 | |
| 65 def start(self): | |
| 66 properties = self.build.getProperties() | |
| 67 | |
| 68 # make a new properties object from a dict rendered by the old | |
| 69 # properties object | |
| 70 props_to_set = Properties() | |
| 71 props_to_set.update(properties.render(self.set_properties), "Trigger") | |
| 72 for p in self.copy_properties: | |
| 73 if p not in properties: | |
| 74 raise RuntimeError("copy_property '%s' is not set in the trigger
ing build" % p) | |
| 75 props_to_set.setProperty(p, properties[p], | |
| 76 "%s (in triggering build)" % properties.getPropertySourc
e(p)) | |
| 77 | |
| 78 self.running = True | |
| 79 ss = self.build.getSourceStamp() | |
| 80 if self.updateSourceStamp: | |
| 81 got = properties.getProperty('got_revision') | |
| 82 if got: | |
| 83 ss = ss.getAbsoluteSourceStamp(got) | |
| 84 | |
| 85 # (is there an easier way to find the BuildMaster?) | |
| 86 all_schedulers = self.build.builder.botmaster.parent.allSchedulers() | |
| 87 all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) | |
| 88 unknown_schedulers = [] | |
| 89 triggered_schedulers = [] | |
| 90 | |
| 91 # TODO: don't fire any schedulers if we discover an unknown one | |
| 92 dl = [] | |
| 93 for scheduler in self.schedulerNames: | |
| 94 scheduler = properties.render(scheduler) | |
| 95 if all_schedulers.has_key(scheduler): | |
| 96 sch = all_schedulers[scheduler] | |
| 97 if isinstance(sch, Triggerable): | |
| 98 dl.append(sch.trigger(ss, set_props=props_to_set)) | |
| 99 triggered_schedulers.append(scheduler) | |
| 100 else: | |
| 101 unknown_schedulers.append(scheduler) | |
| 102 else: | |
| 103 unknown_schedulers.append(scheduler) | |
| 104 | |
| 105 if unknown_schedulers: | |
| 106 self.step_status.setText(['no scheduler:'] + unknown_schedulers) | |
| 107 rc = FAILURE | |
| 108 else: | |
| 109 rc = SUCCESS | |
| 110 self.step_status.setText(['triggered'] + triggered_schedulers) | |
| 111 | |
| 112 if self.waitForFinish: | |
| 113 d = defer.DeferredList(dl, consumeErrors=1) | |
| 114 else: | |
| 115 d = defer.succeed([]) | |
| 116 | |
| 117 def cb(rclist): | |
| 118 rc = SUCCESS # (this rc is not the same variable as that above) | |
| 119 for was_cb, buildsetstatus in rclist: | |
| 120 # TODO: make this algo more configurable | |
| 121 if not was_cb: | |
| 122 rc = EXCEPTION | |
| 123 break | |
| 124 if buildsetstatus.getResults() == FAILURE: | |
| 125 rc = FAILURE | |
| 126 return self.finished(rc) | |
| 127 | |
| 128 def eb(why): | |
| 129 return self.finished(FAILURE) | |
| 130 | |
| 131 d.addCallbacks(cb, eb) | |
| OLD | NEW |