diff --git a/changelogs/fragments/71735-deprecation-tagging.yml b/changelogs/fragments/71735-deprecation-tagging.yml new file mode 100644 index 00000000000..470180799b1 --- /dev/null +++ b/changelogs/fragments/71735-deprecation-tagging.yml @@ -0,0 +1,2 @@ +bugfixes: +- "ansible-doc - plugin option deprecations now also get ``collection_name`` added (https://github.com/ansible/ansible/pull/71735)." diff --git a/lib/ansible/utils/plugin_docs.py b/lib/ansible/utils/plugin_docs.py index 83c670cc4d3..6522f76e95e 100644 --- a/lib/ansible/utils/plugin_docs.py +++ b/lib/ansible/utils/plugin_docs.py @@ -42,14 +42,15 @@ def merge_fragment(target, source): def _process_versions_and_dates(fragment, is_module, return_docs, callback): def process_deprecation(deprecation, top_level=False): + collection_name = 'removed_from_collection' if top_level else 'collection_name' if not isinstance(deprecation, MutableMapping): return if (is_module or top_level) and 'removed_in' in deprecation: # used in module deprecations - callback(deprecation, 'removed_in', 'removed_from_collection') + callback(deprecation, 'removed_in', collection_name) if 'removed_at_date' in deprecation: - callback(deprecation, 'removed_at_date', 'removed_from_collection') + callback(deprecation, 'removed_at_date', collection_name) if not (is_module or top_level) and 'version' in deprecation: # used in plugin option deprecations - callback(deprecation, 'version', 'removed_from_collection') + callback(deprecation, 'version', collection_name) def process_option_specifiers(specifiers): for specifier in specifiers: @@ -73,6 +74,8 @@ def _process_versions_and_dates(fragment, is_module, return_docs, callback): process_option_specifiers(option['ini']) if isinstance(option.get('vars'), list): process_option_specifiers(option['vars']) + if isinstance(option.get('deprecated'), MutableMapping): + process_deprecation(option['deprecated']) if isinstance(option.get('suboptions'), MutableMapping): process_options(option['suboptions']) diff --git a/test/units/utils/test_plugin_docs.py b/test/units/utils/test_plugin_docs.py new file mode 100644 index 00000000000..ff973b1e264 --- /dev/null +++ b/test/units/utils/test_plugin_docs.py @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- +# (c) 2020 Felix Fontein +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import copy + +import pytest + +from ansible.utils.plugin_docs import ( + add_collection_to_versions_and_dates, +) + + +ADD_TESTS = [ + ( + # Module options + True, + False, + { + 'author': 'x', + 'version_added': '1.0.0', + 'deprecated': { + 'removed_in': '2.0.0', + }, + 'options': { + 'test': { + 'description': '', + 'type': 'str', + 'version_added': '1.1.0', + 'deprecated': { + # should not be touched since this isn't a plugin + 'removed_in': '2.0.0', + }, + 'env': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'ini': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'vars': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'removed_at_date': '2020-01-01', + }, + }, + ], + }, + 'subtest': { + 'description': '', + 'type': 'dict', + 'deprecated': { + # should not be touched since this isn't a plugin + 'version': '2.0.0', + }, + 'suboptions': { + 'suboption': { + 'description': '', + 'type': 'int', + 'version_added': '1.2.0', + } + }, + } + }, + }, + { + 'author': 'x', + 'version_added': '1.0.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + 'removed_in': '2.0.0', + 'removed_from_collection': 'foo.bar', + }, + 'options': { + 'test': { + 'description': '', + 'type': 'str', + 'version_added': '1.1.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + # should not be touched since this isn't a plugin + 'removed_in': '2.0.0', + }, + 'env': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'ini': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'vars': [ + # should not be touched since this isn't a plugin + { + 'version_added': '1.3.0', + 'deprecated': { + 'removed_at_date': '2020-01-01', + }, + }, + ], + }, + 'subtest': { + 'description': '', + 'type': 'dict', + 'deprecated': { + # should not be touched since this isn't a plugin + 'version': '2.0.0', + }, + 'suboptions': { + 'suboption': { + 'description': '', + 'type': 'int', + 'version_added': '1.2.0', + 'version_added_collection': 'foo.bar', + } + }, + } + }, + }, + ), + ( + # Module options + True, + False, + { + 'author': 'x', + 'deprecated': { + 'removed_at_date': '2020-01-01', + }, + }, + { + 'author': 'x', + 'deprecated': { + 'removed_at_date': '2020-01-01', + 'removed_from_collection': 'foo.bar', + }, + }, + ), + ( + # Plugin options + False, + False, + { + 'author': 'x', + 'version_added': '1.0.0', + 'deprecated': { + 'removed_in': '2.0.0', + }, + 'options': { + 'test': { + 'description': '', + 'type': 'str', + 'version_added': '1.1.0', + 'deprecated': { + # should not be touched since this is the wrong name + 'removed_in': '2.0.0', + }, + 'env': [ + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'ini': [ + { + 'version_added': '1.3.0', + 'deprecated': { + 'version': '2.0.0', + }, + }, + ], + 'vars': [ + { + 'version_added': '1.3.0', + 'deprecated': { + 'removed_at_date': '2020-01-01', + }, + }, + ], + }, + 'subtest': { + 'description': '', + 'type': 'dict', + 'deprecated': { + 'version': '2.0.0', + }, + 'suboptions': { + 'suboption': { + 'description': '', + 'type': 'int', + 'version_added': '1.2.0', + } + }, + } + }, + }, + { + 'author': 'x', + 'version_added': '1.0.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + 'removed_in': '2.0.0', + 'removed_from_collection': 'foo.bar', + }, + 'options': { + 'test': { + 'description': '', + 'type': 'str', + 'version_added': '1.1.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + # should not be touched since this is the wrong name + 'removed_in': '2.0.0', + }, + 'env': [ + { + 'version_added': '1.3.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + 'version': '2.0.0', + 'collection_name': 'foo.bar', + }, + }, + ], + 'ini': [ + { + 'version_added': '1.3.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + 'version': '2.0.0', + 'collection_name': 'foo.bar', + }, + }, + ], + 'vars': [ + { + 'version_added': '1.3.0', + 'version_added_collection': 'foo.bar', + 'deprecated': { + 'removed_at_date': '2020-01-01', + 'collection_name': 'foo.bar', + }, + }, + ], + }, + 'subtest': { + 'description': '', + 'type': 'dict', + 'deprecated': { + 'version': '2.0.0', + 'collection_name': 'foo.bar', + }, + 'suboptions': { + 'suboption': { + 'description': '', + 'type': 'int', + 'version_added': '1.2.0', + 'version_added_collection': 'foo.bar', + } + }, + } + }, + }, + ), + ( + # Return values + True, # this value is is ignored + True, + { + 'rv1': { + 'version_added': '1.0.0', + 'type': 'dict', + 'contains': { + 'srv1': { + 'version_added': '1.1.0', + }, + 'srv2': { + }, + } + }, + }, + { + 'rv1': { + 'version_added': '1.0.0', + 'version_added_collection': 'foo.bar', + 'type': 'dict', + 'contains': { + 'srv1': { + 'version_added': '1.1.0', + 'version_added_collection': 'foo.bar', + }, + 'srv2': { + }, + } + }, + }, + ), +] + + +@pytest.mark.parametrize('is_module,return_docs,fragment,expected_fragment', ADD_TESTS) +def test_add(is_module, return_docs, fragment, expected_fragment): + fragment_copy = copy.deepcopy(fragment) + add_collection_to_versions_and_dates(fragment_copy, 'foo.bar', is_module, return_docs) + assert fragment_copy == expected_fragment