aboutsummaryrefslogtreecommitdiffstats
path: root/GroupBuildStep.py
diff options
context:
space:
mode:
Diffstat (limited to 'GroupBuildStep.py')
-rw-r--r--GroupBuildStep.py201
1 files changed, 201 insertions, 0 deletions
diff --git a/GroupBuildStep.py b/GroupBuildStep.py
new file mode 100644
index 0000000..5f7d168
--- /dev/null
+++ b/GroupBuildStep.py
@@ -0,0 +1,201 @@
+import types
+import GroupBuildStepStatus
+from twisted.internet import defer
+from twisted.python import log
+from buildbot.process.buildstep import LoggingBuildStep
+from buildbot.status.builder import Results
+from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, \
+ EXCEPTION, RETRY, worst_status
+
+class GroupBuildStep(LoggingBuildStep):
+ renderables = ['description', 'descriptionDone']
+
+ finished = False
+ results = None
+ stopped = False
+ steps = []
+ buildslave = None
+ workdir = None
+
+ def __init__(self, steps = [], description=None, descriptionDone=None, links=[], **kwargs):
+ LoggingBuildStep.__init__(self, **kwargs)
+ self.addFactoryArguments(steps=steps,
+ description=description,
+ descriptionDone=descriptionDone,
+ links=links)
+ self.factories = [s.getStepFactory() for s in steps]
+ self.description = [description]
+ self.descriptionDone = [descriptionDone]
+ self.links = links
+
+ self.currentStep = None
+ self.terminate = False
+ self.results = [] # list of FAILURE, SUCCESS, WARNINGS, SKIPPED
+ self.result = SUCCESS # overall result, may downgrade after each step
+ self.text = [] # list of text string lists (text2)
+
+ def describe(self, done=False):
+ if done and self.descriptionDone is not None:
+ return self.descriptionDone
+ if self.description is not None:
+ return self.description
+ if currentStep is not None:
+ return currentStep.describe(done)
+ return LoggingBuildStep.describe(self, done)
+
+ def setBuild(self, build):
+ LoggingBuildStep.setBuild(self, build)
+
+ # create build steps like Build does it
+ # this has to be done here to be able to execute this
+ # build step more then once afte a master restart
+ for factory, args in self.factories:
+ args = args.copy()
+ try:
+ self.steps.append(factory(**args))
+ except:
+ log.msg("error while creating step, factory=%s, args=%s"
+ % (factory, args))
+ raise
+
+ for step in self.steps:
+ step.setBuild(build)
+
+ def setBuildSlave(self, buildslave):
+ LoggingBuildStep.setBuildSlave(self, buildslave)
+ for step in self.steps:
+ step.setBuildSlave(buildslave)
+
+ def setDefaultWorkdir(self, workdir):
+ LoggingBuildStep.setDefaultWorkdir(self, workdir)
+ for step in self.steps:
+ step.setDefaultWorkdir(workdir)
+
+ def setBuildSlave(self, buildslave):
+ self.buildslave = buildslave
+ LoggingBuildStep.setBuildSlave(self, buildslave)
+
+ def setDefaultWorkdir(self, workdir):
+ self.workdir = workdir
+ LoggingBuildStep.setDefaultWorkdir(self, workdir)
+
+ def setStepStatus(self, step_status):
+ LoggingBuildStep.setStepStatus(self, step_status)
+ i = 0
+ for step in self.steps:
+ substep_status = GroupBuildStepStatus(step_status, i)
+ substep_status.setName(step.name)
+ step.setBuild(self.build)
+ step.setDefaultWorkdir(self.workdir)
+ step.setBuildSlave(self.buildslave)
+ step.setStepStatus(substep_status)
+ i = i + 1
+
+ def startStep(self, remote):
+ self.remote = remote
+ return LoggingBuildStep.startStep(self, remote)
+
+ def start(self):
+ log.msg("start")
+ self.startNextStep()
+
+ def getNextStep(self):
+ if not self.steps:
+ return None
+ if not self.remote:
+ return None
+ if self.terminate or self.stopped:
+ # Run any remaining alwaysRun steps, and skip over the others
+ while True:
+ s = self.steps.pop(0)
+ if s.alwaysRun:
+ return s
+ if not self.steps:
+ return None
+ else:
+ return self.steps.pop(0)
+
+ def startNextStep(self):
+ try:
+ s = self.getNextStep()
+ except StopIteration:
+ s = None
+ if not s:
+ return self.allStepsDone()
+ self.currentStep = s
+ d = defer.maybeDeferred(s.startStep, self.remote)
+ d.addCallback(self._stepDone, s)
+ d.addErrback(self.failed)
+
+ def _stepDone(self, results, step):
+ self.currentStep = None
+ if self.finished:
+ return # build was interrupted, don't keep building
+ terminate = self.stepDone(results, step) # interpret/merge results
+ if terminate:
+ self.terminate = True
+ return self.startNextStep()
+
+ def stepDone(self, result, step):
+ terminate = False
+ text = None
+ if type(result) == types.TupleType:
+ result, text = result
+ assert type(result) == type(SUCCESS)
+ log.msg(" step '%s' complete: %s" % (step.name, Results[result]))
+ self.results.append(result)
+ if text:
+ self.text.extend(text)
+ if not self.remote:
+ terminate = True
+
+ possible_overall_result = result
+ if result == FAILURE:
+ if not step.flunkOnFailure:
+ possible_overall_result = SUCCESS
+ if step.warnOnFailure:
+ possible_overall_result = WARNINGS
+ if step.flunkOnFailure:
+ possible_overall_result = FAILURE
+ if step.haltOnFailure:
+ terminate = True
+ elif result == WARNINGS:
+ if not step.warnOnWarnings:
+ possible_overall_result = SUCCESS
+ else:
+ possible_overall_result = WARNINGS
+ if step.flunkOnWarnings:
+ possible_overall_result = FAILURE
+ elif result in (EXCEPTION, RETRY):
+ terminate = True
+
+ # if we skipped this step, then don't adjust the build status
+ if result != SKIPPED:
+ self.result = worst_status(self.result, possible_overall_result)
+
+ return terminate
+
+ def allStepsDone(self):
+ for link in self.links:
+ self.addURL(link['title'], self.build.getProperties().render(link['href']))
+
+ return LoggingBuildStep.finished(self, self.result)
+
+ def failed(self, why):
+ LoggingBuildStep.failed(self, why)
+
+ def interrupt(self, reason="<no reason given>"):
+ log.msg(" %s: stopping build: %s" % (self, reason))
+ if self.finished:
+ return
+
+ self.stopped = True
+ if self.currentStep:
+ self.currentStep.interrupt(reason)
+
+ self.result = EXCEPTION
+
+ if self._acquiringLock:
+ lock, access, d = self._acquiringLock
+ lock.stopWaitingUntilAvailable(self, access, d)
+ d.callback(None)