Add pragma directive
This allows the user to override the implied branch matcher behavior. Change-Id: I3ef43fd868988666cb01e8a6bb28552cc42151b4
This commit is contained in:
parent
df91ab36e1
commit
7edc25f773
|
@ -668,6 +668,9 @@ Here is an example of two job definitions:
|
||||||
affect that branch, and likewise, changes to the master branch
|
affect that branch, and likewise, changes to the master branch
|
||||||
only affect it.
|
only affect it.
|
||||||
|
|
||||||
|
See :attr:`pragma.implied-branch-matchers` for how to override
|
||||||
|
this behavior on a per-file basis.
|
||||||
|
|
||||||
.. attr:: files
|
.. attr:: files
|
||||||
|
|
||||||
This attribute indicates that the job should only run on changes
|
This attribute indicates that the job should only run on changes
|
||||||
|
@ -1275,3 +1278,41 @@ where it is updated is merged. An example follows:
|
||||||
:default: 1
|
:default: 1
|
||||||
|
|
||||||
The maximum number of running jobs which can use this semaphore.
|
The maximum number of running jobs which can use this semaphore.
|
||||||
|
|
||||||
|
.. _pragma:
|
||||||
|
|
||||||
|
Pragma
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
The `pragma` item does not behave like the others. It can not be
|
||||||
|
included or excluded from configuration loading by the administrator,
|
||||||
|
and does not form part of the final configuration itself. It is used
|
||||||
|
to alter how the configuration is processed while loading.
|
||||||
|
|
||||||
|
A pragma item only affects the current file. The same file in another
|
||||||
|
branch of the same project will not be affected, nor any other files
|
||||||
|
or any other projects. The effect is global within that file --
|
||||||
|
pragma directives may not be set and then unset within the same file.
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
- pragma:
|
||||||
|
implied-branch-matchers: False
|
||||||
|
|
||||||
|
.. attr:: pragma
|
||||||
|
|
||||||
|
The pragma item currently only supports one attribute:
|
||||||
|
|
||||||
|
.. attr:: implied-branch-matchers
|
||||||
|
|
||||||
|
This is a boolean, which, if set, may be used to enable
|
||||||
|
(``True``) or disable (``False``) the addition of implied branch
|
||||||
|
matchers to job definitions. Normally Zuul decides whether to
|
||||||
|
add these based on heuristics described in :attr:`job.branches`.
|
||||||
|
This attribute overrides that behavior.
|
||||||
|
|
||||||
|
This can be useful if a project has multiple branches, yet the
|
||||||
|
jobs defined in the master branch should apply to all branches.
|
||||||
|
|
||||||
|
Note that if a job contains an explicit branch matcher, it will
|
||||||
|
be used regardless of the value supplied here.
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
- pipeline:
|
||||||
|
name: check
|
||||||
|
manager: independent
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: patchset-created
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
Verified: 1
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
Verified: -1
|
||||||
|
|
||||||
|
- pipeline:
|
||||||
|
name: gate
|
||||||
|
manager: dependent
|
||||||
|
post-review: True
|
||||||
|
trigger:
|
||||||
|
gerrit:
|
||||||
|
- event: comment-added
|
||||||
|
approval:
|
||||||
|
- Approved: 1
|
||||||
|
success:
|
||||||
|
gerrit:
|
||||||
|
Verified: 2
|
||||||
|
submit: true
|
||||||
|
failure:
|
||||||
|
gerrit:
|
||||||
|
Verified: -2
|
||||||
|
start:
|
||||||
|
gerrit:
|
||||||
|
Verified: 0
|
||||||
|
precedence: high
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: base
|
||||||
|
parent: null
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: common-config
|
||||||
|
check:
|
||||||
|
jobs: []
|
||||||
|
gate:
|
||||||
|
jobs:
|
||||||
|
- noop
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: org/project
|
||||||
|
check:
|
||||||
|
jobs: []
|
||||||
|
gate:
|
||||||
|
jobs:
|
||||||
|
- noop
|
|
@ -0,0 +1 @@
|
||||||
|
test
|
|
@ -0,0 +1,2 @@
|
||||||
|
- job:
|
||||||
|
name: test-job
|
|
@ -0,0 +1,2 @@
|
||||||
|
- hosts: all
|
||||||
|
tasks: []
|
|
@ -0,0 +1,5 @@
|
||||||
|
- pragma:
|
||||||
|
implied-branch-matchers: False
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: test-job
|
|
@ -0,0 +1,8 @@
|
||||||
|
- tenant:
|
||||||
|
name: tenant-one
|
||||||
|
source:
|
||||||
|
gerrit:
|
||||||
|
config-projects:
|
||||||
|
- common-config
|
||||||
|
untrusted-projects:
|
||||||
|
- org/project
|
|
@ -1907,6 +1907,57 @@ class TestMaxTimeout(AnsibleZuulTestCase):
|
||||||
"B should not fail because of timeout limit")
|
"B should not fail because of timeout limit")
|
||||||
|
|
||||||
|
|
||||||
|
class TestPragma(ZuulTestCase):
|
||||||
|
tenant_config_file = 'config/pragma/main.yaml'
|
||||||
|
|
||||||
|
def test_no_pragma(self):
|
||||||
|
self.create_branch('org/project', 'stable')
|
||||||
|
with open(os.path.join(FIXTURE_DIR,
|
||||||
|
'config/pragma/git/',
|
||||||
|
'org_project/nopragma.yaml')) as f:
|
||||||
|
config = f.read()
|
||||||
|
file_dict = {'.zuul.yaml': config}
|
||||||
|
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
|
||||||
|
files=file_dict)
|
||||||
|
A.addApproval('Code-Review', 2)
|
||||||
|
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||||
|
self.waitUntilSettled()
|
||||||
|
self.fake_gerrit.addEvent(A.getChangeMergedEvent())
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
# This is an untrusted repo with 2 branches, so it should have
|
||||||
|
# an implied branch matcher for the job.
|
||||||
|
tenant = self.sched.abide.tenants.get('tenant-one')
|
||||||
|
jobs = tenant.layout.getJobs('test-job')
|
||||||
|
self.assertEqual(len(jobs), 1)
|
||||||
|
for job in tenant.layout.getJobs('test-job'):
|
||||||
|
self.assertIsNotNone(job.branch_matcher)
|
||||||
|
|
||||||
|
def test_pragma(self):
|
||||||
|
self.create_branch('org/project', 'stable')
|
||||||
|
with open(os.path.join(FIXTURE_DIR,
|
||||||
|
'config/pragma/git/',
|
||||||
|
'org_project/pragma.yaml')) as f:
|
||||||
|
config = f.read()
|
||||||
|
file_dict = {'.zuul.yaml': config}
|
||||||
|
A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A',
|
||||||
|
files=file_dict)
|
||||||
|
A.addApproval('Code-Review', 2)
|
||||||
|
self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
|
||||||
|
self.waitUntilSettled()
|
||||||
|
self.fake_gerrit.addEvent(A.getChangeMergedEvent())
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
# This is an untrusted repo with 2 branches, so it would
|
||||||
|
# normally have an implied branch matcher, but our pragma
|
||||||
|
# overrides it.
|
||||||
|
tenant = self.sched.abide.tenants.get('tenant-one')
|
||||||
|
jobs = tenant.layout.getJobs('test-job')
|
||||||
|
self.assertEqual(len(jobs), 1)
|
||||||
|
for job in tenant.layout.getJobs('test-job'):
|
||||||
|
self.assertIsNone(job.branch_matcher)
|
||||||
|
|
||||||
|
|
||||||
class TestBaseJobs(ZuulTestCase):
|
class TestBaseJobs(ZuulTestCase):
|
||||||
tenant_config_file = 'config/base-jobs/main.yaml'
|
tenant_config_file = 'config/base-jobs/main.yaml'
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ class ZuulMark(object):
|
||||||
class ZuulSafeLoader(yaml.SafeLoader):
|
class ZuulSafeLoader(yaml.SafeLoader):
|
||||||
zuul_node_types = frozenset(('job', 'nodeset', 'secret', 'pipeline',
|
zuul_node_types = frozenset(('job', 'nodeset', 'secret', 'pipeline',
|
||||||
'project', 'project-template',
|
'project', 'project-template',
|
||||||
'semaphore'))
|
'semaphore', 'pragma'))
|
||||||
|
|
||||||
def __init__(self, stream, context):
|
def __init__(self, stream, context):
|
||||||
wrapped_stream = io.StringIO(stream)
|
wrapped_stream = io.StringIO(stream)
|
||||||
|
@ -313,6 +313,30 @@ class EncryptedPKCS1_OAEP(yaml.YAMLObject):
|
||||||
private_key).decode('utf8')
|
private_key).decode('utf8')
|
||||||
|
|
||||||
|
|
||||||
|
class PragmaParser(object):
|
||||||
|
pragma = {
|
||||||
|
'implied-branch-matchers': bool,
|
||||||
|
'_source_context': model.SourceContext,
|
||||||
|
'_start_mark': ZuulMark,
|
||||||
|
}
|
||||||
|
|
||||||
|
schema = vs.Schema(pragma)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.log = logging.getLogger("zuul.PragmaParser")
|
||||||
|
|
||||||
|
def fromYaml(self, conf):
|
||||||
|
with configuration_exceptions('project-template', conf):
|
||||||
|
self.schema(conf)
|
||||||
|
|
||||||
|
bm = conf.get('implied-branch-matchers')
|
||||||
|
if bm is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
source_context = conf['_source_context']
|
||||||
|
source_context.implied_branch_matchers = bm
|
||||||
|
|
||||||
|
|
||||||
class NodeSetParser(object):
|
class NodeSetParser(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getSchema(anonymous=False):
|
def getSchema(anonymous=False):
|
||||||
|
@ -459,6 +483,13 @@ class JobParser(object):
|
||||||
if project_pipeline:
|
if project_pipeline:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# If the user has set a pragma directive for this, use the
|
||||||
|
# value (if unset, the value is None).
|
||||||
|
if job.source_context.implied_branch_matchers is True:
|
||||||
|
return [job.source_context.branch]
|
||||||
|
elif job.source_context.implied_branch_matchers is False:
|
||||||
|
return None
|
||||||
|
|
||||||
# If this is a trusted project, don't create implied branch
|
# If this is a trusted project, don't create implied branch
|
||||||
# matchers.
|
# matchers.
|
||||||
if job.source_context.trusted:
|
if job.source_context.trusted:
|
||||||
|
@ -1462,6 +1493,12 @@ class TenantParser(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parseLayoutItems(layout, tenant, data, scheduler, connections,
|
def _parseLayoutItems(layout, tenant, data, scheduler, connections,
|
||||||
skip_pipelines=False, skip_semaphores=False):
|
skip_pipelines=False, skip_semaphores=False):
|
||||||
|
# Handle pragma items first since they modify the source context
|
||||||
|
# used by other classes.
|
||||||
|
pragma_parser = PragmaParser()
|
||||||
|
for config_pragma in data.pragmas:
|
||||||
|
pragma_parser.fromYaml(config_pragma)
|
||||||
|
|
||||||
if not skip_pipelines:
|
if not skip_pipelines:
|
||||||
for config_pipeline in data.pipelines:
|
for config_pipeline in data.pipelines:
|
||||||
classes = TenantParser._getLoadClasses(
|
classes = TenantParser._getLoadClasses(
|
||||||
|
|
|
@ -635,6 +635,7 @@ class SourceContext(object):
|
||||||
self.branch = branch
|
self.branch = branch
|
||||||
self.path = path
|
self.path = path
|
||||||
self.trusted = trusted
|
self.trusted = trusted
|
||||||
|
self.implied_branch_matchers = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s/%s@%s' % (self.project, self.path, self.branch)
|
return '%s/%s@%s' % (self.project, self.path, self.branch)
|
||||||
|
@ -2338,6 +2339,7 @@ class UnparsedTenantConfig(object):
|
||||||
"""A collection of yaml lists that has not yet been parsed into objects."""
|
"""A collection of yaml lists that has not yet been parsed into objects."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.pragmas = []
|
||||||
self.pipelines = []
|
self.pipelines = []
|
||||||
self.jobs = []
|
self.jobs = []
|
||||||
self.project_templates = []
|
self.project_templates = []
|
||||||
|
@ -2348,6 +2350,7 @@ class UnparsedTenantConfig(object):
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
r = UnparsedTenantConfig()
|
r = UnparsedTenantConfig()
|
||||||
|
r.pragmas = copy.deepcopy(self.pragmas)
|
||||||
r.pipelines = copy.deepcopy(self.pipelines)
|
r.pipelines = copy.deepcopy(self.pipelines)
|
||||||
r.jobs = copy.deepcopy(self.jobs)
|
r.jobs = copy.deepcopy(self.jobs)
|
||||||
r.project_templates = copy.deepcopy(self.project_templates)
|
r.project_templates = copy.deepcopy(self.project_templates)
|
||||||
|
@ -2359,6 +2362,7 @@ class UnparsedTenantConfig(object):
|
||||||
|
|
||||||
def extend(self, conf):
|
def extend(self, conf):
|
||||||
if isinstance(conf, UnparsedTenantConfig):
|
if isinstance(conf, UnparsedTenantConfig):
|
||||||
|
self.pragmas.extend(conf.pragmas)
|
||||||
self.pipelines.extend(conf.pipelines)
|
self.pipelines.extend(conf.pipelines)
|
||||||
self.jobs.extend(conf.jobs)
|
self.jobs.extend(conf.jobs)
|
||||||
self.project_templates.extend(conf.project_templates)
|
self.project_templates.extend(conf.project_templates)
|
||||||
|
@ -2393,6 +2397,8 @@ class UnparsedTenantConfig(object):
|
||||||
self.secrets.append(value)
|
self.secrets.append(value)
|
||||||
elif key == 'semaphore':
|
elif key == 'semaphore':
|
||||||
self.semaphores.append(value)
|
self.semaphores.append(value)
|
||||||
|
elif key == 'pragma':
|
||||||
|
self.pragmas.append(value)
|
||||||
else:
|
else:
|
||||||
raise ConfigItemUnknownError()
|
raise ConfigItemUnknownError()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue