Merge "Cancel jobs behind a failed change."
diff --git a/zuul/model.py b/zuul/model.py
index 86fdc5c..f95195d 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -489,6 +489,14 @@
return False
return True
+ def didAnyJobFail(self):
+ tree = self.project.getJobTreeForQueue(self.queue_name)
+ for job in self._filterJobs(tree.getJobs()):
+ build = self.current_build_set.getBuild(job.name)
+ if build and build.result == 'FAILURE':
+ return True
+ return False
+
def delete(self):
if self.change_behind:
self.change_behind.change_ahead = None
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index 232804d..7b28dec 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -632,10 +632,11 @@
change.change_behind, change))
self.launchJobs(change.change_behind)
- def cancelJobs(self, change):
+ def cancelJobs(self, change, prime=True):
self.log.debug("Cancel jobs for change %s" % change)
to_remove = []
- change.resetAllBuilds()
+ if prime:
+ change.resetAllBuilds()
for build, build_change in self.building_jobs.items():
if build_change == change:
self.log.debug("Found build %s for change %s to cancel" % (
@@ -653,7 +654,20 @@
if change.change_behind:
self.log.debug("Canceling jobs for change %s, \
behind change %s" % (change.change_behind, change))
- self.cancelJobs(change.change_behind)
+ self.cancelJobs(change.change_behind, prime=prime)
+
+ def onBuildCompleted(self, build):
+ change = self.building_jobs.get(build)
+ if not super(DependentQueueManager, self).onBuildCompleted(build):
+ return False
+ if change and change.didAnyJobFail():
+ # This or some other build failed. All changes behind this change
+ # will need to be retested. To free up resources cancel the builds
+ # behind this one as they will be rerun anyways.
+ self.cancelJobs(change.change_behind, prime=False)
+ self.log.debug("Canceling builds behind change: %s due to"
+ " failure." % change)
+ return True
def possiblyReportChange(self, change):
self.log.debug("Possibly reporting change %s" % change)