Add semver support to the jinja2 version test (#71600)

This commit is contained in:
Matt Martz 2020-09-08 08:52:27 -05:00 committed by GitHub
parent b615789fcc
commit 61f6aa55b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 7 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- version test - Add semantic version functionality

View file

@ -153,6 +153,14 @@ This test also accepts a 3rd parameter, ``strict`` which defines if strict versi
{{ sample_version_var is version('1.0', operator='lt', strict=True) }}
As of Ansible 2.11 the ``version`` test accepts a ``version_type`` parameter which is mutually exclusive with ``strict``, and accepts the following values::
loose, strict, semver, semantic
Using ``version_type`` to compare a semantic version would be achieved like the following::
{{ sample_semver_var is version('2.0.0-rc.1+build.123', 'lt', version_type='semver') }}
When using ``version`` in a playbook or role, don't use ``{{ }}`` as described in the `FAQ <https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#when-should-i-use-also-how-to-interpolate-variables-or-dynamic-variable-names>`_::
vars:

View file

@ -24,10 +24,11 @@ import operator as py_operator
from distutils.version import LooseVersion, StrictVersion
from ansible import errors
from ansible.module_utils._text import to_text
from ansible.module_utils._text import to_native, to_text
from ansible.module_utils.common._collections_compat import MutableMapping, MutableSequence
from ansible.module_utils.parsing.convert_bool import boolean
from ansible.utils.display import Display
from ansible.utils.version import SemanticVersion
display = Display()
@ -146,7 +147,7 @@ def search(value, pattern='', ignorecase=False, multiline=False):
return regex(value, pattern, ignorecase, multiline, 'search')
def version_compare(value, version, operator='eq', strict=False):
def version_compare(value, version, operator='eq', strict=None, version_type=None):
''' Perform a version comparison on a value '''
op_map = {
'==': 'eq', '=': 'eq', 'eq': 'eq',
@ -157,21 +158,39 @@ def version_compare(value, version, operator='eq', strict=False):
'!=': 'ne', '<>': 'ne', 'ne': 'ne'
}
type_map = {
'loose': LooseVersion,
'strict': StrictVersion,
'semver': SemanticVersion,
'semantic': SemanticVersion,
}
if strict is not None and version_type is not None:
raise errors.AnsibleFilterError("Cannot specify both 'strict' and 'version_type'")
Version = LooseVersion
if strict:
Version = StrictVersion
else:
Version = LooseVersion
elif version_type:
try:
Version = type_map[version_type]
except KeyError:
raise errors.AnsibleFilterError(
"Invalid version type (%s). Must be one of %s" % (version_type, ', '.join(map(repr, type_map)))
)
if operator in op_map:
operator = op_map[operator]
else:
raise errors.AnsibleFilterError('Invalid operator type')
raise errors.AnsibleFilterError(
'Invalid operator type (%s). Must be one of %s' % (operator, ', '.join(map(repr, op_map)))
)
try:
method = getattr(py_operator, operator)
return method(Version(str(value)), Version(str(version)))
return method(Version(to_text(value)), Version(to_text(version)))
except Exception as e:
raise errors.AnsibleFilterError('Version comparison: %s' % e)
raise errors.AnsibleFilterError('Version comparison failed: %s' % to_native(e))
def truthy(value, convert_bool=False):

View file

@ -217,6 +217,24 @@
ignore_errors: yes
register: version_bad_value
- name: Try version with both strict and version_type
debug:
msg: "{{ '1.0' is version('1.0', strict=False, version_type='loose') }}"
ignore_errors: yes
register: version_strict_version_type
- name: Try version with bad version_type
debug:
msg: "{{ '1.0' is version('1.0', version_type='boom') }}"
ignore_errors: yes
register: version_bad_version_type
- name: Try version with bad semver
debug:
msg: "{{ 'nope' is version('nopenope', version_type='semver') }}"
ignore_errors: yes
register: version_bad_semver
- name: Assert version tests work
assert:
that:
@ -234,8 +252,12 @@
- "'2.0' is version('1.0', '>', true)"
- "'1.0' is version('1.0', '<=', true)"
- "'1.0' is version('1.0', '>=', true)"
- "'1.2.3' is version('2.0.0', 'lt', version_type='semver')"
- version_bad_operator is failed
- version_bad_value is failed
- version_strict_version_type is failed
- version_bad_version_type is failed
- version_bad_semver is failed
- name: Assert any tests work
assert: