diff options
author | Felix Fontein <felix@fontein.de> | 2020-06-10 00:21:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-09 15:21:19 -0700 |
commit | a862ff2d4324f871565ef5b749c6a96ad0ad767e (patch) | |
tree | 2e34f490a9c5f5c9da26e26defb65d33cd2143e9 /lib | |
parent | 7bff3d312f21ea1ccb3bc4a1abdb95a0369361f8 (diff) | |
download | ansible-a862ff2d4324f871565ef5b749c6a96ad0ad767e.tar.gz |
Deprecation revisited (#69926)
* Allow to specify collection_name separately for deprecation.
* Use new functionality in Ansible.
* Use new functionality in tests.
* Update tagging/untagging functions.
* Update pylint deprecated sanity test.
* Update validate-modules. Missing are basic checks for version_added (validate semantic version format for collections).
* Improve version validation. Re-add version_added validation.
* Make sure collection names are added to return docs before schema validation.
* Extra checks to avoid crashes on bad data.
* Make C# module utils code work, and update/extend tests.
* Add changelog fragment.
* Stop extracting collection name from potentially tagged versions/dates.
* Simplify C# code.
* Update Windows modules docs.
* Forgot semicolons.
Diffstat (limited to 'lib')
31 files changed, 154 insertions, 97 deletions
diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 3f5dacc0dd..7e9cb44b98 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -104,7 +104,9 @@ class CLI(with_metaclass(ABCMeta, object)): alt = '' ver = deprecated[1].get('version') date = deprecated[1].get('date') - display.deprecated("%s option, %s %s" % (name, why, alt), version=ver, date=date) + collection_name = deprecated[1].get('collection_name') + display.deprecated("%s option, %s %s" % (name, why, alt), + version=ver, date=date, collection_name=collection_name) @staticmethod def split_vault_id(vault_id): @@ -353,7 +355,7 @@ class CLI(with_metaclass(ABCMeta, object)): verbosity_arg = next(iter([arg for arg in self.args if arg.startswith('-v')]), None) if verbosity_arg: display.deprecated("Setting verbosity before the arg sub command is deprecated, set the verbosity " - "after the sub command", "ansible.builtin:2.13") + "after the sub command", "2.13", collection_name='ansible.builtin') options.verbosity = verbosity_arg.count('v') return options diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index fbf0223bac..78e0b17db2 100644 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -30,7 +30,12 @@ from ansible.plugins.loader import action_loader, fragment_loader from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path from ansible.utils.display import Display -from ansible.utils.plugin_docs import BLACKLIST, untag_versions_and_dates, get_docstring, get_versioned_doclink +from ansible.utils.plugin_docs import ( + BLACKLIST, + remove_current_collection_from_versions_and_dates, + get_docstring, + get_versioned_doclink, +) display = Display() @@ -330,11 +335,18 @@ class DocCLI(CLI): raise ValueError('%s did not contain a DOCUMENTATION attribute' % plugin) doc['filename'] = filename - untag_versions_and_dates(doc, '%s:' % (collection_name, ), is_module=(plugin_type == 'module')) return doc, plainexamples, returndocs, metadata @staticmethod def format_plugin_doc(plugin, plugin_type, doc, plainexamples, returndocs, metadata): + collection_name = 'ansible.builtin' + if plugin.startswith('ansible_collections.'): + collection_name = '.'.join(plugin.split('.')[1:3]) + + # TODO: do we really want this? + # add_collection_to_versions_and_dates(doc, '(unknown)', is_module=(plugin_type == 'module')) + # remove_current_collection_from_versions_and_dates(doc, collection_name, is_module=(plugin_type == 'module')) + # assign from other sections doc['plainexamples'] = plainexamples doc['returndocs'] = returndocs diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index a2d4e217f9..22f758e9ce 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -487,7 +487,7 @@ class TaskExecutor: 'Invoking "%s" only once while using a loop via squash_actions is deprecated. ' 'Instead of using a loop to supply multiple items and specifying `%s: "%s"`, ' 'please use `%s: %s` and remove the loop' % (self._task.action, found, name, found, value_text), - version='ansible.builtin:2.11' + version='2.11', collection_name='ansible.builtin' ) for item in items: variables[loop_var] = item diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index e1569da4c9..3381848238 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -725,10 +725,10 @@ class AnsibleModule(object): warn(warning) self.log('[WARNING] %s' % warning) - def deprecate(self, msg, version=None, date=None): + def deprecate(self, msg, version=None, date=None, collection_name=None): if version is not None and date is not None: raise AssertionError("implementation error -- version and date must not both be set") - deprecate(msg, version=version, date=date) + deprecate(msg, version=version, date=date, collection_name=collection_name) # For compatibility, we accept that neither version nor date is set, # and treat that the same as if version would haven been set if date is not None: @@ -1414,7 +1414,8 @@ class AnsibleModule(object): for deprecation in deprecated_aliases: if deprecation['name'] in param.keys(): deprecate("Alias '%s' is deprecated. See the module docs for more information" % deprecation['name'], - version=deprecation.get('version'), date=deprecation.get('date')) + version=deprecation.get('version'), date=deprecation.get('date'), + collection_name=deprecation.get('collection_name')) return alias_results def _handle_no_log_values(self, spec=None, param=None): @@ -1430,7 +1431,8 @@ class AnsibleModule(object): "%s" % to_native(te), invocation={'module_args': 'HIDDEN DUE TO FAILURE'}) for message in list_deprecations(spec, param): - deprecate(message['msg'], version=message.get('version'), date=message.get('date')) + deprecate(message['msg'], version=message.get('version'), date=message.get('date'), + collection_name=message.get('collection_name')) def _check_arguments(self, spec=None, param=None, legal_inputs=None): self._syslog_facility = 'LOG_USER' @@ -2060,7 +2062,8 @@ class AnsibleModule(object): if isinstance(d, SEQUENCETYPE) and len(d) == 2: self.deprecate(d[0], version=d[1]) elif isinstance(d, Mapping): - self.deprecate(d['msg'], version=d.get('version', None), date=d.get('date', None)) + self.deprecate(d['msg'], version=d.get('version'), date=d.get('date'), + collection_name=d.get('date')) else: self.deprecate(d) # pylint: disable=ansible-deprecated-no-version else: diff --git a/lib/ansible/module_utils/common/parameters.py b/lib/ansible/module_utils/common/parameters.py index b66d956f52..4cf631e1e9 100644 --- a/lib/ansible/module_utils/common/parameters.py +++ b/lib/ansible/module_utils/common/parameters.py @@ -140,12 +140,14 @@ def list_deprecations(argument_spec, params, prefix=''): if arg_opts.get('removed_at_date') is not None: deprecations.append({ 'msg': "Param '%s' is deprecated. See the module docs for more information" % sub_prefix, - 'date': arg_opts.get('removed_at_date') + 'date': arg_opts.get('removed_at_date'), + 'collection_name': arg_opts.get('removed_from_collection'), }) elif arg_opts.get('removed_in_version') is not None: deprecations.append({ 'msg': "Param '%s' is deprecated. See the module docs for more information" % sub_prefix, - 'version': arg_opts.get('removed_in_version') + 'version': arg_opts.get('removed_in_version'), + 'collection_name': arg_opts.get('removed_from_collection'), }) # Check sub-argument spec sub_argument_spec = arg_opts.get('options') diff --git a/lib/ansible/module_utils/common/warnings.py b/lib/ansible/module_utils/common/warnings.py index 5c9971c93e..9423e6a429 100644 --- a/lib/ansible/module_utils/common/warnings.py +++ b/lib/ansible/module_utils/common/warnings.py @@ -18,14 +18,14 @@ def warn(warning): raise TypeError("warn requires a string not a %s" % type(warning)) -def deprecate(msg, version=None, date=None): +def deprecate(msg, version=None, date=None, collection_name=None): if isinstance(msg, string_types): # For compatibility, we accept that neither version nor date is set, # and treat that the same as if version would haven been set if date is not None: - _global_deprecations.append({'msg': msg, 'date': date}) + _global_deprecations.append({'msg': msg, 'date': date, 'collection_name': collection_name}) else: - _global_deprecations.append({'msg': msg, 'version': version}) + _global_deprecations.append({'msg': msg, 'version': version, 'collection_name': collection_name}) else: raise TypeError("deprecate requires a string not a %s" % type(msg)) diff --git a/lib/ansible/module_utils/csharp/Ansible.Basic.cs b/lib/ansible/module_utils/csharp/Ansible.Basic.cs index fb90c847a0..51a543bc13 100644 --- a/lib/ansible/module_utils/csharp/Ansible.Basic.cs +++ b/lib/ansible/module_utils/csharp/Ansible.Basic.cs @@ -86,6 +86,7 @@ namespace Ansible.Basic { "options", new List<object>() { typeof(Hashtable), typeof(Hashtable) } }, { "removed_in_version", new List<object>() { null, typeof(string) } }, { "removed_at_date", new List<object>() { null, typeof(DateTime) } }, + { "removed_from_collection", new List<object>() { null, typeof(string) } }, { "required", new List<object>() { false, typeof(bool) } }, { "required_by", new List<object>() { typeof(Hashtable), typeof(Hashtable) } }, { "required_if", new List<object>() { typeof(List<List<object>>), typeof(List<object>) } }, @@ -275,14 +276,26 @@ namespace Ansible.Basic public void Deprecate(string message, string version) { - deprecations.Add(new Dictionary<string, string>() { { "msg", message }, { "version", version } }); + Deprecate(message, version, null); + } + + public void Deprecate(string message, string version, string collectionName) + { + deprecations.Add(new Dictionary<string, string>() { + { "msg", message }, { "version", version }, { "collection_name", collectionName } }); LogEvent(String.Format("[DEPRECATION WARNING] {0} {1}", message, version)); } public void Deprecate(string message, DateTime date) { + Deprecate(message, date, null); + } + + public void Deprecate(string message, DateTime date, string collectionName) + { string isoDate = date.ToString("yyyy-MM-dd"); - deprecations.Add(new Dictionary<string, string>() { { "msg", message }, { "date", isoDate } }); + deprecations.Add(new Dictionary<string, string>() { + { "msg", message }, { "date", isoDate }, { "collection_name", collectionName } }); LogEvent(String.Format("[DEPRECATION WARNING] {0} {1}", message, isoDate)); } @@ -800,6 +813,11 @@ namespace Ansible.Basic string msg = "A deprecated_aliases date must be a DateTime object"; throw new ArgumentException(FormatOptionsContext(msg, " - ")); } + string collectionName = null; + if (depInfo.ContainsKey("collection_name")) + { + collectionName = (string)depInfo["collection_name"]; + } string aliasName = (string)depInfo["name"]; if (parameters.Contains(aliasName)) @@ -808,12 +826,12 @@ namespace Ansible.Basic if (depInfo.ContainsKey("version")) { string depVersion = (string)depInfo["version"]; - Deprecate(FormatOptionsContext(msg, " - "), depVersion); + Deprecate(FormatOptionsContext(msg, " - "), depVersion, collectionName); } if (depInfo.ContainsKey("date")) { DateTime depDate = (DateTime)depInfo["date"]; - Deprecate(FormatOptionsContext(msg, " - "), depDate); + Deprecate(FormatOptionsContext(msg, " - "), depDate, collectionName); } } } @@ -836,14 +854,21 @@ namespace Ansible.Basic if (!String.IsNullOrEmpty(noLogString)) noLogValues.Add(noLogString); } + string collectionName = null; + if (v.ContainsKey("removed_from_collection")) + { + collectionName = (string)v["removed_from_collection"]; + } object removedInVersion = v["removed_in_version"]; if (removedInVersion != null && parameters.Contains(k)) - Deprecate(String.Format("Param '{0}' is deprecated. See the module docs for more information", k), removedInVersion.ToString()); + Deprecate(String.Format("Param '{0}' is deprecated. See the module docs for more information", k), + removedInVersion.ToString(), collectionName); object removedAtDate = v["removed_at_date"]; if (removedAtDate != null && parameters.Contains(k)) - Deprecate(String.Format("Param '{0}' is deprecated. See the module docs for more information", k), (DateTime)removedAtDate); + Deprecate(String.Format("Param '{0}' is deprecated. See the module docs for more information", k), + (DateTime)removedAtDate, collectionName); } } diff --git a/lib/ansible/module_utils/urls.py b/lib/ansible/module_utils/urls.py index 16fd82d847..0fa6b7180c 100644 --- a/lib/ansible/module_utils/urls.py +++ b/lib/ansible/module_utils/urls.py @@ -1529,7 +1529,7 @@ def url_argument_spec(): return dict( url=dict(type='str'), force=dict(type='bool', default=False, aliases=['thirsty'], - deprecated_aliases=[dict(name='thirsty', version='ansible.builtin:2.13')]), + deprecated_aliases=[dict(name='thirsty', version='2.13', collection='ansible.builtin')]), http_agent=dict(type='str', default='ansible-httpget'), use_proxy=dict(type='bool', default=True), validate_certs=dict(type='bool', default=True), diff --git a/lib/ansible/modules/copy.py b/lib/ansible/modules/copy.py index b6cd8c681f..add01b056d 100644 --- a/lib/ansible/modules/copy.py +++ b/lib/ansible/modules/copy.py @@ -514,7 +514,8 @@ def main(): ) if module.params.get('thirsty'): - module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', version='ansible.builtin:2.13') + module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', + version='2.13', collection_name='ansible.builtin') src = module.params['src'] b_src = to_bytes(src, errors='surrogate_or_strict') diff --git a/lib/ansible/modules/cron.py b/lib/ansible/modules/cron.py index 6a59acb6f7..781a75facf 100644 --- a/lib/ansible/modules/cron.py +++ b/lib/ansible/modules/cron.py @@ -618,12 +618,12 @@ def main(): if not name: module.deprecate( msg="The 'name' parameter will be required in future releases.", - version='ansible.builtin:2.12' + version='2.12', collection_name='ansible.builtin' ) if reboot: module.deprecate( msg="The 'reboot' parameter will be removed in future releases. Use 'special_time' option instead.", - version='ansible.builtin:2.12' + version='2.12', collection_name='ansible.builtin' ) if module._diff: diff --git a/lib/ansible/modules/get_url.py b/lib/ansible/modules/get_url.py index 7a48067c3c..f9a0bb3212 100644 --- a/lib/ansible/modules/get_url.py +++ b/lib/ansible/modules/get_url.py @@ -446,10 +446,12 @@ def main(): ) if module.params.get('thirsty'): - module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', version='ansible.builtin:2.13') + module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', + version='2.13', collection_name='ansible.builtin') if module.params.get('sha256sum'): - module.deprecate('The parameter "sha256sum" has been deprecated and will be removed, use "checksum" instead', version='ansible.builtin:2.14') + module.deprecate('The parameter "sha256sum" has been deprecated and will be removed, use "checksum" instead', + version='2.14', collection_name='ansible.builtin') url = module.params['url'] dest = module.params['dest'] diff --git a/lib/ansible/modules/systemd.py b/lib/ansible/modules/systemd.py index 0f0263e199..b1eefae103 100644 --- a/lib/ansible/modules/systemd.py +++ b/lib/ansible/modules/systemd.py @@ -357,7 +357,7 @@ def main(): ''' Set CLI options depending on params ''' if module.params['user'] is not None: # handle user deprecation, mutually exclusive with scope - module.deprecate("The 'user' option is being replaced by 'scope'", version='ansible.builtin:2.11') + module.deprecate("The 'user' option is being replaced by 'scope'", version='2.11', collection_name='ansible.builtin') if module.params['user']: module.params['scope'] = 'user' else: diff --git a/lib/ansible/modules/uri.py b/lib/ansible/modules/uri.py index 3cc4273230..1db9b931f3 100644 --- a/lib/ansible/modules/uri.py +++ b/lib/ansible/modules/uri.py @@ -611,7 +611,8 @@ def main(): ) if module.params.get('thirsty'): - module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', version='ansible.builtin:2.13') + module.deprecate('The alias "thirsty" has been deprecated and will be removed, use "force" instead', + version='2.13', collection_name='ansible.builtin') url = module.params['url'] body = module.params['body'] diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index bf02c5c6b4..c7dab6b4d1 100644 --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -79,7 +79,8 @@ class Playbook: self._loader.set_basedir(cur_basedir) raise AnsibleParserError("A playbook must be a list of plays, got a %s instead" % type(ds), obj=ds) elif not ds: - display.deprecated("Empty plays will currently be skipped, in the future they will cause a syntax error", version='ansible.builtin:2.12') + display.deprecated("Empty plays will currently be skipped, in the future they will cause a syntax error", + version='2.12', collection_name='ansible.builtin') # Parse the playbook entries. For plays, we simply parse them # using the Play() object, and includes are parsed using the @@ -92,7 +93,8 @@ class Playbook: if any(action in entry for action in ('import_playbook', 'include')): if 'include' in entry: - display.deprecated("'include' for playbook includes. You should use 'import_playbook' instead", version="ansible.builtin:2.12") + display.deprecated("'include' for playbook includes. You should use 'import_playbook' instead", + version="2.12", collection_name='ansible.builtin') pb = PlaybookInclude.load(entry, basedir=self._basedir, variable_manager=variable_manager, loader=self._loader) if pb is not None: self._entries.extend(pb._entries) diff --git a/lib/ansible/playbook/conditional.py b/lib/ansible/playbook/conditional.py index f94f475de1..a969d1a752 100644 --- a/lib/ansible/playbook/conditional.py +++ b/lib/ansible/playbook/conditional.py @@ -134,7 +134,8 @@ class Conditional: conditional = templar.template(conditional, disable_lookups=disable_lookups) if bare_vars_warning and not isinstance(conditional, bool): display.deprecated('evaluating %r as a bare variable, this behaviour will go away and you might need to add |bool' - ' to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle' % original, "ansible.builtin:2.12") + ' to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle' % original, + version="2.12", collection_name='ansible.builtin') if not isinstance(conditional, text_type) or conditional == "": return conditional diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py index 6c4ccf9f9b..45ff837f83 100644 --- a/lib/ansible/playbook/helpers.py +++ b/lib/ansible/playbook/helpers.py @@ -156,7 +156,8 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h is_static = True elif t.static is not None: display.deprecated("The use of 'static' has been deprecated. " - "Use 'import_tasks' for static inclusion, or 'include_tasks' for dynamic inclusion", version='ansible.builtin:2.12') + "Use 'import_tasks' for static inclusion, or 'include_tasks' for dynamic inclusion", + version='2.12', collection_name='ansible.builtin') is_static = t.static else: is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \ @@ -257,7 +258,8 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h "later. In the future, this will be an error unless 'static: no' is used " "on the include task. If you do not want missing includes to be considered " "dynamic, use 'static: yes' on the include or set the global ansible.cfg " - "options to make all includes static for tasks and/or handlers" % include_file, version="ansible.builtin:2.12" + "options to make all includes static for tasks and/or handlers" % include_file, + version="2.12", collection_name='ansible.builtin' ) task_list.append(t) continue @@ -294,7 +296,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h suppress_extended_error=True, ) display.deprecated("You should not specify tags in the include parameters. All tags should be specified using the task-level option", - version="ansible.builtin:2.12") + version="2.12", collection_name='ansible.builtin') else: tags = ti_copy.tags[:] @@ -332,7 +334,8 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h elif ir.static is not None: display.deprecated("The use of 'static' for 'include_role' has been deprecated. " - "Use 'import_role' for static inclusion, or 'include_role' for dynamic inclusion", version='ansible.builtin:2.12') + "Use 'import_role' for static inclusion, or 'include_role' for dynamic inclusion", + version='2.12', collection_name='ansible.builtin') is_static = ir.static if is_static: diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index 48beb74600..b7efe9206b 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -342,7 +342,7 @@ class PlayContext(Base): """ helper function to create privilege escalation commands """ display.deprecated( "PlayContext.make_become_cmd should not be used, the calling code should be using become plugins instead", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) if not cmd or not self.become: diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 2475b61c7c..405316d3f8 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -163,7 +163,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch): raise AnsibleError("you must specify a value when using %s" % k, obj=ds) new_ds['loop_with'] = loop_name new_ds['loop'] = v - # display.deprecated("with_ type loops are being phased out, use the 'loop' keyword instead", version="ansible.builtin:2.10") + # display.deprecated("with_ type loops are being phased out, use the 'loop' keyword instead", + # version="2.10", collection_name='ansible.builtin') def preprocess_data(self, ds): ''' @@ -258,7 +259,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch): if action in ('include',) and k not in self._valid_attrs and k not in self.DEPRECATED_ATTRIBUTES: display.deprecated("Specifying include variables at the top-level of the task is deprecated." " Please see:\nhttps://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\n" - " for currently supported syntax regarding included files and variables", version="ansible.builtin:2.12") + " for currently supported syntax regarding included files and variables", + version="2.12", collection_name='ansible.builtin') new_ds['vars'][k] = v elif C.INVALID_TASK_ATTRIBUTE_FAILED or k in self._valid_attrs: new_ds[k] = v diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py index 614c61494d..fc5cf9021d 100644 --- a/lib/ansible/plugins/action/__init__.py +++ b/lib/ansible/plugins/action/__init__.py @@ -831,7 +831,7 @@ class ActionBase(with_metaclass(ABCMeta, object)): msg = "Setting the async dir from the environment keyword " \ "ANSIBLE_ASYNC_DIR is deprecated. Set the async_dir " \ "shell option instead" - self._display.deprecated(msg, "ansible.builtin:2.12") + self._display.deprecated(msg, "2.12", collection_name='ansible.builtin') else: # ANSIBLE_ASYNC_DIR is not set on the task, we get the value # from the shell option and temporarily add to the environment diff --git a/lib/ansible/plugins/action/async_status.py b/lib/ansible/plugins/action/async_status.py index 40ce563e41..e7273c305d 100644 --- a/lib/ansible/plugins/action/async_status.py +++ b/lib/ansible/plugins/action/async_status.py @@ -33,7 +33,7 @@ class ActionModule(ActionBase): msg = "Setting the async dir from the environment keyword " \ "ANSIBLE_ASYNC_DIR is deprecated. Set the async_dir " \ "shell option instead" - self._display.deprecated(msg, "ansible.builtin:2.12") + self._display.deprecated(msg, "2.12", collection_name='ansible.builtin') else: # inject the async directory based on the shell option into the # module args diff --git a/lib/ansible/plugins/cache/__init__.py b/lib/ansible/plugins/cache/__init__.py index 3b337835d0..a91b66afe7 100644 --- a/lib/ansible/plugins/cache/__init__.py +++ b/lib/ansible/plugins/cache/__init__.py @@ -50,7 +50,7 @@ class FactCache(RealFactCache): ' ansible.vars.fact_cache.FactCache. If you are looking for the class' ' to subclass for a cache plugin, you want' ' ansible.plugins.cache.BaseCacheModule or one of its subclasses.', - version='ansible.builtin:2.12') + version='2.12', collection_name='ansible.builtin') super(FactCache, self).__init__(*args, **kwargs) @@ -62,7 +62,8 @@ class BaseCacheModule(AnsiblePlugin): def __init__(self, *args, **kwargs): # Third party code is not using cache_loader to load plugin - fall back to previous behavior if not hasattr(self, '_load_name'): - display.deprecated('Rather than importing custom CacheModules directly, use ansible.plugins.loader.cache_loader', version='ansible.builtin:2.14') + display.deprecated('Rather than importing custom CacheModules directly, use ansible.plugins.loader.cache_loader', + version='2.14', collection_name='ansible.builtin') self._load_name = self.__module__.split('.')[-1] self._load_name = resource_from_fqcr(self.__module__) super(BaseCacheModule, self).__init__() diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py index 2ad7511ccc..442b1c87e8 100644 --- a/lib/ansible/plugins/callback/__init__.py +++ b/lib/ansible/plugins/callback/__init__.py @@ -242,7 +242,8 @@ class CallbackBase(AnsiblePlugin): def _get_item(self, result): ''' here for backwards compat, really should have always been named: _get_item_label''' cback = getattr(self, 'NAME', os.path.basename(__file__)) - self._display.deprecated("The %s callback plugin should be updated to use the _get_item_label method instead" % cback, version="ansible.builtin:2.11") + self._display.deprecated("The %s callback plugin should be updated to use the _get_item_label method instead" % cback, + version="2.11", collection_name='ansible.builtin') return self._get_item_label(result) def _process_items(self, result): diff --git a/lib/ansible/plugins/connection/__init__.py b/lib/ansible/plugins/connection/__init__.py index 230a6d777e..0b44295fc2 100644 --- a/lib/ansible/plugins/connection/__init__.py +++ b/lib/ansible/plugins/connection/__init__.py @@ -237,28 +237,28 @@ class ConnectionBase(AnsiblePlugin): def check_become_success(self, b_output): display.deprecated( "Connection.check_become_success is deprecated, calling code should be using become plugins instead", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) return self.become.check_success(b_output) def check_password_prompt(self, b_output): display.deprecated( "Connection.check_password_prompt is deprecated, calling code should be using become plugins instead", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) return self.become.check_password_prompt(b_output) def check_incorrect_password(self, b_output): display.deprecated( "Connection.check_incorrect_password is deprecated, calling code should be using become plugins instead", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) return self.become.check_incorrect_password(b_output) def check_missing_password(self, b_output): display.deprecated( "Connection.check_missing_password is deprecated, calling code should be using become plugins instead", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) return self.become.check_missing_password(b_output) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index b82dcdea95..d34c1e0a0f 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -291,19 +291,21 @@ class DeprecatedCache(object): display.deprecated('InventoryModule should utilize self._cache as a dict instead of self.cache. ' 'When expecting a KeyError, use self._cache[key] instead of using self.cache.get(key). ' 'self._cache is a dictionary and will return a default value instead of raising a KeyError ' - 'when the key does not exist', version='ansible.builtin:2.12') + 'when the key does not exist', version='2.12', collection_name='ansible.builtin') return self.real_cacheable._cache[key] def set(self, key, value): display.deprecated('InventoryModule should utilize self._cache as a dict instead of self.cache. ' 'To set the self._cache dictionary, use self._cache[key] = value instead of self.cache.set(key, value). ' 'To force update the underlying cache plugin with the contents of self._cache before parse() is complete, ' - 'call self.set_cache_plugin and it will use the self._cache dictionary to update the cache plugin', version='ansible.builtin:2.12') + 'call self.set_cache_plugin and it will use the self._cache dictionary to update the cache plugin', + version='2.12', collection_name='ansible.builtin') self.real_cacheable._cache[key] = value self.real_cacheable.set_cache_plugin() def __getattr__(self, name): - display.deprecated('InventoryModule should utilize self._cache instead of self.cache', version='ansible.builtin:2.12') + display.deprecated('InventoryModule should utilize self._cache instead of self.cache', + version='2.12', collection_name='ansible.builtin') return self.real_cacheable._cache.__getattribute__(name) diff --git a/lib/ansible/plugins/inventory/script.py b/lib/ansible/plugins/inventory/script.py index 05bfb0cfd8..b4094a569f 100644 --- a/lib/ansible/plugins/inventory/script.py +++ b/lib/ansible/plugins/inventory/script.py @@ -97,7 +97,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable): display.deprecated( msg="The 'cache' option is deprecated for the script inventory plugin. " "External scripts implement their own caching and this option has never been used", - version="ansible.builtin:2.12" + version="2.12", collection_name='ansible.builtin' ) # Support inventory scripts that are not prefixed with some diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 4b4e6c2a3e..c6e03ab35c 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -71,7 +71,7 @@ def SharedPluginLoaderObj(): '''This only exists for backwards compat, do not use. ''' display.deprecated('SharedPluginLoaderObj is deprecated, please directly use ansible.plugins.loader', - version='ansible.builtin:2.11') + version='2.11', collection_name='ansible.builtin') return plugin_loader @@ -918,7 +918,7 @@ class StrategyBase: "Mixing tag specify styles is prohibited for whole import hierarchy, not only for single import statement", obj=included_file._task._ds) display.deprecated("You should not specify tags in the include parameters. All tags should be specified using the task-level option", - version='ansible.builtin:2.12') + version='2.12', collection_name='ansible.builtin') included_file._task.tags = tags block_list = load_list_of_blocks( diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py index 33b31e598e..0881f8623b 100644 --- a/lib/ansible/template/__init__.py +++ b/lib/ansible/template/__init__.py @@ -661,7 +661,7 @@ class Templar: def set_available_variables(self, variables): display.deprecated( 'set_available_variables is being deprecated. Use "@available_variables.setter" instead.', - version='ansible.builtin:2.13' + version='2.13', collection_name='ansible.builtin' ) self.available_variables = variables diff --git a/lib/ansible/utils/display.py b/lib/ansible/utils/display.py index 1f5f2ee448..3943522af8 100644 --- a/lib/ansible/utils/display.py +++ b/lib/ansible/utils/display.py @@ -255,19 +255,6 @@ class Display(with_metaclass(Singleton, object)): if msg and msg[-1] not in ['!', '?', '.']: msg += '.' - # split composite collection info (if any) off date/version and use it if not otherwise spec'd - if date and isinstance(date, string_types): - parts = to_native(date.strip()).split(':', 1) - date = parts[-1] - if len(parts) == 2 and not collection_name: - collection_name = parts[0] - - if version and isinstance(version, string_types): - parts = to_native(version.strip()).split(':', 1) - version = parts[-1] - if len(parts) == 2 and not collection_name: - collection_name = parts[0] - if collection_name == 'ansible.builtin': collection_name = 'ansible-base' diff --git a/lib/ansible/utils/plugin_docs.py b/lib/ansible/utils/plugin_docs.py index b46e50de2c..2638847631 100644 --- a/lib/ansible/utils/plugin_docs.py +++ b/lib/ansible/utils/plugin_docs.py @@ -40,26 +40,32 @@ def merge_fragment(target, source): target[key] = value -def _process_versions_and_dates(fragment, is_module, callback): +def _process_versions_and_dates(fragment, is_module, return_docs, callback): def process_deprecation(deprecation): + if not isinstance(deprecation, MutableMapping): + return if is_module and 'removed_in' in deprecation: # used in module deprecations - callback(deprecation, 'removed_in') + callback(deprecation, 'removed_in', 'removed_from_collection') if 'removed_at_date' in deprecation: - callback(deprecation, 'removed_at_date') + callback(deprecation, 'removed_at_date', 'removed_from_collection') if not is_module and 'version' in deprecation: # used in plugin option deprecations - callback(deprecation, 'version') + callback(deprecation, 'version', 'removed_from_collection') def process_option_specifiers(specifiers): for specifier in specifiers: + if not isinstance(specifier, MutableMapping): + continue if 'version_added' in specifier: - callback(specifier, 'version_added') - if isinstance(specifier.get('deprecated'), dict): + callback(specifier, 'version_added', 'version_added_collection') + if isinstance(specifier.get('deprecated'), MutableMapping): process_deprecation(specifier['deprecated']) def process_options(options): for option in options.values(): + if not isinstance(option, MutableMapping): + continue if 'version_added' in option: - callback(option, 'version_added') + callback(option, 'version_added', 'version_added_collection') if not is_module: if isinstance(option.get('env'), list): process_option_specifiers(option['env']) @@ -67,40 +73,44 @@ def _process_versions_and_dates(fragment, is_module, callback): process_option_specifiers(option['ini']) if isinstance(option.get('vars'), list): process_option_specifiers(option['vars']) - if isinstance(option.get('suboptions'), dict): + if isinstance(option.get('suboptions'), MutableMapping): process_options(option['suboptions']) def process_return_values(return_values): for return_value in return_values.values(): + if not isinstance(return_value, MutableMapping): + continue if 'version_added' in return_value: - callback(return_value, 'version_added') - if isinstance(return_value.get('contains'), dict): + callback(return_value, 'version_added', 'version_added_collection') + if isinstance(return_value.get('contains'), MutableMapping): process_return_values(return_value['contains']) + if return_docs: + process_return_values(fragment) + return + if 'version_added' in fragment: - callback(fragment, 'version_added') - if isinstance(fragment.get('deprecated'), dict): + callback(fragment, 'version_added', 'version_added_collection') + if isinstance(fragment.get('deprecated'), MutableMapping): process_deprecation(fragment['deprecated']) - if isinstance(fragment.get('options'), dict): + if isinstance(fragment.get('options'), MutableMapping): process_options(fragment['options']) -def tag_versions_and_dates(fragment, prefix, is_module): - def tag(options, option): - options[option] = '%s%s' % (prefix, options[option]) +def add_collection_to_versions_and_dates(fragment, collection_name, is_module, return_docs=False): + def add(options, option, collection_name_field): + if collection_name_field not in options: + options[collection_name_field] = collection_name - _process_versions_and_dates(fragment, is_module, tag) + _process_versions_and_dates(fragment, is_module, return_docs, add) -def untag_versions_and_dates(fragment, prefix, is_module): - def untag(options, option): - v = options[option] - if isinstance(v, string_types): - v = to_native(v) - if v.startswith(prefix): - options[option] = v[len(prefix):] +def remove_current_collection_from_versions_and_dates(fragment, collection_name, is_module, return_docs=False): + def remove(options, option, collection_name_field): + if options.get(collection_name_field) == collection_name: + del options[collection_name_field] - _process_versions_and_dates(fragment, is_module, untag) + _process_versions_and_dates(fragment, is_module, return_docs, remove) def add_fragments(doc, filename, fragment_loader, is_module=False): @@ -147,7 +157,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False): real_fragment_name = getattr(fragment_class, '_load_name') if real_fragment_name.startswith('ansible_collections.'): real_collection_name = '.'.join(real_fragment_name.split('.')[1:3]) - tag_versions_and_dates(fragment, '%s:' % (real_collection_name, ), is_module=is_module) + add_collection_to_versions_and_dates(fragment, real_collection_name, is_module=is_module) if 'notes' in fragment: notes = fragment.pop('notes') @@ -195,7 +205,7 @@ def get_docstring(filename, fragment_loader, verbose=False, ignore_errors=False, if data.get('doc', False): # tag version_added if collection_name is not None: - tag_versions_and_dates(data['doc'], '%s:' % (collection_name, ), is_module=is_module) + add_collection_to_versions_and_dates(data['doc'], collection_name, is_module=is_module) # add fragments to documentation add_fragments(data['doc'], filename, fragment_loader=fragment_loader, is_module=is_module) diff --git a/lib/ansible/utils/unsafe_proxy.py b/lib/ansible/utils/unsafe_proxy.py index 936d881b10..8c5d22615e 100644 --- a/lib/ansible/utils/unsafe_proxy.py +++ b/lib/ansible/utils/unsafe_proxy.py @@ -83,7 +83,7 @@ class UnsafeProxy(object): from ansible.utils.display import Display Display().deprecated( 'UnsafeProxy is being deprecated. Use wrap_var or AnsibleUnsafeBytes/AnsibleUnsafeText directly instead', - version='ansible.builtin:2.13' + version='2.13', collection_name='ansible.builtin' ) # In our usage we should only receive unicode strings. # This conditional and conversion exists to sanity check the values diff --git a/lib/ansible/vars/fact_cache.py b/lib/ansible/vars/fact_cache.py index cab97d3840..a8e63bc586 100644 --- a/lib/ansible/vars/fact_cache.py +++ b/lib/ansible/vars/fact_cache.py @@ -99,7 +99,7 @@ class FactCache(MutableMapping): display.deprecated('Calling FactCache().update(key, value) is deprecated. Use' ' FactCache().first_order_merge(key, value) if you want the old' ' behaviour or use FactCache().update({key: value}) if you want' - ' dict-like behaviour.', version='ansible.builtin:2.12') + ' dict-like behaviour.', version='2.12', collection_name='ansible.builtin') return self.first_order_merge(*args) elif len(args) == 1: |