Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58c6a5e8ef |
5 changed files with 557 additions and 22 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -85,5 +85,5 @@
|
|||
/ansible-documentation-2.18.9.tar.gz
|
||||
/ansible-core-2.18.11.tar.gz
|
||||
/ansible-documentation-2.18.11.tar.gz
|
||||
/ansible-core-2.20.1.tar.gz
|
||||
/ansible-documentation-2.20.1.tar.gz
|
||||
/ansible-core-2.18.12.tar.gz
|
||||
/ansible-documentation-2.18.12.tar.gz
|
||||
|
|
|
|||
348
0001-dnf5-apt-add-auto_install_module_deps-option-84292.patch
Normal file
348
0001-dnf5-apt-add-auto_install_module_deps-option-84292.patch
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
From 9c9f20128efdf041a093f0de37fc316c6ec18b66 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Krizek <martin.krizek@gmail.com>
|
||||
Date: Thu, 21 Nov 2024 17:06:18 +0100
|
||||
Subject: [PATCH 1/2] dnf5,apt: add auto_install_module_deps option (#84292)
|
||||
|
||||
* dnf5,apt: add auto_install_module_deps option
|
||||
|
||||
Fixes #84206
|
||||
|
||||
(cherry picked from commit 2a53b851fee8ebaa07c1341122dd905354659237)
|
||||
---
|
||||
...4206-dnf5-apt-auto-install-module-deps.yml | 2 +
|
||||
lib/ansible/modules/apt.py | 90 +++++++++++--------
|
||||
lib/ansible/modules/dnf5.py | 52 ++++++++---
|
||||
test/integration/targets/apt/tasks/apt.yml | 28 ++++--
|
||||
test/integration/targets/dnf5/playbook.yml | 21 ++++-
|
||||
5 files changed, 133 insertions(+), 60 deletions(-)
|
||||
create mode 100644 changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml
|
||||
|
||||
diff --git a/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml b/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml
|
||||
new file mode 100644
|
||||
index 0000000000..14d595449c
|
||||
--- /dev/null
|
||||
+++ b/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml
|
||||
@@ -0,0 +1,2 @@
|
||||
+minor_changes:
|
||||
+ - dnf5, apt - add ``auto_install_module_deps`` option (https://github.com/ansible/ansible/issues/84206)
|
||||
diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py
|
||||
index 70a2a07cc0..c18bd36fe4 100644
|
||||
--- a/lib/ansible/modules/apt.py
|
||||
+++ b/lib/ansible/modules/apt.py
|
||||
@@ -17,6 +17,12 @@ description:
|
||||
- Manages I(apt) packages (such as for Debian/Ubuntu).
|
||||
version_added: "0.0.2"
|
||||
options:
|
||||
+ auto_install_module_deps:
|
||||
+ description:
|
||||
+ - Automatically install dependencies required to run this module.
|
||||
+ type: bool
|
||||
+ default: yes
|
||||
+ version_added: 2.19
|
||||
name:
|
||||
description:
|
||||
- A list of package names, like V(foo), or package specifier with version, like V(foo=1.0) or V(foo>=1.0).
|
||||
@@ -191,8 +197,7 @@ options:
|
||||
default: 60
|
||||
version_added: "2.12"
|
||||
requirements:
|
||||
- - python-apt (python 2)
|
||||
- - python3-apt (python 3)
|
||||
+ - python3-apt
|
||||
- aptitude (before 2.4)
|
||||
author: "Matthew Williams (@mgwilliams)"
|
||||
extends_documentation_fragment: action_common_attributes
|
||||
@@ -214,8 +219,8 @@ notes:
|
||||
- When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the O(name) option.
|
||||
- When O(default_release) is used, an implicit priority of 990 is used. This is the same behavior as C(apt-get -t).
|
||||
- When an exact version is specified, an implicit priority of 1001 is used.
|
||||
- - If the interpreter can't import C(python-apt)/C(python3-apt) the module will check for it in system-owned interpreters as well.
|
||||
- If the dependency can't be found, the module will attempt to install it.
|
||||
+ - If the interpreter can't import C(python3-apt) the module will check for it in system-owned interpreters as well.
|
||||
+ If the dependency can't be found, depending on the value of O(auto_install_module_deps) the module will attempt to install it.
|
||||
If the dependency is found or installed, the module will be respawned under the correct interpreter.
|
||||
'''
|
||||
|
||||
@@ -1233,6 +1238,7 @@ def main():
|
||||
allow_downgrade=dict(type='bool', default=False, aliases=['allow-downgrade', 'allow_downgrades', 'allow-downgrades']),
|
||||
allow_change_held_packages=dict(type='bool', default=False),
|
||||
lock_timeout=dict(type='int', default=60),
|
||||
+ auto_install_module_deps=dict(type='bool', default=True),
|
||||
),
|
||||
mutually_exclusive=[['deb', 'package', 'upgrade']],
|
||||
required_one_of=[['autoremove', 'deb', 'package', 'update_cache', 'upgrade']],
|
||||
@@ -1268,7 +1274,7 @@ def main():
|
||||
if not HAS_PYTHON_APT:
|
||||
# This interpreter can't see the apt Python library- we'll do the following to try and fix that:
|
||||
# 1) look in common locations for system-owned interpreters that can see it; if we find one, respawn under it
|
||||
- # 2) finding none, try to install a matching python-apt package for the current interpreter version;
|
||||
+ # 2) finding none, try to install a matching python3-apt package for the current interpreter version;
|
||||
# we limit to the current interpreter version to try and avoid installing a whole other Python just
|
||||
# for apt support
|
||||
# 3) if we installed a support package, try to respawn under what we think is the right interpreter (could be
|
||||
@@ -1294,39 +1300,47 @@ def main():
|
||||
|
||||
# don't make changes if we're in check_mode
|
||||
if module.check_mode:
|
||||
- module.fail_json(msg="%s must be installed to use check mode. "
|
||||
- "If run normally this module can auto-install it." % apt_pkg_name)
|
||||
-
|
||||
- # We skip cache update in auto install the dependency if the
|
||||
- # user explicitly declared it with update_cache=no.
|
||||
- if module.params.get('update_cache') is False:
|
||||
- module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name)
|
||||
- else:
|
||||
- module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name)
|
||||
- module.run_command([APT_GET_CMD, 'update'], check_rc=True)
|
||||
-
|
||||
- # try to install the apt Python binding
|
||||
- apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options]
|
||||
-
|
||||
- if install_recommends is False:
|
||||
- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"])
|
||||
- elif install_recommends is True:
|
||||
- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"])
|
||||
- # install_recommends is None uses the OS default
|
||||
-
|
||||
- module.run_command(apt_pkg_cmd, check_rc=True)
|
||||
-
|
||||
- # try again to find the bindings in common places
|
||||
- interpreter = probe_interpreters_for_module(interpreters, 'apt')
|
||||
-
|
||||
- if interpreter:
|
||||
- # found the Python bindings; respawn this module under the interpreter where we found them
|
||||
- # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
|
||||
- respawn_module(interpreter)
|
||||
- # this is the end of the line for this process, it will exit here once the respawned module has completed
|
||||
- else:
|
||||
- # we've done all we can do; just tell the user it's busted and get out
|
||||
- module.fail_json(msg="{0} must be installed and visible from {1}.".format(apt_pkg_name, sys.executable))
|
||||
+ module.fail_json(
|
||||
+ msg=f"{apt_pkg_name} must be installed to use check mode. "
|
||||
+ "If run normally this module can auto-install it, "
|
||||
+ "see the auto_install_module_deps option.",
|
||||
+ )
|
||||
+ elif p['auto_install_module_deps']:
|
||||
+ # We skip cache update in auto install the dependency if the
|
||||
+ # user explicitly declared it with update_cache=no.
|
||||
+ if module.params.get('update_cache') is False:
|
||||
+ module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name)
|
||||
+ else:
|
||||
+ module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name)
|
||||
+ module.run_command([APT_GET_CMD, 'update'], check_rc=True)
|
||||
+
|
||||
+ # try to install the apt Python binding
|
||||
+ apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options]
|
||||
+
|
||||
+ if install_recommends is False:
|
||||
+ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"])
|
||||
+ elif install_recommends is True:
|
||||
+ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"])
|
||||
+ # install_recommends is None uses the OS default
|
||||
+
|
||||
+ module.run_command(apt_pkg_cmd, check_rc=True)
|
||||
+
|
||||
+ # try again to find the bindings in common places
|
||||
+ interpreter = probe_interpreters_for_module(interpreters, 'apt')
|
||||
+
|
||||
+ if interpreter:
|
||||
+ # found the Python bindings; respawn this module under the interpreter where we found them
|
||||
+ # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
|
||||
+ respawn_module(interpreter)
|
||||
+ # this is the end of the line for this process, it will exit here once the respawned module has completed
|
||||
+
|
||||
+ # we've done all we can do; just tell the user it's busted and get out
|
||||
+ py_version = sys.version.replace("\n", "")
|
||||
+ module.fail_json(
|
||||
+ msg=f"Could not import the {apt_pkg_name} module using {sys.executable} ({py_version}). "
|
||||
+ f"Ensure {apt_pkg_name} package is installed (either manually or via the auto_install_module_deps option) "
|
||||
+ f"or that you have specified the correct ansible_python_interpreter. (attempted {interpreters}).",
|
||||
+ )
|
||||
|
||||
if p['clean'] is True:
|
||||
aptclean_stdout, aptclean_stderr, aptclean_diff = aptclean(module)
|
||||
diff --git a/lib/ansible/modules/dnf5.py b/lib/ansible/modules/dnf5.py
|
||||
index 24ae91432b..a0e4a4ef5a 100644
|
||||
--- a/lib/ansible/modules/dnf5.py
|
||||
+++ b/lib/ansible/modules/dnf5.py
|
||||
@@ -14,6 +14,12 @@ description:
|
||||
provides are implemented in M(ansible.builtin.dnf5), please consult specific options for more information."
|
||||
short_description: Manages packages with the I(dnf5) package manager
|
||||
options:
|
||||
+ auto_install_module_deps:
|
||||
+ description:
|
||||
+ - Automatically install dependencies required to run this module.
|
||||
+ type: bool
|
||||
+ default: yes
|
||||
+ version_added: 2.19
|
||||
name:
|
||||
description:
|
||||
- "A package name or package specifier with version, like C(name-1.0).
|
||||
@@ -246,6 +252,10 @@ attributes:
|
||||
platforms: rhel
|
||||
requirements:
|
||||
- "python3-libdnf5"
|
||||
+notes:
|
||||
+ - If the interpreter can't import C(python3-libdnf5) the module will check for it in system-owned interpreters as well.
|
||||
+ If the dependency can't be found, depending on the value of O(auto_install_module_deps) the module will attempt to install it.
|
||||
+ If the dependency is found or installed, the module will be respawned under the correct interpreter.
|
||||
version_added: 2.15
|
||||
"""
|
||||
|
||||
@@ -474,6 +484,8 @@ def get_unneeded_pkgs(base):
|
||||
class Dnf5Module(YumDnf):
|
||||
def __init__(self, module):
|
||||
super(Dnf5Module, self).__init__(module)
|
||||
+ self.auto_install_module_deps = self.module.params["auto_install_module_deps"]
|
||||
+
|
||||
self._ensure_dnf()
|
||||
|
||||
self.pkg_mgr_name = "dnf5"
|
||||
@@ -530,21 +542,30 @@ class Dnf5Module(YumDnf):
|
||||
]
|
||||
|
||||
if not has_respawned():
|
||||
- # probe well-known system Python locations for accessible bindings, favoring py3
|
||||
- interpreter = probe_interpreters_for_module(system_interpreters, "libdnf5")
|
||||
-
|
||||
- if interpreter:
|
||||
- # respawn under the interpreter where the bindings should be found
|
||||
- respawn_module(interpreter)
|
||||
- # end of the line for this module, the process will exit here once the respawned module completes
|
||||
+ for attempt in (1, 2):
|
||||
+ # probe well-known system Python locations for accessible bindings
|
||||
+ interpreter = probe_interpreters_for_module(system_interpreters, "libdnf5")
|
||||
+ if interpreter:
|
||||
+ # respawn under the interpreter where the bindings should be found
|
||||
+ respawn_module(interpreter)
|
||||
+ # end of the line for this module, the process will exit here once the respawned module completes
|
||||
+ if attempt == 1:
|
||||
+ if self.module.check_mode:
|
||||
+ self.module.fail_json(
|
||||
+ msg="python3-libdnf5 must be installed to use check mode. "
|
||||
+ "If run normally this module can auto-install it, "
|
||||
+ "see the auto_install_module_deps option.",
|
||||
+ )
|
||||
+ elif self.auto_install_module_deps:
|
||||
+ self.module.run_command(["dnf", "install", "-y", "python3-libdnf5"], check_rc=True)
|
||||
+ else:
|
||||
+ break
|
||||
|
||||
- # done all we can do, something is just broken (auto-install isn't useful anymore with respawn, so it was removed)
|
||||
+ py_version = sys.version.replace("\n", "")
|
||||
self.module.fail_json(
|
||||
- msg="Could not import the libdnf5 python module using {0} ({1}). "
|
||||
- "Please install python3-libdnf5 package or ensure you have specified the "
|
||||
- "correct ansible_python_interpreter. (attempted {2})".format(
|
||||
- sys.executable, sys.version.replace("\n", ""), system_interpreters
|
||||
- ),
|
||||
+ msg=f"Could not import the libdnf5 python module using {sys.executable} ({py_version}). "
|
||||
+ "Ensure python3-libdnf5 package is installed (either manually or via the auto_install_module_deps option) "
|
||||
+ f"or that you have specified the correct ansible_python_interpreter. (attempted {system_interpreters}).",
|
||||
failures=[],
|
||||
)
|
||||
|
||||
@@ -795,6 +816,11 @@ class Dnf5Module(YumDnf):
|
||||
|
||||
|
||||
def main():
|
||||
+ yumdnf_argument_spec["argument_spec"].update(
|
||||
+ dict(
|
||||
+ auto_install_module_deps=dict(type="bool", default=True),
|
||||
+ )
|
||||
+ )
|
||||
module = AnsibleModule(**yumdnf_argument_spec)
|
||||
try:
|
||||
Dnf5Module(module).run()
|
||||
diff --git a/test/integration/targets/apt/tasks/apt.yml b/test/integration/targets/apt/tasks/apt.yml
|
||||
index 64e00d3ca9..dda5fc1fab 100644
|
||||
--- a/test/integration/targets/apt/tasks/apt.yml
|
||||
+++ b/test/integration/targets/apt/tasks/apt.yml
|
||||
@@ -8,17 +8,17 @@
|
||||
distro_mirror: http://archive.ubuntu.com/ubuntu
|
||||
when: ansible_distribution == 'Ubuntu'
|
||||
|
||||
-# UNINSTALL 'python-apt'
|
||||
-# The `apt` module has the smarts to auto-install `python-apt(3)`. To test, we
|
||||
-# will first uninstall `python-apt`.
|
||||
-- name: uninstall python-apt with apt
|
||||
+# UNINSTALL 'python3-apt'
|
||||
+# The `apt` module has the smarts to auto-install `python3-apt`. To test, we
|
||||
+# will first uninstall `python3-apt`.
|
||||
+- name: uninstall python3-apt with apt
|
||||
apt:
|
||||
- pkg: [python-apt, python3-apt]
|
||||
+ pkg: python3-apt
|
||||
state: absent
|
||||
purge: yes
|
||||
register: apt_result
|
||||
|
||||
-# In check mode, auto-install of `python-apt` must fail
|
||||
+# In check mode, auto-install of `python3-apt` must fail
|
||||
- name: test fail uninstall hello without required apt deps in check mode
|
||||
apt:
|
||||
pkg: hello
|
||||
@@ -32,13 +32,25 @@
|
||||
assert:
|
||||
that:
|
||||
- apt_result is failed
|
||||
- - '"If run normally this module can auto-install it." in apt_result.msg'
|
||||
+ - '"If run normally this module can auto-install it" in apt_result.msg'
|
||||
|
||||
- name: check with dpkg
|
||||
- shell: dpkg -s python-apt python3-apt
|
||||
+ shell: dpkg -s python3-apt
|
||||
register: dpkg_result
|
||||
ignore_errors: true
|
||||
|
||||
+- name: Test the auto_install_module_deps option
|
||||
+ apt:
|
||||
+ pkg: hello
|
||||
+ auto_install_module_deps: false
|
||||
+ register: r
|
||||
+ ignore_errors: true
|
||||
+
|
||||
+- assert:
|
||||
+ that:
|
||||
+ - r is failed
|
||||
+ - r.msg is contains("Could not import the python3-apt module")
|
||||
+
|
||||
# UNINSTALL 'hello'
|
||||
# With 'python-apt' uninstalled, the first call to 'apt' should install
|
||||
# python-apt without updating the cache.
|
||||
diff --git a/test/integration/targets/dnf5/playbook.yml b/test/integration/targets/dnf5/playbook.yml
|
||||
index d9a79ced7e..a36c17a202 100644
|
||||
--- a/test/integration/targets/dnf5/playbook.yml
|
||||
+++ b/test/integration/targets/dnf5/playbook.yml
|
||||
@@ -1,8 +1,27 @@
|
||||
- hosts: localhost
|
||||
tasks:
|
||||
- block:
|
||||
- - command: dnf install -y python3-libdnf5
|
||||
+ - command: "dnf install -y 'dnf-command(copr)'"
|
||||
+ - name: Test against dnf5 nightly build to detect any issues early
|
||||
+ command: dnf copr enable -y rpmsoftwaremanagement/dnf-nightly
|
||||
|
||||
+ - name: Ensure module deps are not installed
|
||||
+ command: dnf remove -y python3-libdnf5
|
||||
+
|
||||
+ - name: Test the auto_install_module_deps option
|
||||
+ dnf5:
|
||||
+ name: sos
|
||||
+ auto_install_module_deps: false
|
||||
+ register: r
|
||||
+ ignore_errors: true
|
||||
+
|
||||
+ - assert:
|
||||
+ that:
|
||||
+ - r is failed
|
||||
+ - r.msg is contains("Could not import the libdnf5 python module")
|
||||
+
|
||||
+ # Now the first dnf5 task in the dnf role should auto install python3-libdnf5 as
|
||||
+ # auto_install_module_deps is true by default.
|
||||
- include_role:
|
||||
name: dnf
|
||||
vars:
|
||||
--
|
||||
2.50.1
|
||||
|
||||
182
0002-Initial-support-for-Python-3.14.patch
Normal file
182
0002-Initial-support-for-Python-3.14.patch
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
From 36c1e6ff0d889cef5c57af64d4f6fc08b455bada Mon Sep 17 00:00:00 2001
|
||||
From: Maxwell G <maxwell@gtmx.me>
|
||||
Date: Sat, 7 Jun 2025 15:42:53 -0500
|
||||
Subject: [PATCH 2/2] Initial support for Python 3.14
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is a downstream Fedora patch to make ansible-core work with Python
|
||||
3.14 until it is properly supported upstream.
|
||||
Note that parts of ansible-test will not work properly until we update
|
||||
to an version that officially supports Python 3.14 due to missing
|
||||
upstream test infrastructure.
|
||||
|
||||
Co-authored-by: Miro Hrončok <churchyard@fedoraproject.org>
|
||||
---
|
||||
.../_data/requirements/ansible-test.txt | 2 +-
|
||||
.../ansible_test/_internal/coverage_util.py | 2 +-
|
||||
.../_util/target/common/constants.py | 1 +
|
||||
.../module_utils/common/test_collections.py | 6 +-
|
||||
.../test_check_required_arguments.py | 7 +-
|
||||
test/units/modules/test_copy.py | 74 ++++++++++---------
|
||||
6 files changed, 54 insertions(+), 38 deletions(-)
|
||||
|
||||
diff --git a/test/lib/ansible_test/_data/requirements/ansible-test.txt b/test/lib/ansible_test/_data/requirements/ansible-test.txt
|
||||
index 50f951c845..5edd5cc4de 100644
|
||||
--- a/test/lib/ansible_test/_data/requirements/ansible-test.txt
|
||||
+++ b/test/lib/ansible_test/_data/requirements/ansible-test.txt
|
||||
@@ -1,2 +1,2 @@
|
||||
# The test-constraints sanity test verifies this file, but changes must be made manually to keep it in up-to-date.
|
||||
-coverage == 7.6.1 ; python_version >= '3.8' and python_version <= '3.13'
|
||||
+coverage == 7.6.1 ; python_version >= '3.8' and python_version <= '3.14'
|
||||
diff --git a/test/lib/ansible_test/_internal/coverage_util.py b/test/lib/ansible_test/_internal/coverage_util.py
|
||||
index 2bec9c791e..e900ddb801 100644
|
||||
--- a/test/lib/ansible_test/_internal/coverage_util.py
|
||||
+++ b/test/lib/ansible_test/_internal/coverage_util.py
|
||||
@@ -69,7 +69,7 @@ class CoverageVersion:
|
||||
|
||||
COVERAGE_VERSIONS = (
|
||||
# IMPORTANT: Keep this in sync with the ansible-test.txt requirements file.
|
||||
- CoverageVersion('7.6.1', 7, (3, 8), (3, 13)),
|
||||
+ CoverageVersion('7.6.1', 7, (3, 8), (3, 14)),
|
||||
)
|
||||
"""
|
||||
This tuple specifies the coverage version to use for Python version ranges.
|
||||
diff --git a/test/lib/ansible_test/_util/target/common/constants.py b/test/lib/ansible_test/_util/target/common/constants.py
|
||||
index 31f56adcda..4e4055462d 100644
|
||||
--- a/test/lib/ansible_test/_util/target/common/constants.py
|
||||
+++ b/test/lib/ansible_test/_util/target/common/constants.py
|
||||
@@ -14,4 +14,5 @@ CONTROLLER_PYTHON_VERSIONS = (
|
||||
'3.11',
|
||||
'3.12',
|
||||
'3.13',
|
||||
+ '3.14',
|
||||
)
|
||||
diff --git a/test/units/module_utils/common/test_collections.py b/test/units/module_utils/common/test_collections.py
|
||||
index 381d583004..78d7d19dde 100644
|
||||
--- a/test/units/module_utils/common/test_collections.py
|
||||
+++ b/test/units/module_utils/common/test_collections.py
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
+import re
|
||||
+
|
||||
import pytest
|
||||
|
||||
from collections.abc import Sequence
|
||||
@@ -143,7 +145,9 @@ class TestImmutableDict:
|
||||
# ImmutableDict is unhashable when one of its values is unhashable
|
||||
imdict = ImmutableDict({u'café': u'くらとみ', 1: [1, 2]})
|
||||
|
||||
- expected_reason = r"^unhashable type: 'list'$"
|
||||
+ python314_reason = re.escape("cannot use 'tuple' as a set element (unhashable type: 'list')")
|
||||
+ expected_reasons = (r"^unhashable type: 'list'$", rf"^{python314_reason}$")
|
||||
+ expected_reason = "|".join(expected_reasons)
|
||||
|
||||
with pytest.raises(TypeError, match=expected_reason):
|
||||
hash(imdict)
|
||||
diff --git a/test/units/module_utils/common/validation/test_check_required_arguments.py b/test/units/module_utils/common/validation/test_check_required_arguments.py
|
||||
index 16e79fe7dc..761cd0acd1 100644
|
||||
--- a/test/units/module_utils/common/validation/test_check_required_arguments.py
|
||||
+++ b/test/units/module_utils/common/validation/test_check_required_arguments.py
|
||||
@@ -84,4 +84,9 @@ def test_check_required_arguments_missing_none():
|
||||
def test_check_required_arguments_no_params(arguments_terms):
|
||||
with pytest.raises(TypeError) as te:
|
||||
check_required_arguments(arguments_terms, None)
|
||||
- assert "'NoneType' is not iterable" in to_native(te.value)
|
||||
+ value = to_native(te.value)
|
||||
+ options = (
|
||||
+ "'NoneType' is not iterable", # Python < 3.14
|
||||
+ "argument of type 'NoneType' is not a container or iterable" # 3.14+
|
||||
+ )
|
||||
+ assert any(o in value for o in options)
|
||||
diff --git a/test/units/modules/test_copy.py b/test/units/modules/test_copy.py
|
||||
index 6f15bed122..799ba4b52f 100644
|
||||
--- a/test/units/modules/test_copy.py
|
||||
+++ b/test/units/modules/test_copy.py
|
||||
@@ -95,40 +95,46 @@ ONE_DIR_DATA: tuple[tuple[str, tuple[str, list[str]] | None, tuple[str, list[str
|
||||
ONE_DIR_DATA += tuple(item[:3] for item in TWO_DIRS_DATA)
|
||||
|
||||
|
||||
-@pytest.mark.parametrize('directory, expected', ((d[0], d[4]) for d in THREE_DIRS_DATA))
|
||||
-@pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
-def test_split_pre_existing_dir_three_levels_exist(directory, expected, mocker):
|
||||
- mocker.patch('os.path.exists', side_effect=[True, True, True])
|
||||
- assert split_pre_existing_dir(directory) == expected
|
||||
-
|
||||
-
|
||||
-@pytest.mark.parametrize('directory, expected', ((d[0], d[3]) for d in TWO_DIRS_DATA))
|
||||
-@pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
-def test_split_pre_existing_dir_two_levels_exist(directory, expected, mocker):
|
||||
- mocker.patch('os.path.exists', side_effect=[True, True, False])
|
||||
- assert split_pre_existing_dir(directory) == expected
|
||||
-
|
||||
-
|
||||
-@pytest.mark.parametrize('directory, expected', ((d[0], d[2]) for d in ONE_DIR_DATA))
|
||||
-@pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
-def test_split_pre_existing_dir_one_level_exists(directory, expected, mocker):
|
||||
- mocker.patch('os.path.exists', side_effect=[True, False, False])
|
||||
- assert split_pre_existing_dir(directory) == expected
|
||||
-
|
||||
-
|
||||
-@pytest.mark.parametrize('directory', (d[0] for d in ONE_DIR_DATA if d[1] is None))
|
||||
-def test_split_pre_existing_dir_root_does_not_exist(directory, mocker):
|
||||
- mocker.patch('os.path.exists', return_value=False)
|
||||
- with pytest.raises(AnsibleModuleError) as excinfo:
|
||||
- split_pre_existing_dir(directory)
|
||||
- assert excinfo.value.results['msg'].startswith("The '/' directory doesn't exist on this machine.")
|
||||
-
|
||||
-
|
||||
-@pytest.mark.parametrize('directory, expected', ((d[0], d[1]) for d in ONE_DIR_DATA if not d[0].startswith('/')))
|
||||
-@pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
-def test_split_pre_existing_dir_working_dir_exists(directory, expected, mocker):
|
||||
- mocker.patch('os.path.exists', return_value=False)
|
||||
- assert split_pre_existing_dir(directory) == expected
|
||||
+# NOTE(gotmax23): These tests are all broken (marked with xfail) to begin with.
|
||||
+# On Python 3.14, they also cause pytest to crash, as the os.path.exists patch
|
||||
+# does not get cleaned up in time for some reason and other internal pytest
|
||||
+# code calls the mock instead of the actual function.
|
||||
+# Comment them out for now.
|
||||
+
|
||||
+# @pytest.mark.parametrize('directory, expected', ((d[0], d[4]) for d in THREE_DIRS_DATA))
|
||||
+# @pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
+# def test_split_pre_existing_dir_three_levels_exist(directory, expected, mocker):
|
||||
+# mocker.patch('os.path.exists', side_effect=[True, True, True])
|
||||
+# assert split_pre_existing_dir(directory) == expected
|
||||
+#
|
||||
+#
|
||||
+# @pytest.mark.parametrize('directory, expected', ((d[0], d[3]) for d in TWO_DIRS_DATA))
|
||||
+# @pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
+# def test_split_pre_existing_dir_two_levels_exist(directory, expected, mocker):
|
||||
+# mocker.patch('os.path.exists', side_effect=[True, True, False])
|
||||
+# assert split_pre_existing_dir(directory) == expected
|
||||
+#
|
||||
+#
|
||||
+# @pytest.mark.parametrize('directory, expected', ((d[0], d[2]) for d in ONE_DIR_DATA))
|
||||
+# @pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
+# def test_split_pre_existing_dir_one_level_exists(directory, expected, mocker):
|
||||
+# mocker.patch('os.path.exists', side_effect=[True, False, False])
|
||||
+# assert split_pre_existing_dir(directory) == expected
|
||||
+#
|
||||
+#
|
||||
+# @pytest.mark.parametrize('directory', (d[0] for d in ONE_DIR_DATA if d[1] is None))
|
||||
+# def test_split_pre_existing_dir_root_does_not_exist(directory, mocker):
|
||||
+# mocker.patch('os.path.exists', return_value=False)
|
||||
+# with pytest.raises(AnsibleModuleError) as excinfo:
|
||||
+# split_pre_existing_dir(directory)
|
||||
+# assert excinfo.value.results['msg'].startswith("The '/' directory doesn't exist on this machine.")
|
||||
+#
|
||||
+#
|
||||
+# @pytest.mark.parametrize('directory, expected', ((d[0], d[1]) for d in ONE_DIR_DATA if not d[0].startswith('/')))
|
||||
+# @pytest.mark.xfail(reason='broken test and/or code, original test missing assert', strict=False)
|
||||
+# def test_split_pre_existing_dir_working_dir_exists(directory, expected, mocker):
|
||||
+# mocker.patch('os.path.exists', return_value=False)
|
||||
+# assert split_pre_existing_dir(directory) == expected
|
||||
|
||||
|
||||
#
|
||||
--
|
||||
2.50.1
|
||||
|
||||
|
|
@ -13,21 +13,29 @@
|
|||
%undefine _py3_shebang_s
|
||||
|
||||
Name: ansible-core
|
||||
Version: 2.20.1
|
||||
Version: 2.18.12
|
||||
%global uversion %{version_no_tilde %{quote:%nil}}
|
||||
Release: 2%{?dist}
|
||||
Release: 1%{?dist}
|
||||
Summary: A radically simple IT automation system
|
||||
|
||||
# The main license is GPLv3+. Many of the files in lib/ansible/module_utils
|
||||
# are BSD licensed. There are various files scattered throughout the codebase
|
||||
# containing code under different licenses.
|
||||
# The ssh-agent helper code is BSD-3-Clause.
|
||||
License: GPL-3.0-or-later AND BSD-2-Clause AND BSD-3-Clause AND PSF-2.0 AND MIT AND Apache-2.0
|
||||
License: GPL-3.0-or-later AND BSD-2-Clause AND PSF-2.0 AND MIT AND Apache-2.0
|
||||
URL: https://ansible.com
|
||||
|
||||
Source0: https://github.com/ansible/ansible/archive/v%{uversion}/%{name}-%{uversion}.tar.gz
|
||||
Source1: https://github.com/ansible/ansible-documentation/archive/v%{uversion}/ansible-documentation-%{uversion}.tar.gz
|
||||
|
||||
# dnf5,apt: add auto_install_module_deps option (#84292)
|
||||
# https://github.com/ansible/ansible/pull/84292.patch
|
||||
# https://bugzilla.redhat.com/2322751
|
||||
Patch: 0001-dnf5-apt-add-auto_install_module_deps-option-84292.patch
|
||||
# Initial support for Python 3.14
|
||||
# Downstream patch. See comments in patch file.
|
||||
# https://bugzilla.redhat.com/2366307
|
||||
Patch: 0002-Initial-support-for-Python-3.14.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
# Virtual provides for bundled libraries
|
||||
|
|
@ -39,11 +47,14 @@ Provides: bundled(python3dist(distro)) = 1.9.0
|
|||
|
||||
# lib/ansible/module_utils/six/*
|
||||
# SPDX-License-Identifier: MIT
|
||||
Provides: bundled(python3dist(six)) = 1.17.0
|
||||
Provides: bundled(python3dist(six)) = 1.16.0
|
||||
|
||||
# lib/ansible/_internal/_wrapt.py
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
Provides: bundled(python3dist(wrapt)) = 1.17.2
|
||||
Conflicts: ansible <= 2.9.99
|
||||
#
|
||||
# obsoletes/provides for ansible-base
|
||||
#
|
||||
Provides: ansible-base = %{version}-%{release}
|
||||
Obsoletes: ansible-base < 2.10.6-1
|
||||
|
||||
BuildRequires: make
|
||||
BuildRequires: python%{python3_pkgversion}-devel
|
||||
|
|
@ -234,8 +245,8 @@ install -Dpm 0644 licenses/* -t %{buildroot}%{_pkglicensedir}
|
|||
|
||||
%files -f %{pyproject_files}
|
||||
%license COPYING
|
||||
%license %{_pkglicensedir}/{Apache-License,MIT-license,PSF-license,simplified_bsd,BSD-3-Clause}.txt
|
||||
%doc README.md changelogs/CHANGELOG-v2.2?.rst
|
||||
%license %{_pkglicensedir}/{Apache-License,MIT-license,PSF-license,simplified_bsd}.txt
|
||||
%doc README.md changelogs/CHANGELOG-v2.1?.rst
|
||||
%dir %{_sysconfdir}/ansible/
|
||||
%config(noreplace) %{_sysconfdir}/ansible/*
|
||||
%{_bindir}/ansible*
|
||||
|
|
@ -254,14 +265,8 @@ install -Dpm 0644 licenses/* -t %{buildroot}%{_pkglicensedir}
|
|||
|
||||
|
||||
%changelog
|
||||
* Fri Jan 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 2.20.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
|
||||
|
||||
* Tue Dec 09 2025 Maxwell G <maxwell@gtmx.me> - 2.20.1-1
|
||||
- Update to 2.20.1. Fixes rhbz#2382388.
|
||||
- Update bundled() Provides
|
||||
- Remove upstreamed patches
|
||||
- Remove old Provides and Obsoletes for ansible-base and Ansible <= 2.9
|
||||
* Thu Dec 11 2025 Maxwell G <maxwell@gtmx.me> - 2.18.12-1
|
||||
- Update to 2.18.12.
|
||||
|
||||
* Mon Nov 17 2025 Packit <hello@packit.dev> - 2.18.11-1
|
||||
- Update to version 2.18.11
|
||||
|
|
|
|||
4
sources
4
sources
|
|
@ -1,2 +1,2 @@
|
|||
SHA512 (ansible-core-2.20.1.tar.gz) = fa0a4836e3548cd4e432e87b241beb6fb556765699c25b1f3b1c47111a1c44d5ba3244aeb8793408e72ab63564d6e848148becbfb550bd965e466752d7f78229
|
||||
SHA512 (ansible-documentation-2.20.1.tar.gz) = 0dc20cb62280c715e4b06788a5eb2c757c388d0da646a38fc3ab56e38d236ddb0fd7586a567d973e530ed3ed2310ff26542cdb0e1621e0049147dc747e20205b
|
||||
SHA512 (ansible-core-2.18.12.tar.gz) = 9d276f2be553bdd30bc79bb1a4996f2c49f7c64eefc7926a8809b999c6023ed80cae189754caf203b0ebd90a8bb55de6c7489875dca10bad27cf5d944f006f7e
|
||||
SHA512 (ansible-documentation-2.18.12.tar.gz) = 8dda1716f9abc5fa2370f21384a14fc665f21e703aca64c3961f75a9a3cea672a3f99f36dbb798000f8d3c9803e883f60a24d823ce1a6a187cdfbe6d0fdf16c1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue