diff --git a/changelogs/fragments/truthiness-tests.yaml b/changelogs/fragments/truthiness-tests.yaml new file mode 100644 index 00000000000..303c7a9ed93 --- /dev/null +++ b/changelogs/fragments/truthiness-tests.yaml @@ -0,0 +1,2 @@ +minor_changes: +- tests - Add new ``truthy`` and ``falsy`` jinja2 tests to evaluate the truthiness or falsiness of a value diff --git a/docs/docsite/rst/user_guide/playbooks_tests.rst b/docs/docsite/rst/user_guide/playbooks_tests.rst index 1dd8bdd6cf1..986325823ce 100644 --- a/docs/docsite/rst/user_guide/playbooks_tests.rst +++ b/docs/docsite/rst/user_guide/playbooks_tests.rst @@ -61,6 +61,46 @@ To match strings against a substring or a regular expression, use the "match", " 'match' requires zero or more characters at the beginning of the string, while 'search' only requires matching a subset of the string. By default, 'regex' works like `search`, but `regex` can be configured to perform other tests as well. +.. _testing_truthiness: + +Testing Truthiness +`````````````````` + +.. versionadded:: 2.10 + +As of Ansible 2.10, you can now perform Python like truthy and falsy checks. + +.. code-block:: yaml + + - debug: + msg: "Truthy" + when: value is truthy + vars: + value: "some string" + + - debug: + msg: "Falsy" + when: value is falsy + vars: + value: "" + +Additionally, the ``truthy`` and ``falsy`` tests accept an optional parameter called ``convert_bool`` that will attempt +to convert boolean indicators to actual booleans. + +.. code-block:: yaml + + - debug: + msg: "Truthy" + when: value is truthy(convert_bool=True) + vars: + value: "yes" + + - debug: + msg: "Falsy" + when: value is falsy(convert_bool=True) + vars: + value: "off" + .. _testing_versions: Version Comparison diff --git a/lib/ansible/plugins/test/core.py b/lib/ansible/plugins/test/core.py index 66aff2a14bf..f88a5d931b6 100644 --- a/lib/ansible/plugins/test/core.py +++ b/lib/ansible/plugins/test/core.py @@ -26,6 +26,7 @@ from distutils.version import LooseVersion, StrictVersion from ansible import errors from ansible.module_utils._text import 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 display = Display() @@ -165,6 +166,34 @@ def version_compare(value, version, operator='eq', strict=False): raise errors.AnsibleFilterError('Version comparison: %s' % e) +def truthy(value, convert_bool=False): + """Evaluate as value for truthiness using python ``bool`` + + Optionally, attempt to do a conversion to bool from boolean like values + such as ``"false"``, ``"true"``, ``"yes"``, ``"no"``, ``"on"``, ``"off"``, etc. + + .. versionadded:: 2.10 + """ + if convert_bool: + try: + value = boolean(value) + except TypeError: + pass + + return bool(value) + + +def falsy(value, convert_bool=False): + """Evaluate as value for falsiness using python ``bool`` + + Optionally, attempt to do a conversion to bool from boolean like values + such as ``"false"``, ``"true"``, ``"yes"``, ``"no"``, ``"on"``, ``"off"``, etc. + + .. versionadded:: 2.10 + """ + return not truthy(value, convert_bool=convert_bool) + + class TestModule(object): ''' Ansible core jinja2 tests ''' @@ -203,4 +232,8 @@ class TestModule(object): # lists 'any': any, 'all': all, + + # truthiness + 'truthy': truthy, + 'falsy': falsy, } diff --git a/test/integration/targets/tests/aliases b/test/integration/targets/tests/aliases new file mode 100644 index 00000000000..69e3eebcfc3 --- /dev/null +++ b/test/integration/targets/tests/aliases @@ -0,0 +1,2 @@ +shippable/posix/group2 +skip/python2.6 # tests are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/tests/tasks/main.yml b/test/integration/targets/tests/tasks/main.yml new file mode 100644 index 00000000000..739675066ce --- /dev/null +++ b/test/integration/targets/tests/tasks/main.yml @@ -0,0 +1,35 @@ +- name: Assert truthy tests work + assert: + that: + - '"string" is truthy' + - '"" is not truthy' + - True is truthy + - False is not truthy + - true is truthy + - false is not truthy + - 1 is truthy + - 0 is not truthy + - '[""] is truthy' + - '[] is not truthy' + - '"on" is truthy(convert_bool=True)' + - '"off" is not truthy(convert_bool=True)' + - '{} is not truthy' + - '{"key": "value"} is truthy' + +- name: Assert falsy tests work + assert: + that: + - '"string" is not falsy' + - '"" is falsy' + - True is not falsy + - False is falsy + - true is not falsy + - false is falsy + - 1 is not falsy + - 0 is falsy + - '[""] is not falsy' + - '[] is falsy' + - '"on" is not falsy(convert_bool=True)' + - '"off" is falsy(convert_bool=True)' + - '{} is falsy' + - '{"key": "value"} is not falsy'