Support default string values for variables

Provide syntax support for specifying default values to be substituted
for variables during deep_format when no other replacement is provided.

Allows for individual variables to have a default or be optionally blank
should nothing be placed after the custom specifier.

Change-Id: Ib97a33a2bbca123791d4ca6ef5248ed200992565
This commit is contained in:
Darragh Bailey 2015-04-17 17:11:38 +01:00 committed by Darragh Bailey
parent e47f9629bc
commit 146d285eb9
4 changed files with 112 additions and 18 deletions

View File

@ -72,7 +72,9 @@ back to its template.
Sometimes it is useful to have the same job name format used even
where the template contents may vary. `Ids` provide a mechanism to
support such use cases.
support such use cases in addition to simplifying referencing
templates when the name contains the more complex substitution with
default values.
Default Values for Template Variables
@ -333,9 +335,9 @@ to reference it instead of the name. This has two primary functions:
still using multiple templates to handle subtle variables in job
requirements.
* Provides a simpler name for a `job-template` where you have multiple
variables in the name and don't wish to have to include this information
in every use. This also allows changing the template output name without
impacting references.
variables including default values in the name and don't wish to have
to include this information in every use. This also makes changing
the template output name without impacting references.
Example:

View File

@ -34,20 +34,12 @@ def deep_format(obj, paramdict, allow_empty=False):
# example, is problematic).
if hasattr(obj, 'format'):
try:
result = re.match('^{obj:(?P<key>\w+)}$', obj)
except TypeError:
ret = obj.format(**paramdict)
else:
try:
if result is not None:
ret = paramdict[result.group("key")]
else:
ret = CustomFormatter(allow_empty).format(obj, **paramdict)
except KeyError as exc:
missing_key = exc.args[0]
desc = "%s parameter missing to format %s\nGiven:\n%s" % (
missing_key, obj, pformat(paramdict))
raise JenkinsJobsException(desc)
ret = CustomFormatter(allow_empty).format(obj, **paramdict)
except KeyError as exc:
missing_key = exc.args[0]
desc = "%s parameter missing to format %s\nGiven:\n%s" % (
missing_key, obj, pformat(paramdict))
raise JenkinsJobsException(desc)
elif isinstance(obj, list):
ret = type(obj)()
for item in obj:
@ -73,10 +65,43 @@ class CustomFormatter(Formatter):
Custom formatter to allow non-existing key references when formatting a
string
"""
_expr = '{({{)*(?:obj:)?(?P<key>\w+)(?:\|(?P<default>[\w\s]*))?}(}})*'
def __init__(self, allow_empty=False):
super(CustomFormatter, self).__init__()
self.allow_empty = allow_empty
def vformat(self, format_string, args, kwargs):
matcher = re.compile(self._expr)
# special case of returning the object if the entire string
# matches a single parameter
try:
result = re.match('^%s$' % self._expr, format_string)
except TypeError:
return format_string.format(**kwargs)
if result is not None:
try:
return kwargs[result.group("key")]
except KeyError:
pass
# handle multiple fields within string via a callback to re.sub()
def re_replace(match):
key = match.group("key")
default = match.group("default")
if default is not None:
if key not in kwargs:
return default
else:
return "{%s}" % key
return match.group(0)
format_string = matcher.sub(re_replace, format_string)
return Formatter.vformat(self, format_string, args, kwargs)
def get_value(self, key, args, kwargs):
try:
return Formatter.get_value(self, key, args, kwargs)

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<actions/>
<description>&lt;!-- Managed by Jenkins Job Builder --&gt;</description>
<keepDependencies>false</keepDependencies>
<disabled/>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<concurrentBuild>false</concurrentBuild>
<canRoam>true</canRoam>
<properties/>
<scm class="hudson.scm.NullSCM"/>
<builders>
<hudson.tasks.Shell>
<command>echo &quot;Variable: Goodbye World&quot;
echo &quot;Allow empty Variable: Goodbye World&quot;
echo &quot;show that we expand for num: 1&quot;
</command>
</hudson.tasks.Shell>
</builders>
<publishers/>
<buildWrappers/>
</project>
<?xml version="1.0" encoding="utf-8"?>
<project>
<actions/>
<description>&lt;!-- Managed by Jenkins Job Builder --&gt;</description>
<keepDependencies>false</keepDependencies>
<disabled/>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<concurrentBuild>false</concurrentBuild>
<canRoam>true</canRoam>
<properties/>
<scm class="hudson.scm.NullSCM"/>
<builders>
<hudson.tasks.Shell>
<command>echo &quot;Variable: Goodbye World&quot;
echo &quot;Allow empty Variable: Goodbye World&quot;
echo &quot;show that we expand for num: 2&quot;
</command>
</hudson.tasks.Shell>
</builders>
<publishers/>
<buildWrappers/>
</project>

View File

@ -0,0 +1,20 @@
- project:
name: test_template_variable_defaults
num:
- 1
- 2
jobs:
- 'template_variable_defaults':
test_var: Goodbye World
- job-template:
name: 'template_variable_defaults_{num}{type|_debug}'
id: template_variable_defaults
disabled: '{obj:disabled_var|}'
builders:
- shell: |
echo "Variable: {test_var|Hello World}"
echo "Allow empty Variable: {test_var|}"
echo "show that we expand for num: {num}"