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.interfaces import ITriggerableScheduler 
 17  from buildbot.process.buildstep import LoggingBuildStep, SUCCESS, FAILURE, EXCEPTION 
 18  from buildbot.process.properties import Properties, Property 
 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', 'sourceStamps', 27 'updateSourceStamp', 'alwaysUseLatest' ] 28 29 flunkOnFailure = True 30
31 - def __init__(self, schedulerNames=[], sourceStamp = None, sourceStamps = None, 32 updateSourceStamp=None, alwaysUseLatest=False, 33 waitForFinish=False, set_properties={}, 34 copy_properties=[], **kwargs):
35 if not schedulerNames: 36 config.error( 37 "You must specify a scheduler to trigger") 38 if (sourceStamp or sourceStamps) and (updateSourceStamp is not None): 39 config.error( 40 "You can't specify both sourceStamps and updateSourceStamp") 41 if (sourceStamp or sourceStamps) and alwaysUseLatest: 42 config.error( 43 "You can't specify both sourceStamps and alwaysUseLatest") 44 if alwaysUseLatest and (updateSourceStamp is not None): 45 config.error( 46 "You can't specify both alwaysUseLatest and updateSourceStamp" 47 ) 48 self.schedulerNames = schedulerNames 49 self.sourceStamps = sourceStamps or [] 50 if sourceStamp: 51 self.sourceStamps.append(sourceStamp) 52 if updateSourceStamp is not None: 53 self.updateSourceStamp = updateSourceStamp 54 else: 55 self.updateSourceStamp = not (alwaysUseLatest or self.sourceStamps) 56 self.alwaysUseLatest = alwaysUseLatest 57 self.waitForFinish = waitForFinish 58 properties = {} 59 properties.update(set_properties) 60 for i in copy_properties: 61 properties[i] = Property(i) 62 self.set_properties = properties 63 self.running = False 64 self.ended = False 65 LoggingBuildStep.__init__(self, **kwargs)
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 # Create the properties that are used for the trigger
78 - def createTriggerProperties(self):
79 # make a new properties object from a dict rendered by the old 80 # properties object 81 trigger_properties = Properties() 82 trigger_properties.update(self.set_properties, "Trigger") 83 return trigger_properties
84 85 # Get all scheduler instances that were configured 86 # A tuple of (triggerables, invalidnames) is returned
87 - def getSchedulers(self):
88 all_schedulers = self.build.builder.botmaster.parent.allSchedulers() 89 all_schedulers = dict([(sch.name, sch) for sch in all_schedulers]) 90 invalid_schedulers = [] 91 triggered_schedulers = [] 92 # don't fire any schedulers if we discover an unknown one 93 for scheduler in self.schedulerNames: 94 scheduler = scheduler 95 if all_schedulers.has_key(scheduler): 96 sch = all_schedulers[scheduler] 97 if ITriggerableScheduler.providedBy(sch): 98 triggered_schedulers.append(sch) 99 else: 100 invalid_schedulers.append(scheduler) 101 else: 102 invalid_schedulers.append(scheduler) 103 104 return (triggered_schedulers, invalid_schedulers)
105
107 if self.sourceStamps: 108 ss_for_trigger = {} 109 for ss in self.sourceStamps: 110 codebase = ss.get('codebase','') 111 assert codebase not in ss_for_trigger, "codebase specified multiple times" 112 ss_for_trigger[codebase] = ss 113 return ss_for_trigger 114 115 if self.alwaysUseLatest: 116 return {} 117 118 # start with the sourcestamps from current build 119 ss_for_trigger = {} 120 objs_from_build = self.build.getAllSourceStamps() 121 for ss in objs_from_build: 122 ss_for_trigger[ss.codebase] = ss.asDict() 123 124 # overrule revision in sourcestamps with got revision 125 if self.updateSourceStamp: 126 got = self.build.build_status.getAllGotRevisions() 127 for codebase in ss_for_trigger: 128 if codebase in got: 129 ss_for_trigger[codebase]['revision'] = got[codebase] 130 131 return ss_for_trigger
132 133 @defer.inlineCallbacks
134 - def start(self):
135 # Get all triggerable schedulers and check if there are invalid schedules 136 (triggered_schedulers, invalid_schedulers) = self.getSchedulers() 137 if invalid_schedulers: 138 self.step_status.setText(['not valid scheduler:'] + invalid_schedulers) 139 self.end(FAILURE) 140 return 141 142 self.running = True 143 144 props_to_set = self.createTriggerProperties() 145 146 ss_for_trigger = self.prepareSourcestampListForTrigger() 147 148 dl = [] 149 triggered_names = [] 150 for sch in triggered_schedulers: 151 dl.append(sch.trigger(ss_for_trigger, set_props=props_to_set)) 152 triggered_names.append(sch.name) 153 self.step_status.setText(['triggered'] + triggered_names) 154 155 if self.waitForFinish: 156 rclist = yield defer.DeferredList(dl, consumeErrors=1) 157 else: 158 # do something to handle errors 159 for d in dl: 160 d.addErrback(log.err, 161 '(ignored) while invoking Triggerable schedulers:') 162 rclist = None 163 self.end(SUCCESS) 164 return 165 166 was_exception = was_failure = False 167 brids = {} 168 for was_cb, results in rclist: 169 if isinstance(results, tuple): 170 results, some_brids = results 171 brids.update(some_brids) 172 173 if not was_cb: 174 was_exception = True 175 log.err(results) 176 continue 177 178 if results==FAILURE: 179 was_failure = True 180 181 if was_exception: 182 result = EXCEPTION 183 elif was_failure: 184 result = FAILURE 185 else: 186 result = SUCCESS 187 188 if brids: 189 master = self.build.builder.botmaster.parent 190 def add_links(res): 191 # reverse the dictionary lookup for brid to builder name 192 brid_to_bn = dict((_brid,_bn) for _bn,_brid in brids.iteritems()) 193 194 for was_cb, builddicts in res: 195 if was_cb: 196 for build in builddicts: 197 bn = brid_to_bn[build['brid']] 198 num = build['number'] 199 200 url = master.status.getURLForBuild(bn, num) 201 self.step_status.addURL("%s #%d" % (bn,num), url) 202 203 return self.end(result)
204 205 builddicts = [master.db.builds.getBuildsForRequest(br) for br in brids.values()] 206 dl = defer.DeferredList(builddicts, consumeErrors=1) 207 dl.addCallback(add_links) 208 209 self.end(result) 210 return
211