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
|
||||
only affect it.
|
||||
|
||||
See :attr:`pragma.implied-branch-matchers` for how to override
|
||||
this behavior on a per-file basis.
|
||||
|
||||
.. attr:: files
|
||||
|
||||
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
|
||||
|
||||
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")
|
||||
|
||||
|
||||
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):
|
||||
tenant_config_file = 'config/base-jobs/main.yaml'
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ class ZuulMark(object):
|
|||
class ZuulSafeLoader(yaml.SafeLoader):
|
||||
zuul_node_types = frozenset(('job', 'nodeset', 'secret', 'pipeline',
|
||||
'project', 'project-template',
|
||||
'semaphore'))
|
||||
'semaphore', 'pragma'))
|
||||
|
||||
def __init__(self, stream, context):
|
||||
wrapped_stream = io.StringIO(stream)
|
||||
|
@ -313,6 +313,30 @@ class EncryptedPKCS1_OAEP(yaml.YAMLObject):
|
|||
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):
|
||||
@staticmethod
|
||||
def getSchema(anonymous=False):
|
||||
|
@ -459,6 +483,13 @@ class JobParser(object):
|
|||
if project_pipeline:
|
||||
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
|
||||
# matchers.
|
||||
if job.source_context.trusted:
|
||||
|
@ -1462,6 +1493,12 @@ class TenantParser(object):
|
|||
@staticmethod
|
||||
def _parseLayoutItems(layout, tenant, data, scheduler, connections,
|
||||
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:
|
||||
for config_pipeline in data.pipelines:
|
||||
classes = TenantParser._getLoadClasses(
|
||||
|
|
|
@ -635,6 +635,7 @@ class SourceContext(object):
|
|||
self.branch = branch
|
||||
self.path = path
|
||||
self.trusted = trusted
|
||||
self.implied_branch_matchers = None
|
||||
|
||||
def __str__(self):
|
||||
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."""
|
||||
|
||||
def __init__(self):
|
||||
self.pragmas = []
|
||||
self.pipelines = []
|
||||
self.jobs = []
|
||||
self.project_templates = []
|
||||
|
@ -2348,6 +2350,7 @@ class UnparsedTenantConfig(object):
|
|||
|
||||
def copy(self):
|
||||
r = UnparsedTenantConfig()
|
||||
r.pragmas = copy.deepcopy(self.pragmas)
|
||||
r.pipelines = copy.deepcopy(self.pipelines)
|
||||
r.jobs = copy.deepcopy(self.jobs)
|
||||
r.project_templates = copy.deepcopy(self.project_templates)
|
||||
|
@ -2359,6 +2362,7 @@ class UnparsedTenantConfig(object):
|
|||
|
||||
def extend(self, conf):
|
||||
if isinstance(conf, UnparsedTenantConfig):
|
||||
self.pragmas.extend(conf.pragmas)
|
||||
self.pipelines.extend(conf.pipelines)
|
||||
self.jobs.extend(conf.jobs)
|
||||
self.project_templates.extend(conf.project_templates)
|
||||
|
@ -2393,6 +2397,8 @@ class UnparsedTenantConfig(object):
|
|||
self.secrets.append(value)
|
||||
elif key == 'semaphore':
|
||||
self.semaphores.append(value)
|
||||
elif key == 'pragma':
|
||||
self.pragmas.append(value)
|
||||
else:
|
||||
raise ConfigItemUnknownError()
|
||||
|
||||
|
|
Loading…
Reference in New Issue