Add semver support to the jinja2 version test (#71600)
This commit is contained in:
parent
b615789fcc
commit
61f6aa55b6
4 changed files with 58 additions and 7 deletions
2
changelogs/fragments/version-test-semver.yml
Normal file
2
changelogs/fragments/version-test-semver.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- version test - Add semantic version functionality
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue