summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFelix Fontein <felix@fontein.de>2020-06-10 00:21:19 +0200
committerGitHub <noreply@github.com>2020-06-09 15:21:19 -0700
commita862ff2d4324f871565ef5b749c6a96ad0ad767e (patch)
tree2e34f490a9c5f5c9da26e26defb65d33cd2143e9 /lib
parent7bff3d312f21ea1ccb3bc4a1abdb95a0369361f8 (diff)
downloadansible-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')
-rw-r--r--lib/ansible/cli/__init__.py6
-rw-r--r--lib/ansible/cli/doc.py16
-rw-r--r--lib/ansible/executor/task_executor.py2
-rw-r--r--lib/ansible/module_utils/basic.py13
-rw-r--r--lib/ansible/module_utils/common/parameters.py6
-rw-r--r--lib/ansible/module_utils/common/warnings.py6
-rw-r--r--lib/ansible/module_utils/csharp/Ansible.Basic.cs37
-rw-r--r--lib/ansible/module_utils/urls.py2
-rw-r--r--lib/ansible/modules/copy.py3
-rw-r--r--lib/ansible/modules/cron.py4
-rw-r--r--lib/ansible/modules/get_url.py6
-rw-r--r--lib/ansible/modules/systemd.py2
-rw-r--r--lib/ansible/modules/uri.py3
-rw-r--r--lib/ansible/playbook/__init__.py6
-rw-r--r--lib/ansible/playbook/conditional.py3
-rw-r--r--lib/ansible/playbook/helpers.py11
-rw-r--r--lib/ansible/playbook/play_context.py2
-rw-r--r--lib/ansible/playbook/task.py6
-rw-r--r--lib/ansible/plugins/action/__init__.py2
-rw-r--r--lib/ansible/plugins/action/async_status.py2
-rw-r--r--lib/ansible/plugins/cache/__init__.py5
-rw-r--r--lib/ansible/plugins/callback/__init__.py3
-rw-r--r--lib/ansible/plugins/connection/__init__.py8
-rw-r--r--lib/ansible/plugins/inventory/__init__.py8
-rw-r--r--lib/ansible/plugins/inventory/script.py2
-rw-r--r--lib/ansible/plugins/strategy/__init__.py4
-rw-r--r--lib/ansible/template/__init__.py2
-rw-r--r--lib/ansible/utils/display.py13
-rw-r--r--lib/ansible/utils/plugin_docs.py64
-rw-r--r--lib/ansible/utils/unsafe_proxy.py2
-rw-r--r--lib/ansible/vars/fact_cache.py2
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: