diff --git a/jenkins_jobs/errors.py b/jenkins_jobs/errors.py index 5ffbf2813..09258ceb2 100644 --- a/jenkins_jobs/errors.py +++ b/jenkins_jobs/errors.py @@ -65,6 +65,24 @@ class MissingAttributeError(ModuleError): super(MissingAttributeError, self).__init__(message) +class AttributeConflictError(ModuleError): + + def __init__( + self, attribute_name, attributes_in_conflict, module_name=None + ): + module = module_name or self.get_module_name() + message = ( + "Attribute '{0}' can not be used together with {1} in {2}".format( + attribute_name, + ', '.join( + "'{0}'".format(value) for value in attributes_in_conflict + ), module + ) + ) + + super(AttributeConflictError, self).__init__(message) + + class YAMLFormatError(JenkinsJobsException): pass diff --git a/jenkins_jobs/modules/properties.py b/jenkins_jobs/modules/properties.py index a2589670c..37e0be38e 100644 --- a/jenkins_jobs/modules/properties.py +++ b/jenkins_jobs/modules/properties.py @@ -38,6 +38,7 @@ import xml.etree.ElementTree as XML from jenkins_jobs.errors import InvalidAttributeError from jenkins_jobs.errors import JenkinsJobsException from jenkins_jobs.errors import MissingAttributeError +from jenkins_jobs.errors import AttributeConflictError import jenkins_jobs.modules.base import jenkins_jobs.modules.helpers as helpers @@ -946,6 +947,52 @@ def groovy_label(registry, xml_parent, data): XML.SubElement(entry, 'url').text = value +def lockable_resources(registry, xml_parent, data): + """yaml: lockable-resources + Requires the Jenkins :jenkins-wiki:`Lockable Resources Plugin + `. + + :arg str resources: List of required resources, space separated. + (required, mutual exclusive with label) + :arg str label: If you have created a pool of resources, i.e. a label, + you can take it into use here. The build will select the resource(s) + from the pool that includes all resources sharing the given label. + (required, mutual exclusive with resources) + :arg str var-name: Name for the Jenkins variable to store the reserved + resources in. Leave empty to disable. (default '') + :arg int number: Number of resources to request, empty value or 0 means + all. This is useful, if you have a pool of similar resources, + from which you want one or more to be reserved. (default 0) + + Example: + + .. literalinclude:: + /../../tests/properties/fixtures/lockable_resources_minimal.yaml + :language: yaml + + .. literalinclude:: + /../../tests/properties/fixtures/lockable_resources_label.yaml + :language: yaml + + .. literalinclude:: + /../../tests/properties/fixtures/lockable_resources_full.yaml + :language: yaml + """ + lockable_resources = XML.SubElement( + xml_parent, + 'org.jenkins.plugins.lockableresources.RequiredResourcesProperty') + if data.get('resources') and data.get('label'): + raise AttributeConflictError('resources', ('label',)) + mapping = [ + ('resources', 'resourceNames', ''), + ('var-name', 'resourceNamesVar', ''), + ('number', 'resourceNumber', 0), + ('label', 'labelName', ''), + ] + helpers.convert_mapping_to_xml( + lockable_resources, data, mapping, fail_required=True) + + class Properties(jenkins_jobs.modules.base.Base): sequence = 20 diff --git a/tests/properties/fixtures/lockable_resources_full.xml b/tests/properties/fixtures/lockable_resources_full.xml new file mode 100644 index 000000000..11760a981 --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_full.xml @@ -0,0 +1,11 @@ + + + + + the-resource + RESOURCE_NAME + 10 + + + + diff --git a/tests/properties/fixtures/lockable_resources_full.yaml b/tests/properties/fixtures/lockable_resources_full.yaml new file mode 100644 index 000000000..a49bb985d --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_full.yaml @@ -0,0 +1,6 @@ +--- +properties: + - lockable-resources: + resources: "the-resource" + var-name: "RESOURCE_NAME" + number: 10 diff --git a/tests/properties/fixtures/lockable_resources_label.xml b/tests/properties/fixtures/lockable_resources_label.xml new file mode 100644 index 000000000..903e7321c --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_label.xml @@ -0,0 +1,11 @@ + + + + + + + 0 + pool-1 + + + diff --git a/tests/properties/fixtures/lockable_resources_label.yaml b/tests/properties/fixtures/lockable_resources_label.yaml new file mode 100644 index 000000000..2880390e4 --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_label.yaml @@ -0,0 +1,4 @@ +--- +properties: + - lockable-resources: + label: "pool-1" diff --git a/tests/properties/fixtures/lockable_resources_minimal.xml b/tests/properties/fixtures/lockable_resources_minimal.xml new file mode 100644 index 000000000..df64ff58d --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_minimal.xml @@ -0,0 +1,11 @@ + + + + + the-resource + + 0 + + + + diff --git a/tests/properties/fixtures/lockable_resources_minimal.yaml b/tests/properties/fixtures/lockable_resources_minimal.yaml new file mode 100644 index 000000000..b238ed531 --- /dev/null +++ b/tests/properties/fixtures/lockable_resources_minimal.yaml @@ -0,0 +1,4 @@ +--- +properties: + - lockable-resources: + resources: "the-resource"