diff options
author | Matt Martz <matt@sivel.net> | 2020-09-08 08:52:27 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-08 08:52:27 -0500 |
commit | 61f6aa55b6366b99d3ad3ed0701fdf44159474c5 (patch) | |
tree | c44050af23321c3f6e77bf22868bb391feca7670 | |
parent | b615789fcc8d2ddd831ef04c89163300c3bc1a0b (diff) | |
download | ansible-61f6aa55b6366b99d3ad3ed0701fdf44159474c5.tar.gz |
Add semver support to the jinja2 version test (#71600)
-rw-r--r-- | changelogs/fragments/version-test-semver.yml | 2 | ||||
-rw-r--r-- | docs/docsite/rst/user_guide/playbooks_tests.rst | 8 | ||||
-rw-r--r-- | lib/ansible/plugins/test/core.py | 33 | ||||
-rw-r--r-- | test/integration/targets/test_core/tasks/main.yml | 22 |
4 files changed, 58 insertions, 7 deletions
diff --git a/changelogs/fragments/version-test-semver.yml b/changelogs/fragments/version-test-semver.yml new file mode 100644 index 0000000000..4526b6513c --- /dev/null +++ b/changelogs/fragments/version-test-semver.yml @@ -0,0 +1,2 @@ +minor_changes: +- version test - Add semantic version functionality diff --git a/docs/docsite/rst/user_guide/playbooks_tests.rst b/docs/docsite/rst/user_guide/playbooks_tests.rst index 0a1aa8d91f..419305ee48 100644 --- a/docs/docsite/rst/user_guide/playbooks_tests.rst +++ b/docs/docsite/rst/user_guide/playbooks_tests.rst @@ -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: diff --git a/lib/ansible/plugins/test/core.py b/lib/ansible/plugins/test/core.py index 40733a1402..4b3995dd16 100644 --- a/lib/ansible/plugins/test/core.py +++ b/lib/ansible/plugins/test/core.py @@ -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): diff --git a/test/integration/targets/test_core/tasks/main.yml b/test/integration/targets/test_core/tasks/main.yml index 50c435815b..4f8441e17e 100644 --- a/test/integration/targets/test_core/tasks/main.yml +++ b/test/integration/targets/test_core/tasks/main.yml @@ -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: |