Report dynamic layout config errors
If Zuul encounters a syntax error when loading an in-repo layout,
report that as a failure on the change. Try to provide as much
readable information as possible to allow the user to diagnose the
error.
All top-level configuration objects are updated to support a hidden
source context variable to aid in creating a useful error message.
Item.areAllJobsComplete is updated so that it returns true in the
case of a merge failure or config error. In Zuulv2, we knew what
jobs we would run even in those cases, but in Zuulv3, we don't, so
the item does not have a job tree, so in those cases, the item does
not report that all jobs are complete. Returining True in this case
allows the NNFI algorithm to continue and expel the item from the
queue, avoiding an inifinite loop.
The merge failure accessor method is simplified.
Change-Id: I9cf19b87c6af5926b5e8bb403b81ce0470e3592d
diff --git a/zuul/model.py b/zuul/model.py
index 96414be..19931ea 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -1012,6 +1012,7 @@
self.commit = None
self.zuul_url = None
self.unable_to_merge = False
+ self.config_error = None # None or an error message string.
self.failing_reasons = []
self.merge_state = self.NEW
self.nodesets = {} # job -> nodeset
@@ -1170,6 +1171,9 @@
return True
def areAllJobsComplete(self):
+ if (self.current_build_set.config_error or
+ self.current_build_set.unable_to_merge):
+ return True
if not self.hasJobTree():
return False
for job in self.getJobs():
@@ -1203,9 +1207,10 @@
return False
def didMergerFail(self):
- if self.current_build_set.unable_to_merge:
- return True
- return False
+ return self.current_build_set.unable_to_merge
+
+ def getConfigError(self):
+ return self.current_build_set.config_error
def isHoldingFollowingChanges(self):
if not self.live:
@@ -1325,6 +1330,10 @@
self.current_build_set.unable_to_merge = True
self._setAllJobsSkipped()
+ def setConfigError(self, error):
+ self.current_build_set.config_error = error
+ self._setAllJobsSkipped()
+
def _setAllJobsSkipped(self):
for job in self.getJobs():
fakebuild = Build(job, None)
@@ -2083,8 +2092,7 @@
"a single key (when parsing %s)" %
(conf,))
key, value = item.items()[0]
- if key in ['project', 'project-template', 'job']:
- value['_source_context'] = source_context
+ value['_source_context'] = source_context
if key == 'project':
name = value['name']
self.projects.setdefault(name, []).append(value)