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  from buildbot import config 
 22   
23 -class Trigger(LoggingBuildStep):
24 name = "trigger" 25 26 renderables = [ 'set_properties', 'schedulerNames', 'sourceStamp', 27 'updateSourceStamp', 'alwaysUseLatest' ] 28 29 flunkOnFailure = True 30
31 - def __init__(self, schedulerNames=[], sourceStamp=None, updateSourceStamp=None, alwaysUseLatest=False, 32 waitForFinish=False, set_properties={}, copy_properties=[], **kwargs):
33 if not schedulerNames: 34 config.error( 35 "You must specify a scheduler to trigger") 36 if sourceStamp and (updateSourceStamp is not None): 37 config.error( 38 "You can't specify both sourceStamp and updateSourceStamp") 39 if sourceStamp and alwaysUseLatest: 40 config.error( 41 "You can't specify both sourceStamp and alwaysUseLatest") 42 if alwaysUseLatest and (updateSourceStamp is not None): 43 config.error( 44 "You can't specify both alwaysUseLatest and updateSourceStamp" 45 ) 46 self.schedulerNames = schedulerNames 47 self.sourceStamp = sourceStamp 48 if updateSourceStamp is not None: 49 self.updateSourceStamp = updateSourceStamp 50 else: 51 self.updateSourceStamp = not (alwaysUseLatest or sourceStamp) 52 self.alwaysUseLatest = alwaysUseLatest 53 self.waitForFinish = waitForFinish 54 self.set_properties = set_properties 55 self.copy_properties = copy_properties 56 self.running = False 57 self.ended = False 58 LoggingBuildStep.__init__(self, **kwargs) 59 self.addFactoryArguments(schedulerNames=schedulerNames, 60 sourceStamp=sourceStamp, 61 updateSourceStamp=updateSourceStamp, 62 alwaysUseLatest=alwaysUseLatest, 63 waitForFinish=waitForFinish, 64 set_properties=set_properties, 65 copy_properties=copy_properties)
66
67 - def interrupt(self, reason):
68 if self.running and not self.ended: 69 self.step_status.setText(["interrupted"]) 70 return self.end(EXCEPTION)
71
72 - def end(self, result):
73 if not self.ended: 74 self.ended = True 75 return self.finished(result)
76
77 - def start(self):
78 properties = self.build.getProperties() 79 80 # make a new properties object from a dict rendered by the old 81 # properties object 82 props_to_set = Properties() 83 props_to_set.update(self.set_properties, "Trigger") 84 for p in self.copy_properties: 85 if p not in properties: 86 continue 87 props_to_set.setProperty(p, properties[p], 88 "%s (in triggering build)" % properties.getPropertySource(p)) 89 90 self.running = True 91 92 # (is there an easier way to find the BuildMaster?) 93 all_schedulers = self.build.builder.botmaster.parent.allSchedulers() 94 all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) 95 unknown_schedulers = [] 96 triggered_schedulers = [] 97 98 # don't fire any schedulers if we discover an unknown one 99 for scheduler in self.schedulerNames: 100 scheduler = scheduler 101 if all_schedulers.has_key(scheduler): 102 sch = all_schedulers[scheduler] 103 if isinstance(sch, Triggerable): 104 triggered_schedulers.append(scheduler) 105 else: 106 unknown_schedulers.append(scheduler) 107 else: 108 unknown_schedulers.append(scheduler) 109 110 if unknown_schedulers: 111 self.step_status.setText(['no scheduler:'] + unknown_schedulers) 112 return self.end(FAILURE) 113 114 master = self.build.builder.botmaster.parent # seriously?! 115 116 def add_sourcestamp_to_set(ss_setid, sourceStamp): 117 d = master.db.sourcestamps.addSourceStamp( 118 sourcestampsetid = ss_setid, 119 **sourceStamp) 120 d.addCallback(lambda _ : ss_setid) 121 return d
122 123 if self.sourceStamp: 124 d = master.db.sourcestampsets.addSourceStampSet() 125 d.addCallback(add_sourcestamp_to_set, self.sourceStamp) 126 elif self.alwaysUseLatest: 127 d = defer.succeed(None) 128 else: 129 ss = self.build.getSourceStamp() 130 if self.updateSourceStamp: 131 got = properties.getProperty('got_revision') 132 if got: 133 ss = ss.getAbsoluteSourceStamp(got) 134 d = ss.getSourceStampSetId(master) 135 def start_builds(ss_setid): 136 dl = [] 137 for scheduler in triggered_schedulers: 138 sch = all_schedulers[scheduler] 139 dl.append(sch.trigger(ss_setid, set_props=props_to_set)) 140 self.step_status.setText(['triggered'] + triggered_schedulers) 141 142 if self.waitForFinish: 143 return defer.DeferredList(dl, consumeErrors=1) 144 else: 145 # do something to handle errors 146 for d in dl: 147 d.addErrback(log.err, 148 '(ignored) while invoking Triggerable schedulers:') 149 self.end(SUCCESS) 150 return None
151 d.addCallback(start_builds) 152 153 def cb(rclist): 154 was_exception = was_failure = False 155 brids = {} 156 for was_cb, results in rclist: 157 if isinstance(results, tuple): 158 results, some_brids = results 159 brids.update(some_brids) 160 161 if not was_cb: 162 was_exception = True 163 log.err(results) 164 continue 165 166 if results==FAILURE: 167 was_failure = True 168 169 if was_exception: 170 result = EXCEPTION 171 elif was_failure: 172 result = FAILURE 173 else: 174 result = SUCCESS 175 176 if brids: 177 def add_links(res): 178 # reverse the dictionary lookup for brid to builder name 179 brid_to_bn = dict((_brid,_bn) for _bn,_brid in brids.iteritems()) 180 181 for was_cb, builddicts in res: 182 if was_cb: 183 for build in builddicts: 184 bn = brid_to_bn[build['brid']] 185 num = build['number'] 186 187 url = master.status.getURLForBuild(bn, num) 188 self.step_status.addURL("%s #%d" % (bn,num), url) 189 190 return self.end(result) 191 192 builddicts = [master.db.builds.getBuildsForRequest(br) for br in brids.values()] 193 dl = defer.DeferredList(builddicts, consumeErrors=1) 194 dl.addCallback(add_links) 195 return dl 196 197 return self.end(result) 198 def eb(why): 199 return self.end(FAILURE) 200 201 if self.waitForFinish: 202 d.addCallbacks(cb, eb) 203 204 d.addErrback(log.err, '(ignored) while triggering builds:') 205