Merge "Report layout config errors for config repos" into feature/zuulv3
This commit is contained in:
commit
df1f701cb7
2
tests/fixtures/config/in-repo/git/common-config/playbooks/common-config-test.yaml
vendored
Normal file
2
tests/fixtures/config/in-repo/git/common-config/playbooks/common-config-test.yaml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
- hosts: all
|
||||
tasks: []
|
|
@ -35,3 +35,12 @@
|
|||
gerrit:
|
||||
verified: 0
|
||||
precedence: high
|
||||
|
||||
- job:
|
||||
name: common-config-test
|
||||
|
||||
- project:
|
||||
name: common-config
|
||||
tenant-one-gate:
|
||||
jobs:
|
||||
- common-config-test
|
||||
|
|
|
@ -185,7 +185,7 @@ class TestInRepoConfig(ZuulTestCase):
|
|||
dict(name='project-test1', result='SUCCESS', changes='2,1'),
|
||||
dict(name='project-test2', result='SUCCESS', changes='3,1')])
|
||||
|
||||
def test_dynamic_syntax_error(self):
|
||||
def test_untrusted_syntax_error(self):
|
||||
in_repo_conf = textwrap.dedent(
|
||||
"""
|
||||
- job:
|
||||
|
@ -206,6 +206,27 @@ class TestInRepoConfig(ZuulTestCase):
|
|||
self.assertIn('syntax error', A.messages[1],
|
||||
"A should have a syntax error reported")
|
||||
|
||||
def test_trusted_syntax_error(self):
|
||||
in_repo_conf = textwrap.dedent(
|
||||
"""
|
||||
- job:
|
||||
name: project-test2
|
||||
foo: error
|
||||
""")
|
||||
|
||||
file_dict = {'zuul.yaml': in_repo_conf}
|
||||
A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A',
|
||||
files=file_dict)
|
||||
A.addApproval('code-review', 2)
|
||||
self.fake_gerrit.addEvent(A.addApproval('approved', 1))
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(A.data['status'], 'NEW')
|
||||
self.assertEqual(A.reported, 2,
|
||||
"A should report start and failure")
|
||||
self.assertIn('syntax error', A.messages[1],
|
||||
"A should have a syntax error reported")
|
||||
|
||||
|
||||
class TestAnsible(AnsibleZuulTestCase):
|
||||
# A temporary class to hold new tests while others are disabled
|
||||
|
|
|
@ -841,21 +841,41 @@ class ConfigLoader(object):
|
|||
new_abide.tenants[tenant.name] = new_tenant
|
||||
return new_abide
|
||||
|
||||
def createDynamicLayout(self, tenant, files):
|
||||
config = tenant.config_repos_config.copy()
|
||||
for source, project in tenant.project_repos:
|
||||
for branch in source.getProjectBranches(project):
|
||||
def _loadDynamicProjectData(self, config, source, project, files,
|
||||
config_repo):
|
||||
for branch in source.getProjectBranches(project):
|
||||
data = None
|
||||
if config_repo:
|
||||
data = files.getFile(project.name, branch, 'zuul.yaml')
|
||||
if not data:
|
||||
data = files.getFile(project.name, branch, '.zuul.yaml')
|
||||
if data:
|
||||
source_context = model.SourceContext(project,
|
||||
branch, False)
|
||||
incdata = TenantParser._parseProjectRepoLayout(
|
||||
if data:
|
||||
source_context = model.SourceContext(project, branch,
|
||||
config_repo)
|
||||
if config_repo:
|
||||
incdata = TenantParser._parseConfigRepoLayout(
|
||||
data, source_context)
|
||||
else:
|
||||
incdata = project.unparsed_branch_config[branch]
|
||||
if not incdata:
|
||||
continue
|
||||
config.extend(incdata)
|
||||
incdata = TenantParser._parseProjectRepoLayout(
|
||||
data, source_context)
|
||||
else:
|
||||
incdata = project.unparsed_branch_config.get(branch)
|
||||
if not incdata:
|
||||
continue
|
||||
config.extend(incdata)
|
||||
|
||||
def createDynamicLayout(self, tenant, files, include_config_repos=False):
|
||||
if include_config_repos:
|
||||
config = model.UnparsedTenantConfig()
|
||||
for source, project in tenant.config_repos:
|
||||
self._loadDynamicProjectData(config, source, project,
|
||||
files, True)
|
||||
else:
|
||||
config = tenant.config_repos_config.copy()
|
||||
for source, project in tenant.project_repos:
|
||||
self._loadDynamicProjectData(config, source, project,
|
||||
files, False)
|
||||
|
||||
layout = model.Layout()
|
||||
# TODOv3(jeblair): copying the pipelines could be dangerous/confusing.
|
||||
layout.pipelines = tenant.layout.pipelines
|
||||
|
|
|
@ -466,6 +466,43 @@ class PipelineManager(object):
|
|||
newrev=newrev,
|
||||
)
|
||||
|
||||
def _loadDynamicLayout(self, item):
|
||||
# Load layout
|
||||
# Late import to break an import loop
|
||||
import zuul.configloader
|
||||
loader = zuul.configloader.ConfigLoader()
|
||||
|
||||
build_set = item.current_build_set
|
||||
self.log.debug("Load dynamic layout with %s" % build_set.files)
|
||||
try:
|
||||
# First parse the config with as it will land with the
|
||||
# full set of config and project repos. This lets us
|
||||
# catch syntax errors in config repos even though we won't
|
||||
# actually run with that config.
|
||||
loader.createDynamicLayout(
|
||||
item.pipeline.layout.tenant,
|
||||
build_set.files,
|
||||
include_config_repos=True)
|
||||
|
||||
# Then create the config a second time but without changes
|
||||
# to config repos so that we actually use this config.
|
||||
layout = loader.createDynamicLayout(
|
||||
item.pipeline.layout.tenant,
|
||||
build_set.files,
|
||||
include_config_repos=False)
|
||||
except zuul.configloader.ConfigurationSyntaxError as e:
|
||||
self.log.info("Configuration syntax error "
|
||||
"in dynamic layout %s" %
|
||||
build_set.files)
|
||||
item.setConfigError(str(e))
|
||||
return None
|
||||
except Exception:
|
||||
self.log.exception("Error in dynamic layout %s" %
|
||||
build_set.files)
|
||||
item.setConfigError("Unknown configuration error")
|
||||
return None
|
||||
return layout
|
||||
|
||||
def getLayout(self, item):
|
||||
if not item.change.updatesConfig():
|
||||
if item.item_ahead:
|
||||
|
@ -479,27 +516,7 @@ class PipelineManager(object):
|
|||
if build_set.merge_state == build_set.COMPLETE:
|
||||
if build_set.unable_to_merge:
|
||||
return None
|
||||
# Load layout
|
||||
# Late import to break an import loop
|
||||
import zuul.configloader
|
||||
loader = zuul.configloader.ConfigLoader()
|
||||
self.log.debug("Load dynamic layout with %s" % build_set.files)
|
||||
try:
|
||||
layout = loader.createDynamicLayout(
|
||||
item.pipeline.layout.tenant,
|
||||
build_set.files)
|
||||
except zuul.configloader.ConfigurationSyntaxError as e:
|
||||
self.log.info("Configuration syntax error "
|
||||
"in dynamic layout %s" %
|
||||
build_set.files)
|
||||
item.setConfigError(str(e))
|
||||
return None
|
||||
except Exception:
|
||||
self.log.exception("Error in dynamic layout %s" %
|
||||
build_set.files)
|
||||
item.setConfigError("Unknown configuration error")
|
||||
return None
|
||||
return layout
|
||||
return self._loadDynamicLayout(item)
|
||||
build_set.merge_state = build_set.PENDING
|
||||
self.log.debug("Preparing dynamic layout for: %s" % item.change)
|
||||
dependent_items = self.getDependentItems(item)
|
||||
|
@ -508,7 +525,7 @@ class PipelineManager(object):
|
|||
merger_items = map(self._makeMergerItem, all_items)
|
||||
self.sched.merger.mergeChanges(merger_items,
|
||||
item.current_build_set,
|
||||
['.zuul.yaml'],
|
||||
['zuul.yaml', '.zuul.yaml'],
|
||||
self.pipeline.precedence)
|
||||
|
||||
def prepareLayout(self, item):
|
||||
|
|
Loading…
Reference in New Issue