Package buildbot :: Package steps :: Module trigger
[frames] | no frames]

Source Code for Module buildbot.steps.trigger

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16  from buildbot.process.buildstep import LoggingBuildStep, SUCCESS, FAILURE, EXCEPTION 
 17  from buildbot.process.properties import Properties 
 18  from buildbot.schedulers.triggerable import Triggerable 
 19  from twisted.python import log 
 20  from twisted.internet import defer 
 21   
22 -class Trigger(LoggingBuildStep):
23 """I trigger a scheduler.Triggerable, to use one or more Builders as if 24 they were a single buildstep (like a subroutine call). 25 """ 26 name = "trigger" 27 28 renderables = [ 'set_properties', 'schedulerNames', 'sourceStamp' ] 29 30 flunkOnFailure = True 31
32 - def __init__(self, schedulerNames=[], sourceStamp=None, updateSourceStamp=None, alwaysUseLatest=False, 33 waitForFinish=False, set_properties={}, copy_properties=[], **kwargs):
34 """ 35 Trigger the given schedulers when this step is executed. 36 37 @param schedulerNames: A list of scheduler names that should be 38 triggered. Schedulers can be specified using 39 WithProperties, if desired. 40 41 @param sourceStamp: A dict containing the source stamp to use for the 42 build. Keys must include branch, revision, repository and 43 project. In addition, patch_body, patch_level, and 44 patch_subdir can be specified. Only one of 45 sourceStamp, updateSourceStamp and alwaysUseLatest 46 can be specified. Any of these can be specified using 47 WithProperties, if desired. 48 49 @param updateSourceStamp: If True (the default), I will try to give 50 the schedulers an absolute SourceStamp for 51 their builds, so that a HEAD build will use 52 the same revision even if more changes have 53 occurred since my build's update step was 54 run. If False, I will use the original 55 SourceStamp unmodified. 56 57 @param alwaysUseLatest: If False (the default), I will give the 58 SourceStamp of the current build to the 59 schedulers (as controled by updateSourceStamp). 60 If True, I will give the schedulers an empty 61 SourceStamp, corresponding to the latest 62 revision. 63 64 @param waitForFinish: If False (the default), this step will finish 65 as soon as I've started the triggered 66 schedulers. If True, I will wait until all of 67 the triggered schedulers have finished their 68 builds. 69 70 @param set_properties: A dictionary of properties to set for any 71 builds resulting from this trigger. These 72 properties will override properties set in the 73 Triggered scheduler's constructor. 74 75 @param copy_properties: a list of property names to copy verbatim 76 into any builds resulting from this trigger. 77 78 """ 79 assert schedulerNames, "You must specify a scheduler to trigger" 80 if sourceStamp and updateSourceStamp: 81 raise ValueError("You can't specify both sourceStamp and updateSourceStamp") 82 if sourceStamp and alwaysUseLatest: 83 raise ValueError("You can't specify both sourceStamp and alwaysUseLatest") 84 if alwaysUseLatest and updateSourceStamp: 85 raise ValueError("You can't specify both alwaysUseLatest and updateSourceStamp") 86 self.schedulerNames = schedulerNames 87 self.sourceStamp = sourceStamp 88 self.updateSourceStamp = updateSourceStamp or not (alwaysUseLatest or sourceStamp) 89 self.alwaysUseLatest = alwaysUseLatest 90 self.waitForFinish = waitForFinish 91 self.set_properties = set_properties 92 self.copy_properties = copy_properties 93 self.running = False 94 self.ended = False 95 LoggingBuildStep.__init__(self, **kwargs) 96 self.addFactoryArguments(schedulerNames=schedulerNames, 97 sourceStamp=sourceStamp, 98 updateSourceStamp=updateSourceStamp, 99 alwaysUseLatest=alwaysUseLatest, 100 waitForFinish=waitForFinish, 101 set_properties=set_properties, 102 copy_properties=copy_properties)
103
104 - def interrupt(self, reason):
105 if self.running: 106 self.step_status.setText(["interrupted"]) 107 return self.end(EXCEPTION)
108
109 - def end(self, result):
110 if not self.ended: 111 self.ended = True 112 return self.finished(result)
113
114 - def start(self):
115 properties = self.build.getProperties() 116 117 # make a new properties object from a dict rendered by the old 118 # properties object 119 props_to_set = Properties() 120 props_to_set.update(self.set_properties, "Trigger") 121 for p in self.copy_properties: 122 if p not in properties: 123 continue 124 props_to_set.setProperty(p, properties[p], 125 "%s (in triggering build)" % properties.getPropertySource(p)) 126 127 self.running = True 128 129 # (is there an easier way to find the BuildMaster?) 130 all_schedulers = self.build.builder.botmaster.parent.allSchedulers() 131 all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) 132 unknown_schedulers = [] 133 triggered_schedulers = [] 134 135 # TODO: don't fire any schedulers if we discover an unknown one 136 for scheduler in self.schedulerNames: 137 scheduler = scheduler 138 if all_schedulers.has_key(scheduler): 139 sch = all_schedulers[scheduler] 140 if isinstance(sch, Triggerable): 141 triggered_schedulers.append(scheduler) 142 else: 143 unknown_schedulers.append(scheduler) 144 else: 145 unknown_schedulers.append(scheduler) 146 147 if unknown_schedulers: 148 self.step_status.setText(['no scheduler:'] + unknown_schedulers) 149 return self.end(FAILURE) 150 151 master = self.build.builder.botmaster.parent # seriously?! 152 if self.sourceStamp: 153 d = master.db.sourcestamps.addSourceStamp(**self.sourceStamp) 154 elif self.alwaysUseLatest: 155 d = defer.succeed(None) 156 else: 157 ss = self.build.getSourceStamp() 158 if self.updateSourceStamp: 159 got = properties.getProperty('got_revision') 160 if got: 161 ss = ss.getAbsoluteSourceStamp(got) 162 d = ss.getSourceStampId(master) 163 def start_builds(ssid): 164 dl = [] 165 for scheduler in triggered_schedulers: 166 sch = all_schedulers[scheduler] 167 dl.append(sch.trigger(ssid, set_props=props_to_set)) 168 self.step_status.setText(['triggered'] + triggered_schedulers) 169 170 d = defer.DeferredList(dl, consumeErrors=1) 171 if self.waitForFinish: 172 return d 173 else: 174 # do something to handle errors 175 d.addErrback(log.err, 176 '(ignored) while invoking Triggerable schedulers:') 177 self.end(SUCCESS) 178 return None
179 d.addCallback(start_builds) 180 181 def cb(rclist): 182 rc = SUCCESS # (this rc is not the same variable as that above) 183 for was_cb, results in rclist: 184 # TODO: make this algo more configurable 185 if not was_cb: 186 rc = EXCEPTION 187 log.err(results) 188 break 189 if results == FAILURE: 190 rc = FAILURE 191 return self.end(rc)
192 def eb(why): 193 return self.end(FAILURE) 194 195 if self.waitForFinish: 196 d.addCallbacks(cb, eb) 197 198 d.addErrback(log.err, '(ignored) while triggering builds:') 199