Add support for view-templates
Allow views to also be configured via templates similar to job-templates. This adds a new project key called "views" and parser type called "view-template" allowing the user to add custom views. Example: - view-template: name: '{name}-template-{seq}' description: 'testing view templates feature' view-type: list regex: 'test-view-.*' - project: name: 'test-view' views: - '{name}-template-{seq}' seq: - a - b - c Change-Id: I6eb225f24bc3c7d790c7dcab6391735c579ac71a Signed-off-by: Thanh Ha <thanh.ha@linuxfoundation.org>
This commit is contained in:
parent
b72235c462
commit
418e7c628d
|
@ -201,6 +201,33 @@ create a view, you must define a view in a YAML file and have a variable called
|
||||||
|
|
||||||
Views are processed differently than Jobs and therefore will not work within a `Project`_ or a `Job Template`_.
|
Views are processed differently than Jobs and therefore will not work within a `Project`_ or a `Job Template`_.
|
||||||
|
|
||||||
|
.. _view-template:
|
||||||
|
|
||||||
|
View Template
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Allow views to also be configured via templates similar to job-templates. This
|
||||||
|
is useful when you have multiple views defined that have similar configuration
|
||||||
|
except for a few variables. View Templates can be passed variables to fill in
|
||||||
|
sections automatically via a project configuration using the new 'views' key.
|
||||||
|
|
||||||
|
Minimal Example::
|
||||||
|
|
||||||
|
- view-template:
|
||||||
|
name: '{name}-template-{seq}'
|
||||||
|
description: 'testing view templates feature'
|
||||||
|
view-type: list
|
||||||
|
regex: 'test-view-.*'
|
||||||
|
|
||||||
|
- project:
|
||||||
|
name: 'test-view'
|
||||||
|
views:
|
||||||
|
- '{name}-template-{seq}'
|
||||||
|
seq:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
|
||||||
.. _macro:
|
.. _macro:
|
||||||
|
|
||||||
Macro
|
Macro
|
||||||
|
|
|
@ -316,6 +316,69 @@ class YamlParser(object):
|
||||||
raise JenkinsJobsException("Failed to find suitable "
|
raise JenkinsJobsException("Failed to find suitable "
|
||||||
"template named '{0}'"
|
"template named '{0}'"
|
||||||
.format(jobname))
|
.format(jobname))
|
||||||
|
|
||||||
|
for viewspec in project.get('views', []):
|
||||||
|
if isinstance(viewspec, dict):
|
||||||
|
# Singleton dict containing dict of view-specific params
|
||||||
|
viewname, viewparams = next(iter(viewspec.items()))
|
||||||
|
if not isinstance(viewparams, dict):
|
||||||
|
viewparams = {}
|
||||||
|
else:
|
||||||
|
viewname = viewspec
|
||||||
|
viewparams = {}
|
||||||
|
view = self._getView(viewname)
|
||||||
|
if view:
|
||||||
|
# Just naming an existing defined view
|
||||||
|
if viewname in seen:
|
||||||
|
self._handle_dups("Duplicate view '{0}' specified "
|
||||||
|
"for project '{1}'"
|
||||||
|
.format(viewname, project['name']))
|
||||||
|
seen.add(viewname)
|
||||||
|
continue
|
||||||
|
# see if it's a view group
|
||||||
|
group = self._getViewGroup(viewname)
|
||||||
|
if group:
|
||||||
|
for group_viewspec in group['views']:
|
||||||
|
if isinstance(group_viewspec, dict):
|
||||||
|
group_viewname, group_viewparams = \
|
||||||
|
next(iter(group_viewspec.items()))
|
||||||
|
if not isinstance(group_viewparams, dict):
|
||||||
|
group_viewparams = {}
|
||||||
|
else:
|
||||||
|
group_viewname = group_viewspec
|
||||||
|
group_viewparams = {}
|
||||||
|
view = self._getView(group_viewname)
|
||||||
|
if view:
|
||||||
|
if group_viewname in seen:
|
||||||
|
self._handle_dups(
|
||||||
|
"Duplicate view '{0}' specified for "
|
||||||
|
"project '{1}'".format(group_viewname,
|
||||||
|
project['name']))
|
||||||
|
seen.add(group_viewname)
|
||||||
|
continue
|
||||||
|
template = self._getViewTemplate(group_viewname)
|
||||||
|
# Allow a group to override parameters set by a project
|
||||||
|
d = type(project)(project)
|
||||||
|
d.update(viewparams)
|
||||||
|
d.update(group)
|
||||||
|
d.update(group_viewparams)
|
||||||
|
# Except name, since the group's name is not useful
|
||||||
|
d['name'] = project['name']
|
||||||
|
if template:
|
||||||
|
self._expandYamlForTemplateView(
|
||||||
|
d, template, jobs_glob)
|
||||||
|
continue
|
||||||
|
# see if it's a template
|
||||||
|
template = self._getViewTemplate(viewname)
|
||||||
|
if template:
|
||||||
|
d = type(project)(project)
|
||||||
|
d.update(viewparams)
|
||||||
|
self._expandYamlForTemplateView(d, template, jobs_glob)
|
||||||
|
else:
|
||||||
|
raise JenkinsJobsException("Failed to find suitable "
|
||||||
|
"template named '{0}'"
|
||||||
|
.format(viewname))
|
||||||
|
|
||||||
# check for duplicate generated jobs
|
# check for duplicate generated jobs
|
||||||
seen = set()
|
seen = set()
|
||||||
# walk the list in reverse so that last definition wins
|
# walk the list in reverse so that last definition wins
|
||||||
|
@ -325,6 +388,17 @@ class YamlParser(object):
|
||||||
"specified".format(job['name']))
|
"specified".format(job['name']))
|
||||||
self.jobs.remove(job)
|
self.jobs.remove(job)
|
||||||
seen.add(job['name'])
|
seen.add(job['name'])
|
||||||
|
|
||||||
|
# check for duplicate generated views
|
||||||
|
seen_views = set()
|
||||||
|
# walk the list in reverse so that last definition wins
|
||||||
|
for view in self.views[::-1]:
|
||||||
|
if view['name'] in seen_views:
|
||||||
|
self._handle_dups("Duplicate definitions for view '{0}' "
|
||||||
|
"specified".format(view['name']))
|
||||||
|
self.views.remove(view)
|
||||||
|
seen_views.add(view['name'])
|
||||||
|
|
||||||
return self.jobs, self.views
|
return self.jobs, self.views
|
||||||
|
|
||||||
def _expandYamlForTemplateJob(self, project, template, jobs_glob=None):
|
def _expandYamlForTemplateJob(self, project, template, jobs_glob=None):
|
||||||
|
@ -411,3 +485,73 @@ class YamlParser(object):
|
||||||
# The \n\n is not hard coded, because they get stripped if the
|
# The \n\n is not hard coded, because they get stripped if the
|
||||||
# project does not otherwise have a description.
|
# project does not otherwise have a description.
|
||||||
return "\n\n" + MAGIC_MANAGE_STRING
|
return "\n\n" + MAGIC_MANAGE_STRING
|
||||||
|
|
||||||
|
# Views related
|
||||||
|
def _getView(self, name):
|
||||||
|
view = self.data.get('view', {}).get(name, None)
|
||||||
|
if not view:
|
||||||
|
return view
|
||||||
|
return self._applyDefaults(view)
|
||||||
|
|
||||||
|
def _getViewGroup(self, name):
|
||||||
|
return self.data.get('view-group', {}).get(name, None)
|
||||||
|
|
||||||
|
def _getViewTemplate(self, name):
|
||||||
|
print(name)
|
||||||
|
view = self.data.get('view-template', {}).get(name, None)
|
||||||
|
if not view:
|
||||||
|
return view
|
||||||
|
return self._applyDefaults(view)
|
||||||
|
|
||||||
|
def _expandYamlForTemplateView(self, project, template, views_glob=None):
|
||||||
|
dimensions = []
|
||||||
|
template_name = template['name']
|
||||||
|
# reject keys that are not useful during yaml expansion
|
||||||
|
for k in ['views']:
|
||||||
|
project.pop(k)
|
||||||
|
excludes = project.pop('exclude', [])
|
||||||
|
for (k, v) in project.items():
|
||||||
|
tmpk = '{{{0}}}'.format(k)
|
||||||
|
if tmpk not in template_name:
|
||||||
|
continue
|
||||||
|
if type(v) == list:
|
||||||
|
dimensions.append(zip([k] * len(v), v))
|
||||||
|
# XXX somewhat hackish to ensure we actually have a single
|
||||||
|
# pass through the loop
|
||||||
|
if len(dimensions) == 0:
|
||||||
|
dimensions = [(("", ""),)]
|
||||||
|
|
||||||
|
for values in itertools.product(*dimensions):
|
||||||
|
params = copy.deepcopy(project)
|
||||||
|
params = self._applyDefaults(params, template)
|
||||||
|
|
||||||
|
expanded_values = {}
|
||||||
|
for (k, v) in values:
|
||||||
|
if isinstance(v, dict):
|
||||||
|
inner_key = next(iter(v))
|
||||||
|
expanded_values[k] = inner_key
|
||||||
|
expanded_values.update(v[inner_key])
|
||||||
|
else:
|
||||||
|
expanded_values[k] = v
|
||||||
|
|
||||||
|
params.update(expanded_values)
|
||||||
|
params = deep_format(params, params)
|
||||||
|
if combination_matches(params, excludes):
|
||||||
|
logger.debug('Excluding combination %s', str(params))
|
||||||
|
continue
|
||||||
|
|
||||||
|
for key in template.keys():
|
||||||
|
if key not in params:
|
||||||
|
params[key] = template[key]
|
||||||
|
|
||||||
|
params['template-name'] = template_name
|
||||||
|
expanded = deep_format(
|
||||||
|
template, params,
|
||||||
|
self.jjb_config.yamlparser['allow_empty_variables'])
|
||||||
|
|
||||||
|
view_name = expanded.get('name')
|
||||||
|
if views_glob and not matches(view_name, views_glob):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._formatDescription(expanded)
|
||||||
|
self.views.append(expanded)
|
||||||
|
|
Loading…
Reference in New Issue