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 |