15
15
# Base class for a jenkins_jobs module
17
import xml.etree.ElementTree as XML
20
def add_nonblank_xml_subelement(parent, tag, value):
22
Adds an XML SubElement with the name tag to parent if value is a non-empty
25
if value is not None and value != '':
26
XML.SubElement(parent, tag).text = value
21
29
class Base(object):
32
40
#: ordered XML output.
43
#: The component type for components of this module. This will be
44
#: used to look for macros (they are defined singularly, and should
46
#: Set both component_type and component_list_type to None if module
47
#: doesn't have components.
50
#: The component list type will be used to look up possible
51
#: implementations of the component type via entry points (entry
52
#: points provide a list of components, so it should be plural).
53
#: Set both component_type and component_list_type to None if module
54
#: doesn't have components.
55
component_list_type = None
35
57
def __init__(self, registry):
36
58
self.registry = registry
64
def _dispatch(self, component_type, component_list_type,
66
component, template_data={}):
67
"""This is a private helper method that you can call from your
68
implementation of gen_xml. It allows your module to define a
69
type of component, and benefit from extensibility via Python
70
entry points and Jenkins Job Builder :ref:`Macros <macro>`.
72
:arg string component_type: the name of the component
74
:arg string component_list_type: the plural name of the component
75
type (e.g., `builders`)
76
:arg YAMLParser parser: the global YMAL Parser
77
:arg Element xml_parent: the parent XML element
78
:arg dict template_data: values that should be interpolated into
79
the component definition
81
The value of `component_list_type` will be used to look up
82
possible implementations of the component type via entry
83
points (entry points provide a list of components, so it
84
should be plural) while `component_type` will be used to look
85
for macros (they are defined singularly, and should not be
88
See the Publishers module for a simple example of how to use
92
if isinstance(component, dict):
93
# The component is a sigleton dictionary of name: dict(args)
94
name, component_data = component.items()[0]
96
# Template data contains values that should be interpolated
97
# into the component definition
98
s = yaml.dump(component_data, default_flow_style=False)
99
s = s.format(**template_data)
100
component_data = yaml.load(s)
102
# The component is a simple string name, eg "run-tests"
106
# Look for a component function defined in an entry point
107
for ep in pkg_resources.iter_entry_points(
108
group='jenkins_jobs.{0}'.format(component_list_type), name=name):
110
func(parser, xml_parent, component_data)
112
# Otherwise, see if it's defined as a macro
113
component = parser.data.get(component_type, {}).get(name)
115
for b in component[component_list_type]:
116
# Pass component_data in as template data to this function
117
# so that if the macro is invoked with arguments,
118
# the arguments are interpolated into the real defn.
119
self._dispatch(component_type, component_list_type,
120
parser, xml_parent, b, component_data)