Apply metajobs in order
Metajobs were being applied in dict key order, which meant that
if more that one metajob matched a job, the actual attributes
applied were non-deterministic. This was compounded by the fact
that attributes of each metajob were being strictly copied to
the real job, so the attributes of the second metajob would always
completely replace the first.
Instead, keep metajobs in config file order, and only copy attributes
that are non-null. Boolean attributes are still last-wins, and
so must be set explicitly by each matching metajob.
Change-Id: Ie255658719d5ded1663c3513dae1fc297ce357c4
diff --git a/zuul/model.py b/zuul/model.py
index 312ca50..337e772 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -437,17 +437,24 @@
return '<Job %s>' % (self.name)
def copy(self, other):
- self.failure_message = other.failure_message
- self.success_message = other.success_message
- self.failure_pattern = other.failure_pattern
- self.success_pattern = other.success_pattern
- self.parameter_function = other.parameter_function
+ if other.failure_message:
+ self.failure_message = other.failure_message
+ if other.success_message:
+ self.success_message = other.success_message
+ if other.failure_pattern:
+ self.failure_pattern = other.failure_pattern
+ if other.success_pattern:
+ self.success_pattern = other.success_pattern
+ if other.parameter_function:
+ self.parameter_function = other.parameter_function
+ if other.branches:
+ self.branches = other.branches[:]
+ self._branches = other._branches[:]
+ if other.files:
+ self.files = other.files[:]
+ self._files = other._files[:]
self.hold_following_changes = other.hold_following_changes
self.voting = other.voting
- self.branches = other.branches[:]
- self._branches = other._branches[:]
- self.files = other.files[:]
- self._files = other._files[:]
def changeMatches(self, change):
matches_branch = False
@@ -848,7 +855,7 @@
self.projects = {}
self.pipelines = {}
self.jobs = {}
- self.metajobs = {}
+ self.metajobs = []
def getJob(self, name):
if name in self.jobs:
@@ -857,10 +864,10 @@
if name.startswith('^'):
# This is a meta-job
regex = re.compile(name)
- self.metajobs[regex] = job
+ self.metajobs.append((regex, job))
else:
# Apply attributes from matching meta-jobs
- for regex, metajob in self.metajobs.items():
+ for regex, metajob in self.metajobs:
if regex.match(name):
job.copy(metajob)
self.jobs[name] = job
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index 71d0db8..4bcd21c 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -239,7 +239,7 @@
# All jobs should be defined at this point, get rid of
# metajobs so that getJob isn't doing anything weird.
- layout.metajobs = {}
+ layout.metajobs = []
for pipeline in layout.pipelines.values():
pipeline.manager._postConfig(layout)