Don't generate layouts on non live items

Non live items in Zuul queues never run jobs. They are dependency tree
markers to ensure that we contruct the correct final git states that do
run jobs. Previously we were generating layouts (necessary for running
jobs) on all of the non live items in queues which generated (n^2+n)/2
layouts when we only need a single layout for the terminal item.

Fix this by only generating layouts on live items. This introduces a
slightly new process for getting the correct layout on a child item.
The live child item can:
  Use pipeline layout when itself and items ahead do not modify layout
  Use its parent layout if parent item is live
  Generate its own layout if parent item is not live

The result is some cases where zuul would treat the parent items as
having syntax errors as a merge error in the child item now become
syntax errors in the child item. This is due to waiting to generate that
layout in the child rather than step by step.

The test that checked the old behavior described above has been updated
to reflect the new behavior introduced by this change.

Change-Id: I0d650eef9f7d1d0af46afcbabd76a1f2baf74efa
This commit is contained in:
Clark Boylan 2018-04-30 09:15:10 -07:00
parent 75f3478ed1
commit 4419672188
2 changed files with 25 additions and 8 deletions

View File

@ -1876,7 +1876,8 @@ class TestInRepoConfig(ZuulTestCase):
self.assertEqual(C.reported, 1,
"C should report failure")
self.assertIn('depends on a change that failed to merge',
self.assertIn('Zuul encountered a syntax error while parsing '
'its configuration',
C.messages[0],
"C should have an error reported")

View File

@ -477,13 +477,24 @@ class PipelineManager(object):
return None
return layout
def _queueUpdatesConfig(self, item):
while item:
if item.change.updatesConfig():
return True
item = item.item_ahead
return False
def getLayout(self, item):
if not item.change.updatesConfig():
if item.item_ahead:
return item.item_ahead.layout
else:
return item.queue.pipeline.layout
# This item updates the config, ask the merger for the result.
if not self._queueUpdatesConfig(item):
# No config updates in queue. Use existing pipeline layout
return item.queue.pipeline.layout
elif (not item.change.updatesConfig() and
item.item_ahead and item.item_ahead.live):
# Current change does not update layout, use its parent if parent
# has a layout.
return item.item_ahead.layout
# Else this item or a non live parent updates the config,
# ask the merger for the result.
build_set = item.current_build_set
if build_set.merge_state == build_set.PENDING:
return None
@ -531,7 +542,12 @@ class PipelineManager(object):
def prepareJobs(self, item):
# This only runs once the item is in the pipeline's action window
# Returns True if the item is ready, false otherwise
if not item.layout:
if not item.live:
# Short circuit as non live items don't need layouts.
# We also don't need to take further ready actions in
# _processOneItem() so we return false.
return False
elif not item.layout:
item.layout = self.getLayout(item)
if not item.layout:
return False