Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ansible-core for openSUSE:Factory 
checked in at 2023-11-07 21:27:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ansible-core (Old)
 and      /work/SRC/openSUSE:Factory/.ansible-core.new.17445 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ansible-core"

Tue Nov  7 21:27:42 2023 rev:20 rq:1123920 version:2.15.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/ansible-core/ansible-core.changes        
2023-10-10 21:01:51.501472468 +0200
+++ /work/SRC/openSUSE:Factory/.ansible-core.new.17445/ansible-core.changes     
2023-11-07 21:28:30.068247661 +0100
@@ -1,0 +2,24 @@
+Tue Nov  7 07:46:07 UTC 2023 - Johannes Kastl <[email protected]>
+
+- update to 2.15.6:
+  * Minor Changes
+    - ansible-test - Windows 2012 and 2012-R2 instances are now
+      requested from Azure instead of AWS.
+  * Bugfixes
+    - Fix run_once being incorrectly interpreted on handlers
+      (#81666)
+    - Plugin loader does not dedupe nor cache filter/test plugins
+      by file basename, but full path name.
+    - Properly template tags in parent blocks (#81053)
+    - Restoring the ability of filters/tests can have same file
+      base name but different tests/filters defined inside.
+    - import_role reverts to previous behavior of exporting vars at
+      compile time.
+    - ansible-galaxy - Provide a better error message when using a
+      requirements file with an invalid format - #81901
+    - ansible-inventory - index available_hosts for major
+      performance boost when dumping large inventories
+    - ansible-test - Fix parsing of cgroup entries which contain a
+      : in the path (#81977).
+
+-------------------------------------------------------------------
@@ -9 +33 @@
-  * - Security Fixes
+  * Security Fixes
@@ -13 +37 @@
-  * - Bugfixes
+  * Bugfixes

Old:
----
  ansible-core-2.15.5.tar.gz

New:
----
  ansible-core-2.15.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ansible-core.spec ++++++
--- /var/tmp/diff_new_pack.d5iyIN/_old  2023-11-07 21:28:30.764273292 +0100
+++ /var/tmp/diff_new_pack.d5iyIN/_new  2023-11-07 21:28:30.768273439 +0100
@@ -38,7 +38,7 @@
 %endif
 
 Name:           ansible-core
-Version:        2.15.5
+Version:        2.15.6
 Release:        0
 Summary:        Radically simple IT automation
 License:        GPL-3.0-or-later

++++++ ansible-core-2.15.5.tar.gz -> ansible-core-2.15.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/PKG-INFO 
new/ansible-core-2.15.6/PKG-INFO
--- old/ansible-core-2.15.5/PKG-INFO    2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/PKG-INFO    2023-11-06 18:56:48.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ansible-core
-Version: 2.15.5
+Version: 2.15.6
 Summary: Radically simple IT automation
 Home-page: https://ansible.com/
 Author: Ansible, Inc.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/bin/ansible-galaxy 
new/ansible-core-2.15.6/bin/ansible-galaxy
--- old/ansible-core-2.15.5/bin/ansible-galaxy  2023-10-09 17:51:22.000000000 
+0200
+++ new/ansible-core-2.15.6/bin/ansible-galaxy  2023-11-06 18:56:48.000000000 
+0100
@@ -805,7 +805,7 @@
             for role_req in file_requirements:
                 requirements['roles'] += parse_role_req(role_req)
 
-        else:
+        elif isinstance(file_requirements, dict):
             # Newer format with a collections and/or roles key
             extra_keys = 
set(file_requirements.keys()).difference(set(['roles', 'collections']))
             if extra_keys:
@@ -824,6 +824,9 @@
                 for collection_req in file_requirements.get('collections') or 
[]
             ]
 
+        else:
+            raise AnsibleError(f"Expecting requirements yaml to be a list or 
dictionary but got {type(file_requirements).__name__}")
+
         return requirements
 
     def _init_coll_req_dict(self, coll_req):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/bin/ansible-inventory 
new/ansible-core-2.15.6/bin/ansible-inventory
--- old/ansible-core-2.15.5/bin/ansible-inventory       2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/bin/ansible-inventory       2023-11-06 
18:56:48.000000000 +0100
@@ -325,7 +325,7 @@
             return results
 
         hosts = self.inventory.get_hosts(top.name)
-        results = format_group(top, [h.name for h in hosts])
+        results = format_group(top, frozenset(h.name for h in hosts))
 
         # populate meta
         results['_meta'] = {'hostvars': {}}
@@ -381,7 +381,7 @@
 
             return results
 
-        available_hosts = [h.name for h in self.inventory.get_hosts(top.name)]
+        available_hosts = frozenset(h.name for h in 
self.inventory.get_hosts(top.name))
         return format_group(top, available_hosts)
 
     def toml_inventory(self, top):
@@ -425,7 +425,7 @@
 
             return results
 
-        available_hosts = [h.name for h in self.inventory.get_hosts(top.name)]
+        available_hosts = frozenset(h.name for h in 
self.inventory.get_hosts(top.name))
         results = format_group(top, available_hosts)
 
         return results
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/changelogs/CHANGELOG-v2.15.rst 
new/ansible-core-2.15.6/changelogs/CHANGELOG-v2.15.rst
--- old/ansible-core-2.15.5/changelogs/CHANGELOG-v2.15.rst      2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/changelogs/CHANGELOG-v2.15.rst      2023-11-06 
18:56:48.000000000 +0100
@@ -5,6 +5,33 @@
 .. contents:: Topics
 
 
+v2.15.6
+=======
+
+Release Summary
+---------------
+
+| Release Date: 2023-11-06
+| `Porting Guide 
<https://docs.ansible.com/ansible-core/2.15/porting_guides/porting_guide_core_2.15.html>`__
+
+
+Minor Changes
+-------------
+
+- ansible-test - Windows 2012 and 2012-R2 instances are now requested from 
Azure instead of AWS.
+
+Bugfixes
+--------
+
+- Fix ``run_once`` being incorrectly interpreted on handlers 
(https://github.com/ansible/ansible/issues/81666)
+- Plugin loader does not dedupe nor cache filter/test plugins by file 
basename, but full path name.
+- Properly template tags in parent blocks 
(https://github.com/ansible/ansible/issues/81053)
+- Restoring the ability of filters/tests can have same file base name but 
different tests/filters defined inside.
+- ``import_role`` reverts to previous behavior of exporting vars at compile 
time.
+- ansible-galaxy - Provide a better error message when using a requirements 
file with an invalid format - https://github.com/ansible/ansible/issues/81901
+- ansible-inventory - index available_hosts for major performance boost when 
dumping large inventories
+- ansible-test - Fix parsing of cgroup entries which contain a ``:`` in the 
path (https://github.com/ansible/ansible/issues/81977).
+
 v2.15.5
 =======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/changelogs/changelog.yaml 
new/ansible-core-2.15.6/changelogs/changelog.yaml
--- old/ansible-core-2.15.5/changelogs/changelog.yaml   2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/changelogs/changelog.yaml   2023-11-06 
18:56:48.000000000 +0100
@@ -1180,3 +1180,51 @@
     - role-deduplication-condition.yml
     - winrm-send-input.yml
     release_date: '2023-10-03'
+  2.15.6:
+    changes:
+      release_summary: '| Release Date: 2023-11-06
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.15/porting_guides/porting_guide_core_2.15.html>`__
+
+        '
+    codename: Ten Years Gone
+    fragments:
+    - 2.15.6_summary.yaml
+    release_date: '2023-11-06'
+  2.15.6rc1:
+    changes:
+      bugfixes:
+      - Fix ``run_once`` being incorrectly interpreted on handlers 
(https://github.com/ansible/ansible/issues/81666)
+      - Plugin loader does not dedupe nor cache filter/test plugins by file 
basename,
+        but full path name.
+      - Properly template tags in parent blocks 
(https://github.com/ansible/ansible/issues/81053)
+      - Restoring the ability of filters/tests can have same file base name 
but different
+        tests/filters defined inside.
+      - '``import_role`` reverts to previous behavior of exporting vars at 
compile
+        time.'
+      - ansible-galaxy - Provide a better error message when using a 
requirements
+        file with an invalid format - 
https://github.com/ansible/ansible/issues/81901
+      - ansible-inventory - index available_hosts for major performance boost 
when
+        dumping large inventories
+      - ansible-test - Fix parsing of cgroup entries which contain a ``:`` in 
the
+        path (https://github.com/ansible/ansible/issues/81977).
+      minor_changes:
+      - ansible-test - Windows 2012 and 2012-R2 instances are now requested 
from Azure
+        instead of AWS.
+      release_summary: '| Release Date: 2023-10-30
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.15/porting_guides/porting_guide_core_2.15.html>`__
+
+        '
+    codename: Ten Years Gone
+    fragments:
+    - 2.15.6rc1_summary.yaml
+    - 81053-templated-tags-inheritance.yml
+    - 81666-handlers-run_once.yml
+    - 81901-galaxy-requirements-format.yml
+    - ansible-test-cgroup-split.yml
+    - ansible-test-windows-2012-and-2012-R2.yml
+    - import_role_goes_public.yml
+    - inv_available_hosts_to_frozenset.yml
+    - j2_load_fix.yml
+    release_date: '2023-10-30'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/cli/galaxy.py 
new/ansible-core-2.15.6/lib/ansible/cli/galaxy.py
--- old/ansible-core-2.15.5/lib/ansible/cli/galaxy.py   2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/cli/galaxy.py   2023-11-06 
18:56:48.000000000 +0100
@@ -805,7 +805,7 @@
             for role_req in file_requirements:
                 requirements['roles'] += parse_role_req(role_req)
 
-        else:
+        elif isinstance(file_requirements, dict):
             # Newer format with a collections and/or roles key
             extra_keys = 
set(file_requirements.keys()).difference(set(['roles', 'collections']))
             if extra_keys:
@@ -824,6 +824,9 @@
                 for collection_req in file_requirements.get('collections') or 
[]
             ]
 
+        else:
+            raise AnsibleError(f"Expecting requirements yaml to be a list or 
dictionary but got {type(file_requirements).__name__}")
+
         return requirements
 
     def _init_coll_req_dict(self, coll_req):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/cli/inventory.py 
new/ansible-core-2.15.6/lib/ansible/cli/inventory.py
--- old/ansible-core-2.15.5/lib/ansible/cli/inventory.py        2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/cli/inventory.py        2023-11-06 
18:56:48.000000000 +0100
@@ -325,7 +325,7 @@
             return results
 
         hosts = self.inventory.get_hosts(top.name)
-        results = format_group(top, [h.name for h in hosts])
+        results = format_group(top, frozenset(h.name for h in hosts))
 
         # populate meta
         results['_meta'] = {'hostvars': {}}
@@ -381,7 +381,7 @@
 
             return results
 
-        available_hosts = [h.name for h in self.inventory.get_hosts(top.name)]
+        available_hosts = frozenset(h.name for h in 
self.inventory.get_hosts(top.name))
         return format_group(top, available_hosts)
 
     def toml_inventory(self, top):
@@ -425,7 +425,7 @@
 
             return results
 
-        available_hosts = [h.name for h in self.inventory.get_hosts(top.name)]
+        available_hosts = frozenset(h.name for h in 
self.inventory.get_hosts(top.name))
         results = format_group(top, available_hosts)
 
         return results
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible/module_utils/ansible_release.py 
new/ansible-core-2.15.6/lib/ansible/module_utils/ansible_release.py
--- old/ansible-core-2.15.5/lib/ansible/module_utils/ansible_release.py 
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/module_utils/ansible_release.py 
2023-11-06 18:56:48.000000000 +0100
@@ -19,6 +19,6 @@
 from __future__ import (absolute_import, division, print_function)
 __metaclass__ = type
 
-__version__ = '2.15.5'
+__version__ = '2.15.6'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Ten Years Gone"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/playbook/handler.py 
new/ansible-core-2.15.6/lib/ansible/playbook/handler.py
--- old/ansible-core-2.15.5/lib/ansible/playbook/handler.py     2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/playbook/handler.py     2023-11-06 
18:56:48.000000000 +0100
@@ -53,6 +53,9 @@
     def remove_host(self, host):
         self.notified_hosts = [h for h in self.notified_hosts if h != host]
 
+    def clear_hosts(self):
+        self.notified_hosts = []
+
     def is_host_notified(self, host):
         return host in self.notified_hosts
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible/playbook/role_include.py 
new/ansible-core-2.15.6/lib/ansible/playbook/role_include.py
--- old/ansible-core-2.15.5/lib/ansible/playbook/role_include.py        
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/playbook/role_include.py        
2023-11-06 18:56:48.000000000 +0100
@@ -49,10 +49,10 @@
 
     # 
=================================================================================
     # ATTRIBUTES
+    public = NonInheritableFieldAttribute(isa='bool', default=None, 
private=False, always_post_validate=True)
 
     # private as this is a 'module options' vs a task property
     allow_duplicates = NonInheritableFieldAttribute(isa='bool', default=True, 
private=True, always_post_validate=True)
-    public = NonInheritableFieldAttribute(isa='bool', default=False, 
private=True, always_post_validate=True)
     rolespec_validate = NonInheritableFieldAttribute(isa='bool', default=True, 
private=True, always_post_validate=True)
 
     def __init__(self, block=None, role=None, task_include=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/playbook/taggable.py 
new/ansible-core-2.15.6/lib/ansible/playbook/taggable.py
--- old/ansible-core-2.15.5/lib/ansible/playbook/taggable.py    2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/playbook/taggable.py    2023-11-06 
18:56:48.000000000 +0100
@@ -23,6 +23,17 @@
 from ansible.module_utils.six import string_types
 from ansible.playbook.attribute import FieldAttribute
 from ansible.template import Templar
+from ansible.utils.sentinel import Sentinel
+
+
+def _flatten_tags(tags: list) -> list:
+    rv = set()
+    for tag in tags:
+        if isinstance(tag, list):
+            rv.update(tag)
+        else:
+            rv.add(tag)
+    return list(rv)
 
 
 class Taggable:
@@ -34,11 +45,7 @@
         if isinstance(ds, list):
             return ds
         elif isinstance(ds, string_types):
-            value = ds.split(',')
-            if isinstance(value, list):
-                return [x.strip() for x in value]
-            else:
-                return [ds]
+            return [x.strip() for x in ds.split(',')]
         else:
             raise AnsibleError('tags must be specified as a list', obj=ds)
 
@@ -47,16 +54,12 @@
 
         if self.tags:
             templar = Templar(loader=self._loader, variables=all_vars)
-            tags = templar.template(self.tags)
-
-            _temp_tags = set()
-            for tag in tags:
-                if isinstance(tag, list):
-                    _temp_tags.update(tag)
-                else:
-                    _temp_tags.add(tag)
-            tags = _temp_tags
-            self.tags = list(tags)
+            obj = self
+            while obj is not None:
+                if (_tags := getattr(obj, "_tags", Sentinel)) is not Sentinel:
+                    obj._tags = _flatten_tags(templar.template(_tags))
+                obj = obj._parent
+            tags = set(self.tags)
         else:
             # this makes isdisjoint work for untagged
             tags = self.untagged
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/plugins/loader.py 
new/ansible-core-2.15.6/lib/ansible/plugins/loader.py
--- old/ansible-core-2.15.5/lib/ansible/plugins/loader.py       2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/plugins/loader.py       2023-11-06 
18:56:48.000000000 +0100
@@ -986,23 +986,32 @@
 
         loaded_modules = set()
         for path in all_matches:
+
             name = os.path.splitext(path)[0]
             basename = os.path.basename(name)
+            is_j2 = isinstance(self, Jinja2Loader)
+
+            if is_j2:
+                ref_name = path
+            else:
+                ref_name = basename
 
-            if basename in _PLUGIN_FILTERS[self.package]:
+            if not is_j2 and basename in _PLUGIN_FILTERS[self.package]:
+                # j2 plugins get processed in own class, here they would just 
be container files
                 display.debug("'%s' skipped due to a defined plugin filter" % 
basename)
                 continue
 
             if basename == '__init__' or (basename == 'base' and self.package 
== 'ansible.plugins.cache'):
                 # cache has legacy 'base.py' file, which is wrapper for 
__init__.py
-                display.debug("'%s' skipped due to reserved name" % basename)
+                display.debug("'%s' skipped due to reserved name" % name)
                 continue
 
-            if dedupe and basename in loaded_modules:
-                display.debug("'%s' skipped as duplicate" % basename)
+            if dedupe and ref_name in loaded_modules:
+                # for j2 this is 'same file', other plugins it is basename
+                display.debug("'%s' skipped as duplicate" % ref_name)
                 continue
 
-            loaded_modules.add(basename)
+            loaded_modules.add(ref_name)
 
             if path_only:
                 yield path
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible/plugins/strategy/__init__.py 
new/ansible-core-2.15.6/lib/ansible/plugins/strategy/__init__.py
--- old/ansible-core-2.15.5/lib/ansible/plugins/strategy/__init__.py    
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/plugins/strategy/__init__.py    
2023-11-06 18:56:48.000000000 +0100
@@ -803,10 +803,6 @@
 
             ret_results.append(task_result)
 
-            if isinstance(original_task, Handler):
-                for handler in (h for b in iterator._play.handlers for h in 
b.block if h._uuid == original_task._uuid):
-                    handler.remove_host(original_host)
-
             if one_pass or max_passes is not None and (cur_pass + 1) >= 
max_passes:
                 break
 
@@ -1094,9 +1090,6 @@
             header = skip_reason if skipped else msg
             display.vv(f"META: {header}")
 
-        if isinstance(task, Handler):
-            task.remove_host(target_host)
-
         res = TaskResult(target_host, task, result)
         if skipped:
             self._tqm.send_callback('v2_runner_on_skipped', res)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible/plugins/strategy/free.py 
new/ansible-core-2.15.6/lib/ansible/plugins/strategy/free.py
--- old/ansible-core-2.15.5/lib/ansible/plugins/strategy/free.py        
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/plugins/strategy/free.py        
2023-11-06 18:56:48.000000000 +0100
@@ -146,6 +146,8 @@
                         # advance the host, mark the host blocked, and queue it
                         self._blocked_hosts[host_name] = True
                         iterator.set_state_for_host(host.name, state)
+                        if isinstance(task, Handler):
+                            task.remove_host(host)
 
                         try:
                             action = action_loader.get(task.action, 
class_only=True, collection_list=task.collections)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible/plugins/strategy/linear.py 
new/ansible-core-2.15.6/lib/ansible/plugins/strategy/linear.py
--- old/ansible-core-2.15.5/lib/ansible/plugins/strategy/linear.py      
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/plugins/strategy/linear.py      
2023-11-06 18:56:48.000000000 +0100
@@ -242,6 +242,12 @@
                         self._queue_task(host, task, task_vars, play_context)
                         del task_vars
 
+                    if isinstance(task, Handler):
+                        if run_once:
+                            task.clear_hosts()
+                        else:
+                            task.remove_host(host)
+
                     # if we're bypassing the host loop, break out now
                     if run_once:
                         break
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/release.py 
new/ansible-core-2.15.6/lib/ansible/release.py
--- old/ansible-core-2.15.5/lib/ansible/release.py      2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/release.py      2023-11-06 
18:56:48.000000000 +0100
@@ -19,6 +19,6 @@
 from __future__ import (absolute_import, division, print_function)
 __metaclass__ = type
 
-__version__ = '2.15.5'
+__version__ = '2.15.6'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Ten Years Gone"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/lib/ansible/vars/manager.py 
new/ansible-core-2.15.6/lib/ansible/vars/manager.py
--- old/ansible-core-2.15.5/lib/ansible/vars/manager.py 2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible/vars/manager.py 2023-11-06 
18:56:48.000000000 +0100
@@ -197,13 +197,13 @@
 
         if play:
             if not C.DEFAULT_PRIVATE_ROLE_VARS:
-                # first we compile any vars specified in defaults/main.yml
-                # for all roles within the specified play
                 for role in play.get_roles():
-                    # role from roles or include_role+public or import_role 
and completed
-                    if not role.from_include or role.public or (role.static 
and role._completed.get(to_text(host), False)):
+                    # role is public and
+                    #    either static or dynamic and completed
+                    # role is not set
+                    #    use config option as default
+                    if role.static or role.public and 
role._completed.get(host.name, False):
                         all_vars = _combine_and_track(all_vars, 
role.get_default_vars(), "role '%s' defaults" % role.name)
-
         if task:
             # set basedirs
             if C.PLAYBOOK_VARS_ROOT == 'all':  # should be default
@@ -386,11 +386,15 @@
                 raise AnsibleParserError("Error while reading vars files - 
please supply a list of file names. "
                                          "Got '%s' of type %s" % (vars_files, 
type(vars_files)))
 
-            # By default, we now merge in all exported vars from all roles in 
the play,
-            # unless the user has disabled this via a config option
+            # We now merge in all exported vars from all roles in the play,
+            # unless the user has disabled this
+            # role is public and
+            #    either static or dynamic and completed
+            # role is not set
+            #    use config option as default
             if not C.DEFAULT_PRIVATE_ROLE_VARS:
                 for role in play.get_roles():
-                    if not role.from_include or role.public or (role.static 
and role._completed.get(to_text(host), False)):
+                    if role.static or role.public and 
role._completed.get(host.name, False):
                         all_vars = _combine_and_track(all_vars, 
role.get_vars(include_params=False, only_exports=True), "role '%s' exported 
vars" % role.name)
 
         # next, we merge in the vars from the role, which will specifically
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible_core.egg-info/PKG-INFO 
new/ansible-core-2.15.6/lib/ansible_core.egg-info/PKG-INFO
--- old/ansible-core-2.15.5/lib/ansible_core.egg-info/PKG-INFO  2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible_core.egg-info/PKG-INFO  2023-11-06 
18:56:48.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ansible-core
-Version: 2.15.5
+Version: 2.15.6
 Summary: Radically simple IT automation
 Home-page: https://ansible.com/
 Author: Ansible, Inc.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/lib/ansible_core.egg-info/SOURCES.txt 
new/ansible-core-2.15.6/lib/ansible_core.egg-info/SOURCES.txt
--- old/ansible-core-2.15.5/lib/ansible_core.egg-info/SOURCES.txt       
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/lib/ansible_core.egg-info/SOURCES.txt       
2023-11-06 18:56:48.000000000 +0100
@@ -2018,6 +2018,7 @@
 test/integration/targets/handlers/test_notify_included.yml
 test/integration/targets/handlers/test_role_as_handler.yml
 test/integration/targets/handlers/test_role_handlers_including_tasks.yml
+test/integration/targets/handlers/test_run_once.yml
 test/integration/targets/handlers/test_skip_flush.yml
 test/integration/targets/handlers/test_templating_in_handlers.yml
 
test/integration/targets/handlers/roles/import_template_handler_names/tasks/main.yml
@@ -3052,6 +3053,12 @@
 test/integration/targets/plugin_loader/aliases
 test/integration/targets/plugin_loader/runme.sh
 test/integration/targets/plugin_loader/use_coll_name.yml
+test/integration/targets/plugin_loader/file_collision/play.yml
+test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py
+test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml
+test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml
+test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py
+test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml
 test/integration/targets/plugin_loader/normal/filters.yml
 test/integration/targets/plugin_loader/normal/self_referential.yml
 test/integration/targets/plugin_loader/normal/underscore.yml
@@ -3421,6 +3428,7 @@
 test/integration/targets/tags/ansible_run_tags.yml
 test/integration/targets/tags/runme.sh
 test/integration/targets/tags/test_tags.yml
+test/integration/targets/tags/test_template_parent_tags.yml
 test/integration/targets/task_ordering/aliases
 test/integration/targets/task_ordering/meta/main.yml
 test/integration/targets/task_ordering/tasks/main.yml
@@ -4200,7 +4208,6 @@
 test/sanity/code-smell/update-bundled.requirements.txt
 test/support/README.md
 test/support/integration/plugins/filter/json_query.py
-test/support/integration/plugins/modules/htpasswd.py
 test/support/integration/plugins/modules/pkgng.py
 test/support/integration/plugins/modules/sefcontext.py
 test/support/integration/plugins/modules/timezone.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/handlers/runme.sh 
new/ansible-core-2.15.6/test/integration/targets/handlers/runme.sh
--- old/ansible-core-2.15.5/test/integration/targets/handlers/runme.sh  
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/handlers/runme.sh  
2023-11-06 18:56:48.000000000 +0100
@@ -195,3 +195,6 @@
 
 ansible-playbook test_include_tasks_in_include_role.yml "$@" 2>&1 | tee out.txt
 [ "$(grep out.txt -ce 'handler ran')" = "1" ]
+
+ansible-playbook test_run_once.yml -i inventory.handlers "$@" 2>&1 | tee 
out.txt
+[ "$(grep out.txt -ce 'handler ran once')" = "1" ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/handlers/test_run_once.yml 
new/ansible-core-2.15.6/test/integration/targets/handlers/test_run_once.yml
--- old/ansible-core-2.15.5/test/integration/targets/handlers/test_run_once.yml 
1970-01-01 01:00:00.000000000 +0100
+++ new/ansible-core-2.15.6/test/integration/targets/handlers/test_run_once.yml 
2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,10 @@
+- hosts: A,B,C
+  gather_facts: false
+  tasks:
+    - command: echo
+      notify: handler
+  handlers:
+    - name: handler
+      run_once: true
+      debug:
+        msg: handler ran once
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/include_import/public_exposure/no_bleeding.yml
 
new/ansible-core-2.15.6/test/integration/targets/include_import/public_exposure/no_bleeding.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/include_import/public_exposure/no_bleeding.yml
     2023-10-09 17:51:22.000000000 +0200
+++ 
new/ansible-core-2.15.6/test/integration/targets/include_import/public_exposure/no_bleeding.yml
     2023-11-06 18:56:48.000000000 +0100
@@ -5,8 +5,8 @@
     - name: Static imports should expose vars at parse time, not at execution 
time
       assert:
         that:
-          - static_defaults_var is not defined
-          - static_vars_var is not defined
+          - static_defaults_var == 'static_defaults'
+          - static_vars_var == 'static_vars'
     - import_role:
         name: static
     - assert:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/include_import/public_exposure/playbook.yml
 
new/ansible-core-2.15.6/test/integration/targets/include_import/public_exposure/playbook.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/include_import/public_exposure/playbook.yml
        2023-10-09 17:51:22.000000000 +0200
+++ 
new/ansible-core-2.15.6/test/integration/targets/include_import/public_exposure/playbook.yml
        2023-11-06 18:56:48.000000000 +0100
@@ -10,16 +10,12 @@
     - name: Static imports should expose vars at parse time, not at execution 
time
       assert:
         that:
-          - static_defaults_var is not defined
-          - static_vars_var is not defined
-          - static_task_var is not defined
+          - static_defaults_var == 'static_defaults'
+          - static_vars_var == 'static_vars'
     - import_role:
         name: static
     - assert:
         that:
-          - static_vars_var is defined
-          - static_tasks_var is defined
-          - static_defaults_var is defined
           - static_tasks_var == 'static_tasks'
           - static_defaults_var == 'static_defaults'
           - static_vars_var == 'static_vars'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/play.yml
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/play.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/play.yml
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/play.yml
      2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,7 @@
+- hosts: localhost
+  gather_facts: false
+  roles:
+    - r1
+    - r2
+  tasks:
+    - debug: msg={{'a'|filter1|filter2|filter3}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py
     2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,15 @@
+from __future__ import annotations
+
+
+def do_nothing(myval):
+    return myval
+
+
+class FilterModule(object):
+    ''' Ansible core jinja2 filters '''
+
+    def filters(self):
+        return {
+            'filter1': do_nothing,
+            'filter3': do_nothing,
+        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml
   2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,18 @@
+DOCUMENTATION:
+  name: filter1
+  version_added: "1.9"
+  short_description: Does nothing
+  description:
+    - Really, does nothing
+  notes:
+    - This is a test filter
+  positional: _input
+  options:
+    _input:
+      description: the input
+      required: true
+
+EXAMPLES: ''
+RETURN:
+  _value:
+    description: The input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml
   2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,18 @@
+DOCUMENTATION:
+  name: filter3
+  version_added: "1.9"
+  short_description: Does nothing
+  description:
+    - Really, does nothing
+  notes:
+    - This is a test filter
+  positional: _input
+  options:
+    _input:
+      description: the input
+      required: true
+
+EXAMPLES: ''
+RETURN:
+  _value:
+    description: The input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py
     2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,14 @@
+from __future__ import annotations
+
+
+def do_nothing(myval):
+    return myval
+
+
+class FilterModule(object):
+    ''' Ansible core jinja2 filters '''
+
+    def filters(self):
+        return {
+            'filter2': do_nothing,
+        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml
 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml
   2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,18 @@
+DOCUMENTATION:
+  name: filter2
+  version_added: "1.9"
+  short_description: Does nothing
+  description:
+    - Really, does nothing
+  notes:
+    - This is a test filter
+  positional: _input
+  options:
+    _input:
+      description: the input
+      required: true
+
+EXAMPLES: ''
+RETURN:
+  _value:
+    description: The input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/plugin_loader/runme.sh 
new/ansible-core-2.15.6/test/integration/targets/plugin_loader/runme.sh
--- old/ansible-core-2.15.5/test/integration/targets/plugin_loader/runme.sh     
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/plugin_loader/runme.sh     
2023-11-06 18:56:48.000000000 +0100
@@ -34,3 +34,6 @@
 
 # test config loading
 ansible-playbook use_coll_name.yml -i ../../inventory -e 
'ansible_connection=ansible.builtin.ssh' "$@"
+
+# test filter loading ignoring duplicate file basename
+ansible-playbook file_collision/play.yml "$@"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/roles/vars_scope.yml 
new/ansible-core-2.15.6/test/integration/targets/roles/vars_scope.yml
--- old/ansible-core-2.15.5/test/integration/targets/roles/vars_scope.yml       
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/roles/vars_scope.yml       
2023-11-06 18:56:48.000000000 +0100
@@ -63,8 +63,7 @@
           play_only: play
           roles_and_role_vars: role_vars
           role_vars_only: role_vars
-
-- name: play and import
+- name: play baseline (no roles)
   hosts: localhost
   gather_facts: false
   vars_files:
@@ -82,6 +81,30 @@
           play_and_role_vars: play
           play_only: play
 
+- name: play and import
+  hosts: localhost
+  gather_facts: false
+  vars_files:
+    - vars/play.yml
+  tasks:
+    - include_tasks: roles/vars_scope/tasks/check_vars.yml
+      vars:
+        defined:
+          play_and_import: play
+          play_and_include: play
+          play_and_roles: play
+          play_only: play
+          default_only: default
+          import_and_role_vars: role_vars
+          include_and_role_vars: role_vars
+          play_and_import_and_role_vars: role_vars
+          play_and_role_vars: role_vars
+          play_and_role_vars_and_role_vars: role_vars
+          play_and_include_and_role_vars: role_vars
+          play_and_roles_and_role_vars: role_vars
+          roles_and_role_vars: role_vars
+          role_vars_only: role_vars
+
     - name: static import
       import_role:
         name: vars_scope
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/subversion/aliases 
new/ansible-core-2.15.6/test/integration/targets/subversion/aliases
--- old/ansible-core-2.15.5/test/integration/targets/subversion/aliases 
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/subversion/aliases 
2023-11-06 18:56:48.000000000 +0100
@@ -1,4 +1,3 @@
-setup/always/setup_passlib
 shippable/posix/group2
 skip/macos
 destructive
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/subversion/roles/subversion/tasks/cleanup.yml
 
new/ansible-core-2.15.6/test/integration/targets/subversion/roles/subversion/tasks/cleanup.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/subversion/roles/subversion/tasks/cleanup.yml
      2023-10-09 17:51:22.000000000 +0200
+++ 
new/ansible-core-2.15.6/test/integration/targets/subversion/roles/subversion/tasks/cleanup.yml
      2023-11-06 18:56:48.000000000 +0100
@@ -1,8 +1,18 @@
 ---
-- name: stop apache after tests
-  shell: "kill -9 $(cat '{{ subversion_server_dir }}/apache.pid')"
+- name: stop apache after tests - non Red Hat
+  shell: apachectl -k stop -f {{ subversion_server_dir }}/subversion.conf
+  when: ansible_os_family not in ['RedHat']
+
+- name: stop apache after tests - Red Hat
+  shell: "kill $(cat '{{ subversion_server_dir }}/apache.pid')"
+  when: ansible_os_family in ['RedHat']
 
 - name: remove tmp subversion server dir
   file:
     path: '{{ subversion_server_dir }}'
     state: absent
+
+- name: remove tmp subversion checkout dir
+  file:
+    path: '{{ subversion_test_dir }}'
+    state: absent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/subversion/roles/subversion/tasks/setup.yml
 
new/ansible-core-2.15.6/test/integration/targets/subversion/roles/subversion/tasks/setup.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/subversion/roles/subversion/tasks/setup.yml
        2023-10-09 17:51:22.000000000 +0200
+++ 
new/ansible-core-2.15.6/test/integration/targets/subversion/roles/subversion/tasks/setup.yml
        2023-11-06 18:56:48.000000000 +0100
@@ -45,11 +45,7 @@
     creates: '{{ subversion_server_dir }}/{{ subversion_repo_name }}'
 
 - name: add test user to htpasswd for Subversion site
-  htpasswd:
-    path: '{{ subversion_server_dir }}/svn-auth-users'
-    name: '{{ subversion_username }}'
-    password: '{{ subversion_password }}'
-    state: present
+  command: htpasswd -bc {{ subversion_server_dir + '/svn-auth-users' | quote 
}} {{ subversion_username | quote }} {{ subversion_password | quote }}
 
 - name: apply ownership for all SVN directories
   file:
@@ -62,11 +58,11 @@
   command: apachectl -k start -f {{ subversion_server_dir }}/subversion.conf
   async: 3600  # We kill apache manually in the clean up phase
   poll: 0
-  when: ansible_os_family not in ['RedHat', 'Alpine']
+  when: ansible_os_family not in ['RedHat']
 
 # On Red Hat based OS', we can't use apachectl to start up own instance, just 
use the raw httpd
 - name: start test Apache SVN site - Red Hat
   command: httpd -k start -f {{ subversion_server_dir }}/subversion.conf
   async: 3600  # We kill apache manually in the clean up phase
   poll: 0
-  when: ansible_os_family in ['RedHat', 'Alpine']
+  when: ansible_os_family in ['RedHat']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/subversion/vars/Alpine.yml 
new/ansible-core-2.15.6/test/integration/targets/subversion/vars/Alpine.yml
--- old/ansible-core-2.15.5/test/integration/targets/subversion/vars/Alpine.yml 
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/subversion/vars/Alpine.yml 
2023-11-06 18:56:48.000000000 +0100
@@ -3,5 +3,7 @@
 - subversion
 - mod_dav_svn
 - apache2-webdav
+- apache2-utils
+- apache2-ctl
 apache_user: apache
 apache_group: apache
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/tags/runme.sh 
new/ansible-core-2.15.6/test/integration/targets/tags/runme.sh
--- old/ansible-core-2.15.5/test/integration/targets/tags/runme.sh      
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/integration/targets/tags/runme.sh      
2023-11-06 18:56:48.000000000 +0100
@@ -73,3 +73,12 @@
 ansible-playbook -i ../../inventory ansible_run_tags.yml -e expect=untagged 
--tags untagged "$@"
 ansible-playbook -i ../../inventory ansible_run_tags.yml -e 
expect=untagged_list --tags untagged,tag3 "$@"
 ansible-playbook -i ../../inventory ansible_run_tags.yml -e expect=tagged 
--tags tagged "$@"
+
+ansible-playbook test_template_parent_tags.yml "$@" 2>&1 | tee out.txt
+[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
+
+ansible-playbook test_template_parent_tags.yml --tags tag1 "$@" 2>&1 | tee 
out.txt
+[ "$(grep out.txt -ce 'Tagged_task')" = "1" ]; rm out.txt
+
+ansible-playbook test_template_parent_tags.yml --skip-tags tag1 "$@" 2>&1 | 
tee out.txt
+[ "$(grep out.txt -ce 'Tagged_task')" = "0" ]; rm out.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/integration/targets/tags/test_template_parent_tags.yml
 
new/ansible-core-2.15.6/test/integration/targets/tags/test_template_parent_tags.yml
--- 
old/ansible-core-2.15.5/test/integration/targets/tags/test_template_parent_tags.yml
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible-core-2.15.6/test/integration/targets/tags/test_template_parent_tags.yml
 2023-11-06 18:56:48.000000000 +0100
@@ -0,0 +1,10 @@
+- hosts: localhost
+  gather_facts: false
+  vars:
+    tags_in_var:
+      - tag1
+  tasks:
+    - block:
+        - name: Tagged_task
+          debug:
+      tags: "{{ tags_in_var }}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/lib/ansible_test/_data/completion/windows.txt 
new/ansible-core-2.15.6/test/lib/ansible_test/_data/completion/windows.txt
--- old/ansible-core-2.15.5/test/lib/ansible_test/_data/completion/windows.txt  
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/lib/ansible_test/_data/completion/windows.txt  
2023-11-06 18:56:48.000000000 +0100
@@ -1,5 +1,5 @@
-windows/2012 provider=aws arch=x86_64
-windows/2012-R2 provider=aws arch=x86_64
+windows/2012 provider=azure arch=x86_64
+windows/2012-R2 provider=azure arch=x86_64
 windows/2016 provider=aws arch=x86_64
 windows/2019 provider=aws arch=x86_64
 windows/2022 provider=aws arch=x86_64
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/lib/ansible_test/_internal/cgroup.py 
new/ansible-core-2.15.6/test/lib/ansible_test/_internal/cgroup.py
--- old/ansible-core-2.15.5/test/lib/ansible_test/_internal/cgroup.py   
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/lib/ansible_test/_internal/cgroup.py   
2023-11-06 18:56:48.000000000 +0100
@@ -44,7 +44,7 @@
     @classmethod
     def parse(cls, value: str) -> CGroupEntry:
         """Parse the given cgroup line from the proc filesystem and return a 
cgroup entry."""
-        cid, subsystem, path = value.split(':')
+        cid, subsystem, path = value.split(':', maxsplit=2)
 
         return cls(
             id=int(cid),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/support/integration/plugins/modules/htpasswd.py 
new/ansible-core-2.15.6/test/support/integration/plugins/modules/htpasswd.py
--- 
old/ansible-core-2.15.5/test/support/integration/plugins/modules/htpasswd.py    
    2023-10-09 17:51:22.000000000 +0200
+++ 
new/ansible-core-2.15.6/test/support/integration/plugins/modules/htpasswd.py    
    1970-01-01 01:00:00.000000000 +0100
@@ -1,275 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2013, Nimbis Services, Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
-                    'status': ['preview'],
-                    'supported_by': 'community'}
-
-
-DOCUMENTATION = """
-module: htpasswd
-version_added: "1.3"
-short_description: manage user files for basic authentication
-description:
-  - Add and remove username/password entries in a password file using htpasswd.
-  - This is used by web servers such as Apache and Nginx for basic 
authentication.
-options:
-  path:
-    required: true
-    aliases: [ dest, destfile ]
-    description:
-      - Path to the file that contains the usernames and passwords
-  name:
-    required: true
-    aliases: [ username ]
-    description:
-      - User name to add or remove
-  password:
-    required: false
-    description:
-      - Password associated with user.
-      - Must be specified if user does not exist yet.
-  crypt_scheme:
-    required: false
-    choices: ["apr_md5_crypt", "des_crypt", "ldap_sha1", "plaintext"]
-    default: "apr_md5_crypt"
-    description:
-      - Encryption scheme to be used.  As well as the four choices listed
-        here, you can also use any other hash supported by passlib, such as
-        md5_crypt and sha256_crypt, which are linux passwd hashes.  If you
-        do so the password file will not be compatible with Apache or Nginx
-  state:
-    required: false
-    choices: [ present, absent ]
-    default: "present"
-    description:
-      - Whether the user entry should be present or not
-  create:
-    required: false
-    type: bool
-    default: "yes"
-    description:
-      - Used with C(state=present). If specified, the file will be created
-        if it does not already exist. If set to "no", will fail if the
-        file does not exist
-notes:
-  - "This module depends on the I(passlib) Python library, which needs to be 
installed on all target systems."
-  - "On Debian, Ubuntu, or Fedora: install I(python-passlib)."
-  - "On RHEL or CentOS: Enable EPEL, then install I(python-passlib)."
-requirements: [ passlib>=1.6 ]
-author: "Ansible Core Team"
-extends_documentation_fragment: files
-"""
-
-EXAMPLES = """
-# Add a user to a password file and ensure permissions are set
-- htpasswd:
-    path: /etc/nginx/passwdfile
-    name: janedoe
-    password: '9s36?;fyNp'
-    owner: root
-    group: www-data
-    mode: 0640
-
-# Remove a user from a password file
-- htpasswd:
-    path: /etc/apache2/passwdfile
-    name: foobar
-    state: absent
-
-# Add a user to a password file suitable for use by libpam-pwdfile
-- htpasswd:
-    path: /etc/mail/passwords
-    name: alex
-    password: oedu2eGh
-    crypt_scheme: md5_crypt
-"""
-
-
-import os
-import tempfile
-import traceback
-from ansible.module_utils.compat.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-from ansible.module_utils._text import to_native
-
-PASSLIB_IMP_ERR = None
-try:
-    from passlib.apache import HtpasswdFile, htpasswd_context
-    from passlib.context import CryptContext
-    import passlib
-except ImportError:
-    PASSLIB_IMP_ERR = traceback.format_exc()
-    passlib_installed = False
-else:
-    passlib_installed = True
-
-apache_hashes = ["apr_md5_crypt", "des_crypt", "ldap_sha1", "plaintext"]
-
-
-def create_missing_directories(dest):
-    destpath = os.path.dirname(dest)
-    if not os.path.exists(destpath):
-        os.makedirs(destpath)
-
-
-def present(dest, username, password, crypt_scheme, create, check_mode):
-    """ Ensures user is present
-
-    Returns (msg, changed) """
-    if crypt_scheme in apache_hashes:
-        context = htpasswd_context
-    else:
-        context = CryptContext(schemes=[crypt_scheme] + apache_hashes)
-    if not os.path.exists(dest):
-        if not create:
-            raise ValueError('Destination %s does not exist' % dest)
-        if check_mode:
-            return ("Create %s" % dest, True)
-        create_missing_directories(dest)
-        if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
-            ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, 
context=context)
-        else:
-            ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, 
context=context)
-        if getattr(ht, 'set_password', None):
-            ht.set_password(username, password)
-        else:
-            ht.update(username, password)
-        ht.save()
-        return ("Created %s and added %s" % (dest, username), True)
-    else:
-        if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
-            ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, 
context=context)
-        else:
-            ht = HtpasswdFile(dest, default=crypt_scheme, context=context)
-
-        found = None
-        if getattr(ht, 'check_password', None):
-            found = ht.check_password(username, password)
-        else:
-            found = ht.verify(username, password)
-
-        if found:
-            return ("%s already present" % username, False)
-        else:
-            if not check_mode:
-                if getattr(ht, 'set_password', None):
-                    ht.set_password(username, password)
-                else:
-                    ht.update(username, password)
-                ht.save()
-            return ("Add/update %s" % username, True)
-
-
-def absent(dest, username, check_mode):
-    """ Ensures user is absent
-
-    Returns (msg, changed) """
-    if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
-        ht = HtpasswdFile(dest, new=False)
-    else:
-        ht = HtpasswdFile(dest)
-
-    if username not in ht.users():
-        return ("%s not present" % username, False)
-    else:
-        if not check_mode:
-            ht.delete(username)
-            ht.save()
-        return ("Remove %s" % username, True)
-
-
-def check_file_attrs(module, changed, message):
-
-    file_args = module.load_file_common_arguments(module.params)
-    if module.set_fs_attributes_if_different(file_args, False):
-
-        if changed:
-            message += " and "
-        changed = True
-        message += "ownership, perms or SE linux context changed"
-
-    return message, changed
-
-
-def main():
-    arg_spec = dict(
-        path=dict(required=True, aliases=["dest", "destfile"]),
-        name=dict(required=True, aliases=["username"]),
-        password=dict(required=False, default=None, no_log=True),
-        crypt_scheme=dict(required=False, default="apr_md5_crypt"),
-        state=dict(required=False, default="present"),
-        create=dict(type='bool', default='yes'),
-
-    )
-    module = AnsibleModule(argument_spec=arg_spec,
-                           add_file_common_args=True,
-                           supports_check_mode=True)
-
-    path = module.params['path']
-    username = module.params['name']
-    password = module.params['password']
-    crypt_scheme = module.params['crypt_scheme']
-    state = module.params['state']
-    create = module.params['create']
-    check_mode = module.check_mode
-
-    if not passlib_installed:
-        module.fail_json(msg=missing_required_lib("passlib"), 
exception=PASSLIB_IMP_ERR)
-
-    # Check file for blank lines in effort to avoid "need more than 1 value to 
unpack" error.
-    try:
-        f = open(path, "r")
-    except IOError:
-        # No preexisting file to remove blank lines from
-        f = None
-    else:
-        try:
-            lines = f.readlines()
-        finally:
-            f.close()
-
-        # If the file gets edited, it returns true, so only edit the file if 
it has blank lines
-        strip = False
-        for line in lines:
-            if not line.strip():
-                strip = True
-                break
-
-        if strip:
-            # If check mode, create a temporary file
-            if check_mode:
-                temp = tempfile.NamedTemporaryFile()
-                path = temp.name
-            f = open(path, "w")
-            try:
-                [f.write(line) for line in lines if line.strip()]
-            finally:
-                f.close()
-
-    try:
-        if state == 'present':
-            (msg, changed) = present(path, username, password, crypt_scheme, 
create, check_mode)
-        elif state == 'absent':
-            if not os.path.exists(path):
-                module.exit_json(msg="%s not present" % username,
-                                 warnings="%s does not exist" % path, 
changed=False)
-            (msg, changed) = absent(path, username, check_mode)
-        else:
-            module.fail_json(msg="Invalid state: %s" % state)
-
-        check_file_attrs(module, changed, msg)
-        module.exit_json(msg=msg, changed=changed)
-    except Exception as e:
-        module.fail_json(msg=to_native(e))
-
-
-if __name__ == '__main__':
-    main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible-core-2.15.5/test/units/cli/test_galaxy.py 
new/ansible-core-2.15.6/test/units/cli/test_galaxy.py
--- old/ansible-core-2.15.5/test/units/cli/test_galaxy.py       2023-10-09 
17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/units/cli/test_galaxy.py       2023-11-06 
18:56:48.000000000 +0100
@@ -753,6 +753,20 @@
     assert mock_install.call_args[0][6] is False  # force_deps
 
 
+def 
test_collection_install_with_invalid_requirements_format(collection_install):
+    output_dir = collection_install[2]
+
+    requirements_file = os.path.join(output_dir, 'requirements.yml')
+    with open(requirements_file, 'wb') as req_obj:
+        req_obj.write(b'"invalid"')
+
+    galaxy_args = ['ansible-galaxy', 'collection', 'install', 
'--requirements-file', requirements_file,
+                   '--collections-path', output_dir]
+
+    with pytest.raises(AnsibleError, match="Expecting requirements yaml to be 
a list or dictionary but got str"):
+        GalaxyCLI(args=galaxy_args).run()
+
+
 def test_collection_install_with_requirements_file(collection_install):
     mock_install, mock_warning, output_dir = collection_install
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/units/playbook/test_taggable.py 
new/ansible-core-2.15.6/test/units/playbook/test_taggable.py
--- old/ansible-core-2.15.5/test/units/playbook/test_taggable.py        
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/units/playbook/test_taggable.py        
2023-11-06 18:56:48.000000000 +0100
@@ -29,6 +29,7 @@
     def __init__(self):
         self._loader = DictDataLoader({})
         self.tags = []
+        self._parent = None
 
 
 class TestTaggable(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible-core-2.15.5/test/units/plugins/connection/test_winrm.py 
new/ansible-core-2.15.6/test/units/plugins/connection/test_winrm.py
--- old/ansible-core-2.15.5/test/units/plugins/connection/test_winrm.py 
2023-10-09 17:51:22.000000000 +0200
+++ new/ansible-core-2.15.6/test/units/plugins/connection/test_winrm.py 
2023-11-06 18:56:48.000000000 +0100
@@ -13,8 +13,8 @@
 from io import StringIO
 
 from unittest.mock import MagicMock
-from ansible.errors import AnsibleConnectionFailure
-from ansible.module_utils._text import to_bytes
+from ansible.errors import AnsibleConnectionFailure, AnsibleError
+from ansible.module_utils.common.text.converters import to_bytes
 from ansible.playbook.play_context import PlayContext
 from ansible.plugins.loader import connection_loader
 from ansible.plugins.connection import winrm
@@ -441,3 +441,123 @@
         assert str(err.value) == \
             "Kerberos auth failure for principal username with pexpect: " \
             "Error with kinit\n<redacted>"
+
+    def test_exec_command_with_timeout(self, monkeypatch):
+        requests_exc = pytest.importorskip("requests.exceptions")
+
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+
+        mock_proto = MagicMock()
+        mock_proto.run_command.side_effect = requests_exc.Timeout("msg")
+
+        conn._connected = True
+        conn._winrm_host = 'hostname'
+
+        monkeypatch.setattr(conn, "_winrm_connect", lambda: mock_proto)
+
+        with pytest.raises(AnsibleConnectionFailure) as e:
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+        assert str(e.value) == "winrm connection error: msg"
+
+    def test_exec_command_get_output_timeout(self, monkeypatch):
+        requests_exc = pytest.importorskip("requests.exceptions")
+
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+
+        mock_proto = MagicMock()
+        mock_proto.run_command.return_value = "command_id"
+        mock_proto.get_command_output.side_effect = requests_exc.Timeout("msg")
+
+        conn._connected = True
+        conn._winrm_host = 'hostname'
+
+        monkeypatch.setattr(conn, "_winrm_connect", lambda: mock_proto)
+
+        with pytest.raises(AnsibleConnectionFailure) as e:
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+        assert str(e.value) == "winrm connection error: msg"
+
+    def test_exec_command_with_timeout(self, monkeypatch):
+        requests_exc = pytest.importorskip("requests.exceptions")
+
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+
+        mock_proto = MagicMock()
+        mock_proto.run_command.side_effect = requests_exc.Timeout("msg")
+
+        conn._connected = True
+        conn._winrm_host = 'hostname'
+
+        monkeypatch.setattr(conn, "_winrm_connect", lambda: mock_proto)
+
+        with pytest.raises(AnsibleConnectionFailure) as e:
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+        assert str(e.value) == "winrm connection error: msg"
+
+    def test_connect_failure_auth_401(self, monkeypatch):
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+        conn.set_options(var_options={"ansible_winrm_transport": "basic", 
"_extras": {}})
+
+        mock_proto = MagicMock()
+        mock_proto.open_shell.side_effect = ValueError("Custom exc Code 401")
+
+        mock_proto_init = MagicMock()
+        mock_proto_init.return_value = mock_proto
+        monkeypatch.setattr(winrm, "Protocol", mock_proto_init)
+
+        with pytest.raises(AnsibleConnectionFailure, match="the specified 
credentials were rejected by the server"):
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+    def test_connect_failure_other_exception(self, monkeypatch):
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+        conn.set_options(var_options={"ansible_winrm_transport": "basic", 
"_extras": {}})
+
+        mock_proto = MagicMock()
+        mock_proto.open_shell.side_effect = ValueError("Custom exc")
+
+        mock_proto_init = MagicMock()
+        mock_proto_init.return_value = mock_proto
+        monkeypatch.setattr(winrm, "Protocol", mock_proto_init)
+
+        with pytest.raises(AnsibleConnectionFailure, match="basic: Custom 
exc"):
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+    def test_connect_failure_operation_timed_out(self, monkeypatch):
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+        conn.set_options(var_options={"ansible_winrm_transport": "basic", 
"_extras": {}})
+
+        mock_proto = MagicMock()
+        mock_proto.open_shell.side_effect = ValueError("Custom exc Operation 
timed out")
+
+        mock_proto_init = MagicMock()
+        mock_proto_init.return_value = mock_proto
+        monkeypatch.setattr(winrm, "Protocol", mock_proto_init)
+
+        with pytest.raises(AnsibleError, match="the connection attempt timed 
out"):
+            conn.exec_command('cmd', in_data=None, sudoable=True)
+
+    def test_connect_no_transport(self):
+        pc = PlayContext()
+        new_stdin = StringIO()
+        conn = connection_loader.get('winrm', pc, new_stdin)
+        conn.set_options(var_options={"_extras": {}})
+        conn._build_winrm_kwargs()
+        conn._winrm_transport = []
+
+        with pytest.raises(AnsibleError, match="No transport found for WinRM 
connection"):
+            conn._winrm_connect()

Reply via email to