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 2026-05-19 17:50:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ansible-core (Old)
 and      /work/SRC/openSUSE:Factory/.ansible-core.new.1966 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ansible-core"

Tue May 19 17:50:23 2026 rev:56 rq:1353955 version:2.20.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/ansible-core/ansible-core.changes        
2026-04-21 12:47:41.133554471 +0200
+++ /work/SRC/openSUSE:Factory/.ansible-core.new.1966/ansible-core.changes      
2026-05-19 17:50:59.398174693 +0200
@@ -1,0 +2,22 @@
+Tue May 19 07:08:20 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- update to 2.20.6:
+  
https://github.com/ansible/ansible/blob/v2.20.6/changelogs/CHANGELOG-v2.20.rst
+  * Security Fixes
+    - psrp - Do not log raw stdout/stderr on verbosity 5 when task
+      has no_log: true set
+    - winrm - Do not log raw stdout/stderr on verbosity 5 when task
+      has no_log: true set
+  * Bugfixes
+    - ansible-test remote alias - Alias values for --controller and
+      --target are properly resolved for remote. Previously, remote
+      alias values (e.g. fedora/latest) resolved to the correct
+      name only for the legacy --remote arg, failing with an
+      unknown image error for the newer args.
+    - git - use the branch configured in .gitmodules or the remote
+      HEAD instead of hardcoding master when track_submodules=yes
+      (#77691).
+    - module_utils/basic.py - Fix AnsibleModule.run_command() to
+      handle None return from non-blocking pipe reads (#86920).
+
+-------------------------------------------------------------------

Old:
----
  ansible_core-2.20.5.tar.gz
  ansible_core-2.20.5.tar.gz.sha256

New:
----
  ansible_core-2.20.6.tar.gz
  ansible_core-2.20.6.tar.gz.sha256

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

Other differences:
------------------
++++++ ansible-core.spec ++++++
--- /var/tmp/diff_new_pack.rYp0al/_old  2026-05-19 17:51:01.474260475 +0200
+++ /var/tmp/diff_new_pack.rYp0al/_new  2026-05-19 17:51:01.490261136 +0200
@@ -43,7 +43,7 @@
 %endif
 
 Name:           ansible-core
-Version:        2.20.5
+Version:        2.20.6
 Release:        0
 Summary:        Radically simple IT automation
 License:        GPL-3.0-or-later

++++++ ansible_core-2.20.5.tar.gz -> ansible_core-2.20.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/PKG-INFO 
new/ansible_core-2.20.6/PKG-INFO
--- old/ansible_core-2.20.5/PKG-INFO    2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/PKG-INFO    2026-05-18 21:15:21.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: ansible-core
-Version: 2.20.5
+Version: 2.20.6
 Summary: Radically simple IT automation
 Author: Ansible Project
 Project-URL: Homepage, https://ansible.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/ansible_core.egg-info/PKG-INFO 
new/ansible_core-2.20.6/ansible_core.egg-info/PKG-INFO
--- old/ansible_core-2.20.5/ansible_core.egg-info/PKG-INFO      2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/ansible_core.egg-info/PKG-INFO      2026-05-18 
21:15:21.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: ansible-core
-Version: 2.20.5
+Version: 2.20.6
 Summary: Radically simple IT automation
 Author: Ansible Project
 Project-URL: Homepage, https://ansible.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/ansible_core.egg-info/SOURCES.txt 
new/ansible_core-2.20.6/ansible_core.egg-info/SOURCES.txt
--- old/ansible_core-2.20.5/ansible_core.egg-info/SOURCES.txt   2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/ansible_core.egg-info/SOURCES.txt   2026-05-18 
21:15:21.000000000 +0200
@@ -2290,6 +2290,7 @@
 test/integration/targets/git/tasks/single-branch.yml
 test/integration/targets/git/tasks/specific-revision.yml
 test/integration/targets/git/tasks/submodules.yml
+test/integration/targets/git/tasks/track-submodules-branch.yml
 test/integration/targets/git/vars/main.yml
 test/integration/targets/group/aliases
 test/integration/targets/group/files/get_free_gid.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/changelogs/CHANGELOG-v2.20.rst 
new/ansible_core-2.20.6/changelogs/CHANGELOG-v2.20.rst
--- old/ansible_core-2.20.5/changelogs/CHANGELOG-v2.20.rst      2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/changelogs/CHANGELOG-v2.20.rst      2026-05-18 
21:15:21.000000000 +0200
@@ -4,6 +4,28 @@
 
 .. contents:: Topics
 
+v2.20.6
+=======
+
+Release Summary
+---------------
+
+| Release Date: 2026-05-18
+| `Porting Guide 
<https://docs.ansible.com/ansible-core/2.20/porting_guides/porting_guide_core_2.20.html>`__
+
+Security Fixes
+--------------
+
+- psrp - Do not log raw stdout/stderr on verbosity 5 when task has ``no_log: 
true`` set
+- winrm - Do not log raw stdout/stderr on verbosity 5 when task has ``no_log: 
true`` set
+
+Bugfixes
+--------
+
+- ansible-test remote alias - Alias values for ``--controller`` and 
``--target`` are properly resolved for ``remote``. Previously, remote alias 
values (e.g. ``fedora/latest``) resolved to the correct name only for the 
legacy ``--remote`` arg, failing with an unknown image error for the newer args.
+- git - use the branch configured in ``.gitmodules`` or the remote HEAD 
instead of hardcoding ``master`` when ``track_submodules=yes`` 
(https://github.com/ansible/ansible/issues/77691).
+- module_utils/basic.py - Fix ``AnsibleModule.run_command()`` to handle 
``None`` return from non-blocking pipe reads 
(https://github.com/ansible/ansible/issues/86920).
+
 v2.20.5
 =======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/changelogs/changelog.yaml 
new/ansible_core-2.20.6/changelogs/changelog.yaml
--- old/ansible_core-2.20.5/changelogs/changelog.yaml   2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/changelogs/changelog.yaml   2026-05-18 
21:15:21.000000000 +0200
@@ -619,3 +619,43 @@
     - clearlinux-gentoo-parsing.yml
     - start-at-task-fact-gathering.yml
     release_date: '2026-04-13'
+  2.20.6:
+    changes:
+      release_summary: '| Release Date: 2026-05-18
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.20/porting_guides/porting_guide_core_2.20.html>`__
+
+        '
+    codename: Good Times Bad Times
+    fragments:
+    - 2.20.6_summary.yaml
+    release_date: '2026-05-18'
+  2.20.6rc1:
+    changes:
+      bugfixes:
+      - ansible-test remote alias - Alias values for ``--controller`` and 
``--target``
+        are properly resolved for ``remote``. Previously, remote alias values 
(e.g.
+        ``fedora/latest``) resolved to the correct name only for the legacy 
``--remote``
+        arg, failing with an unknown image error for the newer args.
+      - git - use the branch configured in ``.gitmodules`` or the remote HEAD 
instead
+        of hardcoding ``master`` when ``track_submodules=yes`` 
(https://github.com/ansible/ansible/issues/77691).
+      - module_utils/basic.py - Fix ``AnsibleModule.run_command()`` to handle 
``None``
+        return from non-blocking pipe reads 
(https://github.com/ansible/ansible/issues/86920).
+      release_summary: '| Release Date: 2026-05-11
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.20/porting_guides/porting_guide_core_2.20.html>`__
+
+        '
+      security_fixes:
+      - 'psrp - Do not log raw stdout/stderr on verbosity 5 when task has 
``no_log:
+        true`` set'
+      - 'winrm - Do not log raw stdout/stderr on verbosity 5 when task has 
``no_log:
+        true`` set'
+    codename: Good Times Bad Times
+    fragments:
+    - 2.20.6rc1_summary.yaml
+    - 77691-git-track-submodules-branch.yml
+    - 86920-fix-run-command-none-read.yml
+    - core_ci_remote_alias.yml
+    - winrm-psrp-nolog.yml
+    release_date: '2026-05-11'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/lib/ansible/module_utils/ansible_release.py 
new/ansible_core-2.20.6/lib/ansible/module_utils/ansible_release.py
--- old/ansible_core-2.20.5/lib/ansible/module_utils/ansible_release.py 
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/module_utils/ansible_release.py 
2026-05-18 21:15:21.000000000 +0200
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.20.5'
+__version__ = '2.20.6'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Good Times Bad Times"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/lib/ansible/module_utils/basic.py 
new/ansible_core-2.20.6/lib/ansible/module_utils/basic.py
--- old/ansible_core-2.20.5/lib/ansible/module_utils/basic.py   2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/module_utils/basic.py   2026-05-18 
21:15:21.000000000 +0200
@@ -2093,7 +2093,13 @@
                 stdout_changed = False
                 for key, event in events:
                     b_chunk = key.fileobj.read(32768)
-                    if not b_chunk and b_chunk is not None:
+                    if b_chunk is None:
+                        # Non-blocking read returned None (no data currently 
available).
+                        # This can happen with certain file-like objects or in 
edge cases.
+                        # Skip this chunk and try again on next select 
iteration.
+                        continue
+                    if not b_chunk:
+                        # Empty bytes received, EOF reached
                         selector.unregister(key.fileobj)
                     elif key.fileobj == cmd.stdout:
                         stdout += b_chunk
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/lib/ansible/modules/git.py 
new/ansible_core-2.20.6/lib/ansible/modules/git.py
--- old/ansible_core-2.20.5/lib/ansible/modules/git.py  2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/modules/git.py  2026-05-18 
21:15:21.000000000 +0200
@@ -168,9 +168,11 @@
 
     track_submodules:
         description:
-            - If V(true), submodules will track the latest commit on their
-              master branch (or other branch specified in C(.gitmodules)).  If
-              V(false), submodules will be kept at the revision specified by 
the
+            - If V(true), submodules will track the latest commit on the 
branch specified in C(.gitmodules).
+              If no branch is specified in C(.gitmodules), it will use the 
remote HEAD.
+            - Currently, the value of remote is defaulted to C(origin).
+              Specifying the remote for the submodules is not supported.
+            - If V(false), submodules will be kept at the revision specified 
by the
               main project. This is equivalent to specifying the C(--remote) 
flag
               to git submodule update.
         type: bool
@@ -566,6 +568,28 @@
     return submodules
 
 
+def get_submodule_branch(git_path, module, dest, submodule):
+    """Get the configured branch for a submodule from .gitmodules.
+
+    Falls back to the remote HEAD if no branch is configured.
+    """
+    cmd = [git_path, 'config', '-f', '.gitmodules',
+           f'submodule.{submodule}.branch']
+    rc, out, _err = module.run_command(cmd, cwd=dest)
+    if rc == 0 and out.strip():
+        return out.strip()
+
+    # No branch configured in .gitmodules, use remote HEAD
+    submodule_path = os.path.join(dest, submodule)
+    cmd = [git_path, 'symbolic-ref', '--short', 'refs/remotes/origin/HEAD']
+    rc, out, _err = module.run_command(cmd, cwd=submodule_path)
+    if rc == 0 and out.strip():
+        # Returns e.g. "origin/main", strip the remote prefix
+        return out.strip().split('/', 1)[-1]
+
+    return 'HEAD'
+
+
 def clone(git_path, module, repo, dest, remote, depth, version, bare,
           reference, refspec, git_version_used, verify_commit, 
separate_git_dir, result, gpg_allowlist, single_branch):
     """ makes a new git repo if it does not already exist """
@@ -959,10 +983,19 @@
             module.fail_json(msg="Failed to fetch submodules: %s" % out + err)
 
         if track_submodules:
-            # Compare against submodule HEAD
-            # FIXME: determine this from .gitmodules
-            version = 'master'
-            after = get_submodule_versions(git_path, module, dest, '%s/%s' % 
(remote, version))
+            # Compare each submodule against its configured remote branch
+            after = {}
+            for submodule in begin:
+                branch = get_submodule_branch(git_path, module, dest, 
submodule)
+                version_ref = f'{remote}/{branch}' if branch != 'HEAD' else 
'HEAD'
+                submodule_path = os.path.join(dest, submodule)
+                cmd = [git_path, 'rev-parse', version_ref]
+                (rc, out, err) = module.run_command(cmd, cwd=submodule_path)
+                if rc != 0:
+                    module.fail_json(
+                        msg='Unable to determine hash of submodule %s at %s' % 
(submodule, version_ref),
+                        stdout=out, stderr=err, rc=rc)
+                after[submodule] = out.strip()
             if begin != after:
                 changed = True
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/lib/ansible/plugins/connection/psrp.py 
new/ansible_core-2.20.6/lib/ansible/plugins/connection/psrp.py
--- old/ansible_core-2.20.5/lib/ansible/plugins/connection/psrp.py      
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/plugins/connection/psrp.py      
2026-05-18 21:15:21.000000000 +0200
@@ -767,9 +767,14 @@
             stderr_list += self.host.ui.stderr
         stderr = "".join([to_text(o) for o in stderr_list])
 
+        log_stdout = stdout
+        log_stderr = stderr
+        if self._play_context.no_log:
+            log_stdout = log_stderr = '<censored due to no log>'
+
         display.vvvvv("PSRP RC: %d" % rc, host=self._psrp_host)
-        display.vvvvv("PSRP STDOUT: %s" % stdout, host=self._psrp_host)
-        display.vvvvv("PSRP STDERR: %s" % stderr, host=self._psrp_host)
+        display.vvvvv(f"PSRP STDOUT: {log_stdout}", host=self._psrp_host)
+        display.vvvvv(f"PSRP STDERR: {log_stderr}", host=self._psrp_host)
 
         # reset the host back output back to defaults, needed if running
         # multiple pipelines on the same RunspacePool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/lib/ansible/plugins/connection/winrm.py 
new/ansible_core-2.20.6/lib/ansible/plugins/connection/winrm.py
--- old/ansible_core-2.20.5/lib/ansible/plugins/connection/winrm.py     
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/plugins/connection/winrm.py     
2026-05-18 21:15:21.000000000 +0200
@@ -625,11 +625,16 @@
             stdout = to_text(b_stdout)
             stderr = to_text(b_stderr)
 
+            log_stdout = stdout
+            log_stderr = stderr
+            if self._play_context.no_log:
+                log_stdout = log_stderr = '<censored due to no log>'
+
             if from_exec:
-                display.vvvvv('WINRM RESULT <Response code %d, out %r, err 
%r>' % (rc, stdout, stderr), host=self._winrm_host)
+                display.vvvvv(f'WINRM RESULT <Response code {rc}, out 
{log_stdout!r}, err {log_stderr!r}>', host=self._winrm_host)
             display.vvvvvv('WINRM RC %d' % rc, host=self._winrm_host)
-            display.vvvvvv('WINRM STDOUT %s' % stdout, host=self._winrm_host)
-            display.vvvvvv('WINRM STDERR %s' % stderr, host=self._winrm_host)
+            display.vvvvvv(f'WINRM STDOUT {log_stdout}', host=self._winrm_host)
+            display.vvvvvv(f'WINRM STDERR {log_stderr}', host=self._winrm_host)
 
             # This is done after logging so we can still see the raw stderr for
             # debugging purposes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.20.5/lib/ansible/release.py 
new/ansible_core-2.20.6/lib/ansible/release.py
--- old/ansible_core-2.20.5/lib/ansible/release.py      2026-04-21 
02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/lib/ansible/release.py      2026-05-18 
21:15:21.000000000 +0200
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.20.5'
+__version__ = '2.20.6'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Good Times Bad Times"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/test/integration/targets/git/tasks/main.yml 
new/ansible_core-2.20.6/test/integration/targets/git/tasks/main.yml
--- old/ansible_core-2.20.5/test/integration/targets/git/tasks/main.yml 
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/test/integration/targets/git/tasks/main.yml 
2026-05-18 21:15:21.000000000 +0200
@@ -32,6 +32,7 @@
   - import_tasks: no-destination.yml
   - import_tasks: specific-revision.yml
   - import_tasks: submodules.yml
+  - import_tasks: track-submodules-branch.yml
   - import_tasks: change-repo-url.yml
   - import_tasks: depth.yml
   - import_tasks: single-branch.yml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/test/integration/targets/git/tasks/track-submodules-branch.yml
 
new/ansible_core-2.20.6/test/integration/targets/git/tasks/track-submodules-branch.yml
--- 
old/ansible_core-2.20.5/test/integration/targets/git/tasks/track-submodules-branch.yml
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.20.6/test/integration/targets/git/tasks/track-submodules-branch.yml
      2026-05-18 21:15:21.000000000 +0200
@@ -0,0 +1,272 @@
+#
+# Tests for track_submodules with non-master default branches
+#
+# Verifies that get_submodule_branch() correctly reads the branch from
+# .gitmodules and falls back to remote HEAD, instead of hardcoding 'master'.
+#
+
+# --- Setup ---
+
+- name: TRACK-SUBMODULES-BRANCH | allow local file transport for submodule 
clones
+  shell: git config --global protocol.file.allow always
+
+- name: TRACK-SUBMODULES-BRANCH | create local repo dirs
+  file:
+    path: "{{ item }}"
+    state: directory
+  loop:
+    - "{{ repo_dir }}/track_sub_remote"
+    - "{{ repo_dir }}/track_sub_parent"
+
+- name: TRACK-SUBMODULES-BRANCH | create a submodule repo with 'main' as 
default branch
+  shell: |
+    set -eEu
+    git init
+    echo "initial" > file1.txt
+    git add file1.txt
+    git commit -m "initial commit on main"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote"
+
+- name: TRACK-SUBMODULES-BRANCH | create parent repo with submodule pointing 
to 'main'
+  shell: |
+    set -eEu
+    git init
+    echo "parent" > README.md
+    git add README.md
+    git commit -m "parent initial"
+
+    git submodule add "{{ repo_dir }}/track_sub_remote" sub1
+    git commit -m "add submodule sub1"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_parent"
+
+- name: TRACK-SUBMODULES-BRANCH | set explicit branch in .gitmodules
+  shell: |
+    set -eEu
+    git config -f .gitmodules submodule.sub1.branch main
+    git add .gitmodules
+    git commit -m "set submodule branch to main"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_parent"
+
+# --- Test 1: track_submodules detects updates on configured branch (main) ---
+
+- name: TRACK-SUBMODULES-BRANCH | clean checkout dir
+  file:
+    state: absent
+    path: "{{ checkout_dir }}"
+
+- name: TRACK-SUBMODULES-BRANCH | clone parent with recursive submodules
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+
+- name: TRACK-SUBMODULES-BRANCH | record initial state (should not be changed)
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+  register: track_initial
+
+- name: TRACK-SUBMODULES-BRANCH | assert no change on first re-run
+  assert:
+    that:
+      - not track_initial.changed
+
+- name: TRACK-SUBMODULES-BRANCH | push a new commit to the submodule remote
+  shell: |
+    set -eEu
+    echo "update" > file2.txt
+    git add file2.txt
+    git commit -m "second commit on main"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote"
+
+- name: TRACK-SUBMODULES-BRANCH | re-run with track_submodules to detect 
remote update
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+  register: track_after_update
+
+- name: TRACK-SUBMODULES-BRANCH | assert change detected after submodule 
remote was updated
+  assert:
+    that:
+      - track_after_update.changed
+
+# --- Test 2: track_submodules works with remote HEAD fallback (no branch in 
.gitmodules) ---
+
+- name: TRACK-SUBMODULES-BRANCH | create dirs for fallback test
+  file:
+    path: "{{ item }}"
+    state: directory
+  loop:
+    - "{{ repo_dir }}/track_sub_remote_fb"
+    - "{{ repo_dir }}/track_sub_parent_fb"
+
+- name: TRACK-SUBMODULES-BRANCH | create submodule repo for fallback test
+  shell: |
+    set -eEu
+    git init
+    echo "initial" > file1.txt
+    git add file1.txt
+    git commit -m "initial commit"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote_fb"
+
+- name: TRACK-SUBMODULES-BRANCH | create parent repo without explicit branch 
in .gitmodules
+  shell: |
+    set -eEu
+    git init
+    echo "parent" > README.md
+    git add README.md
+    git commit -m "parent initial"
+
+    git submodule add "{{ repo_dir }}/track_sub_remote_fb" sub_fb
+    git commit -m "add submodule sub_fb (no explicit branch)"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_parent_fb"
+
+- name: TRACK-SUBMODULES-BRANCH | clean checkout dir for fallback test
+  file:
+    state: absent
+    path: "{{ checkout_dir }}"
+
+- name: TRACK-SUBMODULES-BRANCH | clone parent (fallback test)
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent_fb"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+
+- name: TRACK-SUBMODULES-BRANCH | push a new commit to fallback submodule 
remote
+  shell: |
+    set -eEu
+    echo "new content" > file2.txt
+    git add file2.txt
+    git commit -m "second commit"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote_fb"
+
+- name: TRACK-SUBMODULES-BRANCH | re-run track_submodules with fallback branch 
detection
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent_fb"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+  register: track_fallback_update
+
+- name: TRACK-SUBMODULES-BRANCH | assert change detected with fallback branch
+  assert:
+    that:
+      - track_fallback_update.changed
+
+# --- Test 3: two submodules with different default branches ---
+
+- name: TRACK-SUBMODULES-BRANCH | create dirs for multi-branch test
+  file:
+    path: "{{ item }}"
+    state: directory
+  loop:
+    - "{{ repo_dir }}/track_sub_remote_master"
+    - "{{ repo_dir }}/track_sub_remote_main"
+    - "{{ repo_dir }}/track_sub_parent_multi"
+
+- name: TRACK-SUBMODULES-BRANCH | create submodule repo with 'develop' branch
+  shell: |
+    set -eEu
+    git init
+    echo "initial" > file1.txt
+    git add file1.txt
+    git commit -m "initial on main"
+    git checkout -b develop
+    echo "dev" > file2.txt
+    git add file2.txt
+    git commit -m "initial on develop"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote_master"
+
+- name: TRACK-SUBMODULES-BRANCH | create submodule repo using 'main'
+  shell: |
+    set -eEu
+    git init
+    echo "initial" > file1.txt
+    git add file1.txt
+    git commit -m "initial on main"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote_main"
+
+- name: TRACK-SUBMODULES-BRANCH | create parent with two submodules on 
different branches
+  shell: |
+    set -eEu
+    git init
+    echo "parent" > README.md
+    git add README.md
+    git commit -m "parent initial"
+
+    git submodule add -b develop "{{ repo_dir }}/track_sub_remote_master" 
sub_develop
+    git submodule add "{{ repo_dir }}/track_sub_remote_main" sub_main
+    git config -f .gitmodules submodule.sub_main.branch main
+    git add .gitmodules
+    git commit -m "add two submodules with different branches"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_parent_multi"
+
+- name: TRACK-SUBMODULES-BRANCH | clean checkout dir for multi-branch test
+  file:
+    state: absent
+    path: "{{ checkout_dir }}"
+
+- name: TRACK-SUBMODULES-BRANCH | clone parent with two submodules
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent_multi"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+
+- name: TRACK-SUBMODULES-BRANCH | re-run should show no changes
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent_multi"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+  register: track_multi_initial
+
+- name: TRACK-SUBMODULES-BRANCH | assert no change on re-run with two 
submodules
+  assert:
+    that:
+      - not track_multi_initial.changed
+
+- name: TRACK-SUBMODULES-BRANCH | push update to only the 'main' submodule
+  shell: |
+    set -eEu
+    echo "update" > file2.txt
+    git add file2.txt
+    git commit -m "second commit on main"
+  args:
+    chdir: "{{ repo_dir }}/track_sub_remote_main"
+
+- name: TRACK-SUBMODULES-BRANCH | re-run should detect change in sub_main only
+  git:
+    repo: "{{ repo_dir }}/track_sub_parent_multi"
+    dest: "{{ checkout_dir }}"
+    recursive: yes
+    track_submodules: yes
+  register: track_multi_update
+
+- name: TRACK-SUBMODULES-BRANCH | assert change detected with mixed-branch 
submodules
+  assert:
+    that:
+      - track_multi_update.changed
+
+# --- Cleanup ---
+
+- name: TRACK-SUBMODULES-BRANCH | clean checkout dir
+  file:
+    state: absent
+    path: "{{ checkout_dir }}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/test/lib/ansible_test/_internal/host_configs.py 
new/ansible_core-2.20.6/test/lib/ansible_test/_internal/host_configs.py
--- old/ansible_core-2.20.5/test/lib/ansible_test/_internal/host_configs.py     
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/test/lib/ansible_test/_internal/host_configs.py     
2026-05-18 21:15:21.000000000 +0200
@@ -384,6 +384,7 @@
         super().apply_defaults(context, defaults)
 
         self.become = self.become or defaults.become
+        self.name = defaults.name
 
     @property
     def have_root(self) -> bool:
@@ -413,6 +414,7 @@
         super().apply_defaults(context, defaults)
 
         self.connection = self.connection or defaults.connection
+        self.name = defaults.name
 
 
 @dataclasses.dataclass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.20.5/test/units/module_utils/basic/test_run_command.py 
new/ansible_core-2.20.6/test/units/module_utils/basic/test_run_command.py
--- old/ansible_core-2.20.5/test/units/module_utils/basic/test_run_command.py   
2026-04-21 02:44:49.000000000 +0200
+++ new/ansible_core-2.20.6/test/units/module_utils/basic/test_run_command.py   
2026-05-18 21:15:21.000000000 +0200
@@ -255,3 +255,81 @@
 
     assert subprocess_mock.Popen.call_args[1]['pass_fds'] == (101, 42)
     assert subprocess_mock.Popen.call_args[1]['close_fds'] is True
+
+
+class TestRunCommandNoneRead:
+    """
+    Test handling of read() returning None from non-blocking pipes.
+
+    This tests the fix for issue #86920 where read() can return None
+    in certain edge cases with non-blocking I/O, which would cause
+    TypeError when trying to concatenate None to bytes.
+    """
+
+    class NoneReturningBytesIO(SpecialBytesIO):
+        """
+        BytesIO that returns None on first read, then actual data.
+
+        This simulates edge cases where non-blocking read() returns None
+        to indicate "no data available right now" rather than empty bytes.
+        """
+
+        def __init__(self, *args, **kwargs):
+            # Pop 'data' before calling super().__init__() since BytesIO 
doesn't accept it
+            self.data = kwargs.pop('data', b'test output')
+            self.read_count = 0
+            super(TestRunCommandNoneRead.NoneReturningBytesIO, 
self).__init__(*args, **kwargs)
+
+        def read(self, size=-1):
+            self.read_count += 1
+            if self.read_count == 1:
+                # First read returns None (no data available)
+                return None
+            elif self.read_count == 2:
+                # Second read returns actual data
+                return self.data
+            else:
+                # Subsequent reads return empty bytes (EOF)
+                return b''
+
+    @pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])
+    def test_none_from_stdout_read(self, mocker, rc_am):
+        """Test that None returned from stdout.read() doesn't cause 
TypeError."""
+        rc_am._subprocess._output = {
+            mocker.sentinel.stdout:
+                self.NoneReturningBytesIO(fh=mocker.sentinel.stdout, 
data=b'command output'),
+            mocker.sentinel.stderr:
+                SpecialBytesIO(b'', fh=mocker.sentinel.stderr)
+        }
+        (rc, stdout, stderr) = rc_am.run_command('/bin/test')
+        assert rc == 0
+        assert stdout == 'command output'
+        assert stderr == ''
+
+    @pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])
+    def test_none_from_stderr_read(self, mocker, rc_am):
+        """Test that None returned from stderr.read() doesn't cause 
TypeError."""
+        rc_am._subprocess._output = {
+            mocker.sentinel.stdout:
+                SpecialBytesIO(b'', fh=mocker.sentinel.stdout),
+            mocker.sentinel.stderr:
+                self.NoneReturningBytesIO(fh=mocker.sentinel.stderr, 
data=b'error output')
+        }
+        (rc, stdout, stderr) = rc_am.run_command('/bin/test')
+        assert rc == 0
+        assert stdout == ''
+        assert stderr == 'error output'
+
+    @pytest.mark.parametrize('stdin', [{}], indirect=['stdin'])
+    def test_none_from_both_pipes(self, mocker, rc_am):
+        """Test that None returned from both pipes doesn't cause TypeError."""
+        rc_am._subprocess._output = {
+            mocker.sentinel.stdout:
+                self.NoneReturningBytesIO(fh=mocker.sentinel.stdout, 
data=b'stdout data'),
+            mocker.sentinel.stderr:
+                self.NoneReturningBytesIO(fh=mocker.sentinel.stderr, 
data=b'stderr data')
+        }
+        (rc, stdout, stderr) = rc_am.run_command('/bin/test')
+        assert rc == 0
+        assert stdout == 'stdout data'
+        assert stderr == 'stderr data'

++++++ ansible_core-2.20.5.tar.gz.sha256 -> ansible_core-2.20.6.tar.gz.sha256 
++++++
--- /work/SRC/openSUSE:Factory/ansible-core/ansible_core-2.20.5.tar.gz.sha256   
2026-04-21 12:47:41.229558453 +0200
+++ 
/work/SRC/openSUSE:Factory/.ansible-core.new.1966/ansible_core-2.20.6.tar.gz.sha256
 2026-05-19 17:50:59.602183122 +0200
@@ -1 +1 @@
-82e3049d95e6e02e5d20d4a5a8e10533a55e0cc52e878e4cf77166c45410f16f  
ansible_core-2.20.5.tar.gz
+3066c430e8cba46777bf736ebcd085c90b0d7664c3fbd8c5b85227f8579cdcbf  
ansible_core-2.20.6.tar.gz

Reply via email to