public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/cobbler] rawhide: Update to 3.3.9
@ 2026-09-01 4:03 Orion Poplawski
0 siblings, 0 replies; only message in thread
From: Orion Poplawski @ 2026-09-01 4:03 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/cobbler
Branch : rawhide
Commit : 22816b82182d74fd8509e110efd2b34be7e0f85e
Author : Orion Poplawski <orion@nwra.com>
Date : 2026-08-31T20:37:26-06:00
Stats : +2/-1012 in 4 file(s)
URL : https://src.fedoraproject.org/rpms/cobbler/c/22816b82182d74fd8509e110efd2b34be7e0f85e?branch=rawhide
Log:
Update to 3.3.9
---
diff --git a/3945.patch b/3945.patch
deleted file mode 100644
index e75c349..0000000
--- a/3945.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 1d83bd29c253ba898ac35683258fec285d5a6529 Mon Sep 17 00:00:00 2001
-From: Orion Poplawski <orion@nwra.com>
-Date: Sat, 4 Oct 2025 19:49:26 -0600
-Subject: [PATCH] Use systemctl is-active --quiet to check status of services
- (fixes #3942)
-
----
- changelog.d/3942.fixed | 1 +
- cobbler/actions/check.py | 2 +-
- 2 files changed, 2 insertions(+), 1 deletion(-)
- create mode 100644 changelog.d/3942.fixed
-
-diff --git a/changelog.d/3942.fixed b/changelog.d/3942.fixed
-new file mode 100644
-index 0000000000..444bdb800a
---- /dev/null
-+++ b/changelog.d/3942.fixed
-@@ -0,0 +1 @@
-+check: Use systemctl is-active --quiet to check the status of services
-diff --git a/cobbler/actions/check.py b/cobbler/actions/check.py
-index b79706aff1..5f6a3fa3bc 100644
---- a/cobbler/actions/check.py
-+++ b/cobbler/actions/check.py
-@@ -142,7 +142,7 @@ def check_service(self, status, which, notes=""):
- status.append("service %s is not running%s" % (which, notes))
- return
- elif utils.is_systemd():
-- return_code = utils.subprocess_call("systemctl status %s > /dev/null 2>/dev/null" % which,
-+ return_code = utils.subprocess_call("systemctl is-active --quiet %s > /dev/null 2>/dev/null" % which,
- shell=True)
- if return_code != 0:
- status.append("service %s is not running%s" % (which, notes))
diff --git a/cobbler-python3.13.patch b/cobbler-python3.13.patch
deleted file mode 100644
index 78847a4..0000000
--- a/cobbler-python3.13.patch
+++ /dev/null
@@ -1,972 +0,0 @@
-diff --git a/changelog.d/3842.fixed b/changelog.d/3842.fixed
-new file mode 100644
-index 00000000..6c6d6313
---- /dev/null
-+++ b/changelog.d/3842.fixed
-@@ -0,0 +1 @@
-+Fix compatibility with Python 3.13
-diff --git a/cobbler/actions/reposync.py b/cobbler/actions/reposync.py
-index c0163350..ec5745fb 100644
---- a/cobbler/actions/reposync.py
-+++ b/cobbler/actions/reposync.py
-@@ -23,9 +23,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- import logging
- import os
- import os.path
--import pipes
--import stat
-+import shlex
- import shutil
-+import stat
- from typing import Optional, Union
-
- from cobbler import utils
-@@ -272,9 +272,9 @@ class RepoSync:
- blended = utils.blender(self.api, False, repo)
- flags = blended.get("createrepo_flags", "(ERROR: FLAGS)")
- try:
-- cmd = "createrepo %s %s %s" % (" ".join(mdoptions), flags, pipes.quote(dirname))
-- utils.subprocess_call(cmd)
-- except:
-+ cmd = ["createrepo"] + mdoptions + flags + [shlex.quote(dirname)]
-+ utils.subprocess_call(cmd, shell=False)
-+ except Exception:
- utils.log_exc()
- self.logger.error("createrepo failed.")
- del fnames[:] # we're in the right place
-@@ -302,8 +302,19 @@ class RepoSync:
- dest_path = os.path.join(self.settings.webdir, "repo_mirror", repo.name)
-
- # FIXME: wrapper for subprocess that logs to logger
-- cmd = ["wget", "-N", "-np", "-r", "-l", "inf", "-nd", "-P", pipes.quote(dest_path), pipes.quote(repo.mirror)]
-- rc = utils.subprocess_call(cmd)
-+ cmd = [
-+ "wget",
-+ "-N",
-+ "-np",
-+ "-r",
-+ "-l",
-+ "inf",
-+ "-nd",
-+ "-P",
-+ shlex.quote(dest_path),
-+ shlex.quote(repo.mirror),
-+ ]
-+ return_value = utils.subprocess_call(cmd, shell=False)
-
- if rc != 0:
- raise CX("cobbler reposync failed")
-@@ -347,9 +358,14 @@ class RepoSync:
- if flags == '':
- flags = self.settings.reposync_rsync_flags
-
-- cmd = "rsync %s --delete-after %s --delete --exclude-from=/etc/cobbler/rsync.exclude %s %s" \
-- % (flags, spacer, pipes.quote(repo.mirror), pipes.quote(dest_path))
-- rc = utils.subprocess_call(cmd)
-+ cmd = ["rsync"] + flags + ["--delete-after"]
-+ cmd += spacer + [
-+ "--delete",
-+ "--exclude-from=/etc/cobbler/rsync.exclude",
-+ shlex.quote(repo.mirror),
-+ shlex.quote(dest_path),
-+ ]
-+ return_code = utils.subprocess_call(cmd, shell=False)
-
- if rc != 0:
- raise CX("cobbler reposync failed")
-@@ -386,10 +402,11 @@ class RepoSync:
- if not HAS_LIBREPO:
- raise CX("no librepo found, please install python3-librepo")
-
-- if os.path.exists("/usr/bin/dnf"):
-- cmd = "/usr/bin/dnf reposync"
-- elif os.path.exists("/usr/bin/reposync"):
-- cmd = "/usr/bin/reposync"
-+ if os.path.exists("/usr/bin/reposync"):
-+ cmd = ["/usr/bin/reposync"]
-+ # DNF5 does not have a reposync subcommand
-+ elif os.path.exists("/usr/bin/dnf"):
-+ cmd = ["/usr/bin/dnf", "reposync"]
- else:
- # Warn about not having yum-utils. We don't want to require it in the package because Fedora 22+ has moved
- # to dnf.
-@@ -451,6 +468,11 @@ class RepoSync:
- # Counter-intuitive, but we want the newish kernels too
- arch = "i686"
-
-+ cmd = self.reposync_cmd()
-+ cmd += self.rflags + [
-+ f"--repo={shlex.quote(rest)}",
-+ f"--download-path={shlex.quote(repos_path)}",
-+ ]
- if arch != "none":
- cmd = "%s -a %s" % (cmd, arch)
-
-@@ -544,9 +566,11 @@ class RepoSync:
-
- if not has_rpm_list:
- # If we have not requested only certain RPMs, use reposync
-- cmd = "%s %s --config=%s --repoid=%s -p %s" \
-- % (cmd, self.rflags, temp_file, pipes.quote(repo.name),
-- pipes.quote(repos_path))
-+ cmd += self.rflags + [
-+ f"--config={temp_file}",
-+ f"--repoid={shlex.quote(repo.name)}",
-+ f"--download-path={shlex.quote(repos_path)}",
-+ ]
- if arch != "none":
- cmd = "%s -a %s" % (cmd, arch)
-
-@@ -557,14 +581,14 @@ class RepoSync:
-
- use_source = ""
- if arch == "src":
-- use_source = "--source"
--
-- # Older yumdownloader sometimes explodes on --resolvedeps if this happens to you, upgrade yum & yum-utils
-- extra_flags = self.settings.yumdownloader_flags
-- cmd = "/usr/bin/dnf download"
-- cmd = "%s %s %s --disablerepo=* --enablerepo=%s -c %s --destdir=%s %s" \
-- % (cmd, extra_flags, use_source, pipes.quote(repo.name), temp_file, pipes.quote(dest_path),
-- " ".join(repo.rpm_list))
-+ cmd.append("--source")
-+ cmd += [
-+ "--disablerepo=*",
-+ f"--enablerepo={shlex.quote(repo.name)}",
-+ f"-c={temp_file}",
-+ f"--destdir={shlex.quote(dest_path)}",
-+ ]
-+ cmd += repo.rpm_list
-
- # Now regardless of whether we're doing yumdownloader or reposync or whether the repo was http://, ftp://, or
- # rhn://, execute all queued commands here. Any failure at any point stops the operation.
-@@ -669,17 +693,21 @@ class RepoSync:
- dists = ",".join(repo.apt_dists)
- components = ",".join(repo.apt_components)
-
-- mirror_data = "--method=%s --host=%s --root=%s --dist=%s --section=%s" \
-- % (pipes.quote(method), pipes.quote(host), pipes.quote(mirror), pipes.quote(dists),
-- pipes.quote(components))
-+ mirror_data = [
-+ f"--method={shlex.quote(method)}",
-+ f"--host={shlex.quote(host)}",
-+ f"--root={shlex.quote(mirror)}",
-+ f"--dist={shlex.quote(dists)}",
-+ f"--section={shlex.quote(components)}",
-+ ]
-
- rflags = "--nocleanup"
- for x in repo.yumopts:
- if repo.yumopts[x]:
- rflags += " %s=%s" % (x, repo.yumopts[x])
- else:
-- rflags += " %s" % x
-- cmd = "%s %s %s %s" % (mirror_program, rflags, mirror_data, pipes.quote(dest_path))
-+ rflags.append(repo_yumoption)
-+ cmd = [mirror_program] + rflags + mirror_data + [shlex.quote(dest_path)]
- if repo.arch == RepoArchs.SRC:
- cmd = "%s --source" % cmd
- else:
-diff --git a/tests/actions/reposync_test.py b/tests/actions/reposync_test.py
-index 0bee772c..ee8d1549 100644
---- a/tests/actions/reposync_test.py
-+++ b/tests/actions/reposync_test.py
-@@ -1,251 +1,592 @@
-+"""
-+Tests that validate the functionality of the module that is responsible for repository synchronization.
-+"""
-+
- import os
--import glob
-+from pathlib import Path
-+from typing import TYPE_CHECKING, Any, Dict, List, Union
-
- import pytest
-
--from cobbler import enums
-+from cobbler import cexceptions, enums
-+from cobbler.actions import reposync
- from cobbler.api import CobblerAPI
--from cobbler.actions.reposync import RepoSync
- from cobbler.items.repo import Repo
--from cobbler import cexceptions
--from tests.conftest import does_not_raise
-
-+from tests.conftest import does_not_raise
-
--@pytest.fixture(scope="class")
--def api():
-- return CobblerAPI()
-+if TYPE_CHECKING:
-+ from pytest_mock import MockerFixture
-
-
--@pytest.fixture(scope="class")
--def reposync(api):
-- test_reposync = RepoSync(api, tries=2, nofail=False)
-+@pytest.fixture(name="reposync_object", scope="function")
-+def fixture_reposync_object(
-+ mocker: "MockerFixture", cobbler_api: CobblerAPI
-+) -> reposync.RepoSync:
-+ settings_mock = mocker.MagicMock()
-+ settings_mock.webdir = "/srv/www/cobbler"
-+ settings_mock.server = "localhost"
-+ settings_mock.http_port = 80
-+ settings_mock.proxy_url_ext = ""
-+ settings_mock.yumdownloader_flags = "--testflag"
-+ settings_mock.reposync_rsync_flags = "--testflag"
-+ settings_mock.reposync_flags = "--testflag"
-+ mocker.patch.object(cobbler_api, "settings", return_value=settings_mock)
-+ test_reposync = reposync.RepoSync(cobbler_api, tries=2, nofail=False)
- return test_reposync
-
-
--@pytest.fixture
--def repo(api):
-+@pytest.fixture(name="repo")
-+def fixture_repo(cobbler_api: CobblerAPI) -> Repo:
- """
- Creates a Repository "testrepo0" with a keep_updated=True and mirror_locally=True".
- """
-- test_repo = Repo(api)
-+ test_repo = Repo(cobbler_api)
- test_repo.name = "testrepo0"
- test_repo.mirror_locally = True
- test_repo.keep_updated = True
-- api.add_repo(test_repo)
- return test_repo
-
-
- @pytest.fixture
--def remove_repo(api):
-+def remove_repo(cobbler_api: CobblerAPI):
- """
- Removes the Repository "testrepo0" which can be created with repo.
- """
- yield
-- test_repo = api.find_repo("testrepo0")
-- if test_repo is not None:
-- api.remove_repo(test_repo.name)
-+ test_repo = cobbler_api.find_repo("testrepo0")
-+ if test_repo is not None and not isinstance(test_repo, list):
-+ cobbler_api.remove_repo(test_repo.name)
-
-
--class TestRepoSync:
-- @pytest.mark.usefixtures("remove_repo")
-- @pytest.mark.parametrize(
-- "input_mirror_type,input_mirror,expected_exception",
-- [
-- (
-- enums.MirrorType.BASEURL,
-- "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os",
-- does_not_raise()
-- ),
-- (
-- enums.MirrorType.MIRRORLIST,
-- "https://mirrors.fedoraproject.org/mirrorlist?repo=rawhide&arch=x86_64",
-- does_not_raise()
-- ),
-- (
-- enums.MirrorType.METALINK,
-- "https://mirrors.fedoraproject.org/metalink?repo=rawhide&arch=x86_64",
-- does_not_raise()
-- ),
-- (
-- enums.MirrorType.BASEURL,
-- "http://www.example.com/path/to/some/repo",
-- pytest.raises(cexceptions.CX)
-- ),
-+@pytest.fixture(scope="function", autouse=True)
-+def reset_librepo():
-+ has_librepo = reposync.HAS_LIBREPO
-+ yield
-+ reposync.HAS_LIBREPO = has_librepo
-+
-+
-+def test_repo_walker(mocker: "MockerFixture", tmp_path: Path):
-+ # Arrange
-+ def test_fun(arg: Any, top: Any, names: Any):
-+ pass
-+
-+ subdir1 = tmp_path / "sub1"
-+ subdir2 = tmp_path / "sub2"
-+ subdir1.mkdir()
-+ subdir2.mkdir()
-+ spy = mocker.Mock(wraps=test_fun)
-+
-+ # Act
-+ reposync.repo_walker(tmp_path, spy, None) # type: ignore
-+
-+ # Assert
-+ assert spy.mock_calls == [
-+ # settings.yaml is here because of our autouse fixture that we use to restore the settings
-+ mocker.call(None, tmp_path, ["settings.yaml", "sub1", "sub2"]),
-+ mocker.call(None, str(subdir1), []),
-+ mocker.call(None, str(subdir2), []),
-+ ]
-+
-+
-+@pytest.mark.parametrize(
-+ "input_has_librepo,input_path_exists_side_effect,expected_exception,expected_result",
-+ [
-+ (True, [False, True], does_not_raise(), ["/usr/bin/dnf", "reposync"]),
-+ (True, [True, False], does_not_raise(), ["/usr/bin/reposync"]),
-+ (True, [False, False], pytest.raises(cexceptions.CX), ""),
-+ (False, [False, True], pytest.raises(cexceptions.CX), ""),
-+ ],
-+)
-+def test_reposync_cmd(
-+ mocker: "MockerFixture",
-+ reposync_object: reposync.RepoSync,
-+ input_has_librepo: bool,
-+ input_path_exists_side_effect: List[bool],
-+ expected_exception: Any,
-+ expected_result: Union[List[str], str],
-+):
-+ # Arrange
-+ mocker.patch("os.path.exists", side_effect=input_path_exists_side_effect)
-+ reposync.HAS_LIBREPO = input_has_librepo
-+
-+ # Act
-+ with expected_exception:
-+ result = reposync_object.reposync_cmd()
-+
-+ # Assert
-+ assert result == expected_result
-+
-+
-+def test_run(mocker: "MockerFixture", reposync_object: reposync.RepoSync, repo: Repo):
-+ # Arrange
-+ env_vars: Dict[str, Any] = {}
-+ mocker.patch("os.makedirs")
-+ mocker.patch("os.path.isdir", return_value=True)
-+ mocker.patch(
-+ "os.path.join",
-+ side_effect=[
-+ "/srv/www/cobbler/repo_mirror",
-+ "/srv/www/cobbler/repo_mirror/%s" % repo.name,
- ],
- )
-- def test_reposync_yum(
-- self,
-- input_mirror_type,
-- input_mirror,
-- expected_exception,
-- api,
-- repo,
-- reposync
-- ):
-- # Arrange
-- test_repo = repo
-- test_repo.breed = enums.RepoBreeds.YUM
-- test_repo.mirror = input_mirror
-- test_repo.mirror_type = input_mirror_type
-- test_repo.rpm_list = "fedora-gpg-keys"
-- test_settings = api.settings()
-- repo_path = os.path.join(test_settings.webdir, "repo_mirror", test_repo.name)
--
-- # Act & Assert
-- with expected_exception:
-- reposync.run(test_repo.name)
-- result = os.path.exists(repo_path)
-- if test_repo.rpm_list and test_repo.rpm_list != []:
-- for rpm in test_repo.rpm_list:
-- assert glob.glob(os.path.join(repo_path, "**", rpm) + "*.rpm", recursive=True) != []
-- assert result
-- # Test that re-downloading the metadata in .origin/repodata will not result in an error
-- reposync.run(test_repo.name)
--
-- @pytest.mark.usefixtures("remove_repo")
-- @pytest.mark.parametrize(
-- "input_mirror_type,input_mirror,input_arch,input_rpm_list,expected_exception",
-+ mocker.patch("os.environ", return_value=env_vars)
-+ mocker.patch.object(reposync_object, "repos", return_value=[repo])
-+ mocker.patch.object(reposync_object, "sync")
-+ mocker.patch.object(reposync_object, "update_permissions")
-+ reposync_object.repos = [repo] # type: ignore
-+
-+ # Act
-+ reposync_object.run()
-+
-+ # Assert
-+ # This has to be 0 since all env vars need to be removed after reposync has run.
-+ assert len(env_vars) == 0
-+
-+
-+def test_gen_urlgrab_ssl_opts(reposync_object: reposync.RepoSync):
-+ # Arrange
-+ input_dict: Dict[str, Any] = {}
-+
-+ # Act
-+ result = reposync_object.gen_urlgrab_ssl_opts(input_dict)
-+
-+ # Assert
-+ assert isinstance(result, tuple)
-+ assert len(result) == 2
-+ # The data of the first element is kind of flexible let's skip asserting it for now
-+ assert isinstance(result[1], bool)
-+
-+
-+@pytest.mark.usefixtures("remove_repo")
-+@pytest.mark.parametrize(
-+ "input_mirror_type,input_mirror,expected_exception",
-+ [
-+ (
-+ enums.MirrorType.BASEURL,
-+ "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os",
-+ does_not_raise(),
-+ ),
-+ (
-+ enums.MirrorType.MIRRORLIST,
-+ "https://mirrors.fedoraproject.org/mirrorlist?repo=rawhide&arch=x86_64",
-+ does_not_raise(),
-+ ),
-+ (
-+ enums.MirrorType.METALINK,
-+ "https://mirrors.fedoraproject.org/metalink?repo=rawhide&arch=x86_64",
-+ does_not_raise(),
-+ ),
-+ ],
-+)
-+def test_reposync_yum(
-+ mocker: "MockerFixture",
-+ input_mirror_type: enums.MirrorType,
-+ input_mirror: str,
-+ expected_exception: Any,
-+ cobbler_api: CobblerAPI,
-+ repo: Repo,
-+ reposync_object: reposync.RepoSync,
-+):
-+ # Arrange
-+ test_repo = repo
-+ test_repo.breed = enums.RepoBreeds.YUM
-+ test_repo.mirror = input_mirror
-+ test_repo.mirror_type = input_mirror_type
-+ test_repo.rpm_list = "fedora-gpg-keys"
-+ test_settings = cobbler_api.settings()
-+ repo_path = os.path.join(test_settings.webdir, "repo_mirror", test_repo.name)
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ mocker.patch.object(
-+ reposync_object, "create_local_file", return_value="/create/local/file"
-+ )
-+ mocker.patch.object(
-+ reposync_object, "reposync_cmd", return_value=["/my/fake/dnf", "reposync"]
-+ )
-+ mocker.patch.object(reposync_object, "rflags", return_value="--fake-r-flakg")
-+ mocker.patch.object(
-+ reposync_object,
-+ "gen_urlgrab_ssl_opts",
-+ return_value=(("TODO", "TODO", "TODO"), False),
-+ )
-+ mocker.patch("os.path.exists", return_value=True)
-+ mocker.patch("shutil.rmtree")
-+ mocker.patch("os.makedirs")
-+ mocked_repo_walker = mocker.patch("cobbler.actions.reposync.repo_walker")
-+ handle_mock = mocker.MagicMock()
-+ result_mock = mocker.MagicMock()
-+ mocker.patch("librepo.Handle", return_value=handle_mock)
-+ mocker.patch("librepo.Result", return_value=result_mock)
-+
-+ # Act & Assert
-+ with expected_exception:
-+ reposync_object.yum_sync(repo)
-+
-+ mocked_subprocess.assert_called_with(
-+ [
-+ "/usr/bin/dnf",
-+ "download",
-+ "--testflag",
-+ "--disablerepo=*",
-+ f"--enablerepo={repo.name}",
-+ "-c=/create/local/file",
-+ f"--destdir={repo_path}",
-+ "fedora-gpg-keys",
-+ ],
-+ shell=False,
-+ )
-+ handle_mock.perform.assert_called_with(result_mock)
-+ assert mocked_repo_walker.call_count == 1
-+
-+
-+@pytest.mark.usefixtures("remove_repo")
-+@pytest.mark.parametrize(
-+ "input_mirror_type,input_mirror,input_arch,input_rpm_list,expected_exception",
-+ [
-+ (
-+ enums.MirrorType.BASEURL,
-+ "http://ftp.debian.org/debian",
-+ enums.RepoArchs.X86_64,
-+ "",
-+ does_not_raise(),
-+ ),
-+ (
-+ enums.MirrorType.MIRRORLIST,
-+ "http://ftp.debian.org/debian",
-+ enums.RepoArchs.X86_64,
-+ "",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ (
-+ enums.MirrorType.METALINK,
-+ "http://ftp.debian.org/debian",
-+ enums.RepoArchs.X86_64,
-+ "",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ (
-+ enums.MirrorType.BASEURL,
-+ "http://ftp.debian.org/debian",
-+ enums.RepoArchs.NONE,
-+ "",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ (
-+ enums.MirrorType.BASEURL,
-+ "http://ftp.debian.org/debian",
-+ enums.RepoArchs.X86_64,
-+ "dpkg",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ ],
-+)
-+def test_reposync_apt(
-+ mocker: "MockerFixture",
-+ input_mirror_type: enums.MirrorType,
-+ input_mirror: str,
-+ input_arch: enums.RepoArchs,
-+ input_rpm_list: str,
-+ expected_exception: Any,
-+ cobbler_api: CobblerAPI,
-+ repo: Repo,
-+ reposync_object: reposync.RepoSync,
-+):
-+ # Arrange
-+ test_repo = repo
-+ test_repo.breed = enums.RepoBreeds.APT
-+ test_repo.arch = input_arch
-+ test_repo.apt_components = "main"
-+ test_repo.apt_dists = "stable"
-+ test_repo.mirror = input_mirror
-+ test_repo.mirror_type = input_mirror_type
-+ test_repo.rpm_list = input_rpm_list
-+ test_settings = cobbler_api.settings()
-+ repo_path = os.path.join(test_settings.webdir, "repo_mirror", test_repo.name)
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ mocker.patch("os.path.exists", return_value=True)
-+
-+ # Act
-+ with expected_exception:
-+ reposync_object.apt_sync(repo)
-+
-+ # Assert
-+ mocked_subprocess.assert_called_with(
-+ [
-+ "/usr/bin/debmirror",
-+ "--nocleanup",
-+ "--method=http",
-+ "--host=ftp.debian.org",
-+ "--root=/debian",
-+ "--dist=stable",
-+ "--section=main",
-+ repo_path,
-+ "--nosource",
-+ "-a=amd64",
-+ ],
-+ shell=False,
-+ )
-+
-+
-+@pytest.mark.usefixtures("remove_repo")
-+@pytest.mark.parametrize(
-+ "input_mirror_type,input_mirror,expected_exception",
-+ [
-+ (
-+ enums.MirrorType.BASEURL,
-+ "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-+ does_not_raise(),
-+ ),
-+ (
-+ enums.MirrorType.MIRRORLIST,
-+ "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ (
-+ enums.MirrorType.METALINK,
-+ "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-+ pytest.raises(cexceptions.CX),
-+ ),
-+ ],
-+)
-+def test_reposync_wget(
-+ mocker: "MockerFixture",
-+ input_mirror_type: enums.MirrorType,
-+ input_mirror: str,
-+ expected_exception: Any,
-+ cobbler_api: CobblerAPI,
-+ repo: Repo,
-+ reposync_object: reposync.RepoSync,
-+):
-+ # Arrange
-+ test_repo = repo
-+ test_repo.breed = enums.RepoBreeds.WGET
-+ test_repo.mirror = input_mirror
-+ test_repo.mirror_type = input_mirror_type
-+ repo_path = os.path.join(
-+ reposync_object.settings.webdir, "repo_mirror", test_repo.name
-+ )
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ mocker.patch("cobbler.actions.reposync.repo_walker")
-+ mocker.patch.object(reposync_object, "create_local_file")
-+
-+ # Act
-+ with expected_exception:
-+ reposync_object.wget_sync(test_repo)
-+
-+ # Assert
-+ mocked_subprocess.assert_called_with(
-+ [
-+ "wget",
-+ "-N",
-+ "-np",
-+ "-r",
-+ "-l",
-+ "inf",
-+ "-nd",
-+ "-P",
-+ repo_path,
-+ input_mirror,
-+ ],
-+ shell=False,
-+ )
-+
-+
-+def test_reposync_rhn(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync, repo: Repo
-+):
-+ # Arrange
-+ repo.mirror = "rhn://%s" % repo.name
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ mocker.patch("os.path.isdir", return_value=True)
-+ mocker.patch("os.makedirs")
-+ mocker.patch("cobbler.actions.reposync.repo_walker")
-+ mocker.patch.object(reposync_object, "create_local_file")
-+ mocker.patch.object(
-+ reposync_object, "reposync_cmd", return_value=["/my/fake/reposync"]
-+ )
-+
-+ # Act
-+ reposync_object.rhn_sync(repo)
-+
-+ # Assert
-+ # TODO: Check this more and document how its actually working
-+ mocked_subprocess.assert_called_with(
- [
-- (
-- enums.MirrorType.BASEURL,
-- "http://ftp.debian.org/debian",
-- enums.RepoArchs.X86_64,
-- "",
-- does_not_raise()
-- ),
-- (
-- enums.MirrorType.MIRRORLIST,
-- "http://ftp.debian.org/debian",
-- enums.RepoArchs.X86_64,
-- "",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.METALINK,
-- "http://ftp.debian.org/debian",
-- enums.RepoArchs.X86_64,
-- "",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.BASEURL,
-- "http://www.example.com/path/to/some/repo",
-- enums.RepoArchs.X86_64,
-- "",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.BASEURL,
-- "http://ftp.debian.org/debian",
-- enums.RepoArchs.NONE,
-- "",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.BASEURL,
-- "http://ftp.debian.org/debian",
-- enums.RepoArchs.X86_64,
-- "dpkg",
-- pytest.raises(cexceptions.CX)
-- ),
-+ "/my/fake/reposync",
-+ "--testflag",
-+ "--repo=testrepo0",
-+ "--download-path=/srv/www/cobbler/repo_mirror",
- ],
-+ shell=False,
- )
-- def test_reposync_apt(
-- self,
-- input_mirror_type,
-- input_mirror,
-- input_arch,
-- input_rpm_list,
-- expected_exception,
-- api,
-- repo,
-- reposync
-- ):
-- # Arrange
-- test_repo = repo
-- test_repo.breed = enums.RepoBreeds.APT
-- test_repo.arch = input_arch
-- test_repo.apt_components = "main"
-- test_repo.apt_dists = "stable"
-- test_repo.mirror = input_mirror
-- test_repo.mirror_type = input_mirror_type
-- test_repo.rpm_list = input_rpm_list
-- test_repo.yumopts = "--exclude=.* --include=dpkg.* --no-check-gpg --rsync-extra=none"
-- test_settings = api.settings()
-- repo_path = os.path.join(test_settings.webdir, "repo_mirror", test_repo.name)
--
-- # Act & Assert
-- with expected_exception:
-- reposync.run(test_repo.name)
-- result = os.path.exists(repo_path)
-- for rpm in ["dpkg"]:
-- assert glob.glob(os.path.join(repo_path, "**", "dpkg") + "*", recursive=True) != []
-- assert result
--
-- @pytest.mark.skip("To flaky and thus not reliable. Needs to be mocked to be of use.")
-- @pytest.mark.usefixtures("remove_repo")
-- @pytest.mark.parametrize(
-- "input_mirror_type,input_mirror,expected_exception",
-+
-+
-+def test_reposync_rsync(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync, repo: Repo
-+):
-+ # Arrange
-+ mocked_subprocess = mocker.patch("cobbler.utils.subprocess_call", return_value=0)
-+ mocker.patch("cobbler.actions.reposync.repo_walker")
-+ mocker.patch.object(reposync_object, "create_local_file")
-+ repo_path = os.path.join(reposync_object.settings.webdir, "repo_mirror", repo.name)
-+
-+ # Act
-+ reposync_object.rsync_sync(repo)
-+
-+ # Assert
-+ mocked_subprocess.assert_called_with(
- [
-- (
-- enums.MirrorType.BASEURL,
-- "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-- does_not_raise()
-- ),
-- (
-- enums.MirrorType.MIRRORLIST,
-- "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.METALINK,
-- "http://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/2",
-- pytest.raises(cexceptions.CX)
-- ),
-- (
-- enums.MirrorType.BASEURL,
-- "http://www.example.com/path/to/some/repo",
-- pytest.raises(cexceptions.CX)
-- ),
-+ "rsync",
-+ "--testflag",
-+ "--delete-after",
-+ "-e ssh",
-+ "--delete",
-+ "--exclude-from=/etc/cobbler/rsync.exclude",
-+ "/",
-+ repo_path,
- ],
-+ shell=False,
- )
-- def test_reposync_wget(
-- self,
-- input_mirror_type,
-- input_mirror,
-- expected_exception,
-- api,
-- repo,
-- reposync
-- ):
-- # Arrange
-- test_repo = repo
-- test_repo.breed = enums.RepoBreeds.WGET
-- test_repo.mirror = input_mirror
-- test_repo.mirror_type = input_mirror_type
-- test_settings = api.settings()
-- repo_path = os.path.join(test_settings.webdir, "repo_mirror", test_repo.name)
--
-- # Act & Assert
-- with expected_exception:
-- reposync.run(test_repo.name)
-- result = os.path.exists(repo_path)
-- for rpm in ["rpm"]:
-- assert glob.glob(os.path.join(repo_path, "**", "2") + "*", recursive=True) != []
-- assert result
--
--
--@pytest.mark.skip("TODO")
--def test_reposync_rhn():
-+
-+
-+def test_createrepo_walker(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync, repo: Repo
-+):
- # Arrange
-+ input_repo = repo
-+ input_repo.breed = enums.RepoBreeds.RSYNC
-+ input_dirname = ""
-+ input_fnames = []
-+ expected_call = ["createrepo", "--testflags", f"'{input_dirname}'"]
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ mocker.patch(
-+ "cobbler.utils.blender",
-+ autospec=True,
-+ return_value={"createrepo_flags": "--testflags"},
-+ )
-+ mocker.patch("cobbler.utils.remove_yum_olddata")
-+ mocker.patch("cobbler.utils.subprocess_get", return_value="5")
-+ mocker.patch("cobbler.utils.get_family", return_value="TODO")
-+ mocker.patch("os.path.exists", return_value=True)
-+ mocker.patch("os.path.isfile", return_value=True)
-+ mocker.patch.object(reposync_object, "librepo_getinfo", return_value={})
-+
- # Act
-+ reposync_object.createrepo_walker(input_repo, input_dirname, input_fnames)
-+
- # Assert
-- assert False
-+ # TODO: Improve coverage over different cases in method
-+ mocked_subprocess.assert_called_with(expected_call, shell=False)
-
-
--@pytest.mark.skip("TODO")
--def test_reposync_rsync():
-+@pytest.mark.parametrize(
-+ "input_repotype,expected_exception",
-+ [
-+ (enums.RepoBreeds.YUM, does_not_raise()),
-+ (enums.RepoBreeds.RHN, does_not_raise()),
-+ (enums.RepoBreeds.APT, does_not_raise()),
-+ (enums.RepoBreeds.RSYNC, does_not_raise()),
-+ (enums.RepoBreeds.WGET, does_not_raise()),
-+ (enums.RepoBreeds.NONE, pytest.raises(cexceptions.CX)),
-+ ],
-+)
-+def test_sync(
-+ mocker: "MockerFixture",
-+ cobbler_api: CobblerAPI,
-+ reposync_object: reposync.RepoSync,
-+ input_repotype: enums.RepoBreeds,
-+ expected_exception: Any,
-+):
- # Arrange
-+ test_repo = Repo(cobbler_api)
-+ test_repo.breed = input_repotype
-+ rhn_sync_mock = mocker.patch.object(reposync_object, "rhn_sync")
-+ yum_sync_mock = mocker.patch.object(reposync_object, "yum_sync")
-+ apt_sync_mock = mocker.patch.object(reposync_object, "apt_sync")
-+ rsync_sync_mock = mocker.patch.object(reposync_object, "rsync_sync")
-+ wget_sync_mock = mocker.patch.object(reposync_object, "wget_sync")
-+
- # Act
-+ with expected_exception:
-+ reposync_object.sync(test_repo)
-+
-+ # Assert
-+ call_count = sum(
-+ (
-+ rhn_sync_mock.call_count,
-+ yum_sync_mock.call_count,
-+ apt_sync_mock.call_count,
-+ rsync_sync_mock.call_count,
-+ wget_sync_mock.call_count,
-+ )
-+ )
-+ assert call_count == 1
-+
-+
-+def test_librepo_getinfo(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync, tmp_path: Path
-+):
-+ # Arrange
-+ handle_mock = mocker.MagicMock()
-+ result_mock = mocker.MagicMock()
-+ mocker.patch("librepo.Handle", return_value=handle_mock)
-+ mocker.patch("librepo.Result", return_value=result_mock)
-+
-+ # Act
-+ reposync_object.librepo_getinfo(str(tmp_path))
-+
-+ # Assert
-+ handle_mock.perform.assert_called_with(result_mock)
-+ result_mock.getinfo.assert_called()
-+
-+
-+def test_create_local_file(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync, repo: Repo
-+):
-+ # Arrange
-+ mocker.patch("cobbler.utils.filesystem_helpers.mkdir", autospec=True)
-+ mock_open = mocker.patch("builtins.open", mocker.mock_open())
-+ input_dest_path = ""
-+ input_repo = repo
-+ input_output = True
-+
-+ # Act
-+ reposync_object.create_local_file(input_dest_path, input_repo, output=input_output)
-+
-+ # Assert
-+ # TODO: Extend checks
-+ assert mock_open.call_count == 1
-+ assert mock_open.mock_calls[0] == mocker.call("config.repo", "w", encoding="UTF-8")
-+ mock_open_handle = mock_open()
-+ assert mock_open_handle.write.mock_calls[0] == mocker.call("[testrepo0]\n")
-+ assert mock_open_handle.write.mock_calls[1] == mocker.call("name=testrepo0\n")
-+
-+
-+def test_update_permissions(
-+ mocker: "MockerFixture", reposync_object: reposync.RepoSync
-+):
-+ # Arrange
-+ mocked_subprocess = mocker.patch(
-+ "cobbler.utils.subprocess_call", autospec=True, return_value=0
-+ )
-+ path_to_update = "/my/fake/path"
-+ expected_calls = [
-+ mocker.call(["chown", "-R", "root:www", path_to_update], shell=False),
-+ mocker.call(["chmod", "-R", "755", path_to_update], shell=False),
-+ ]
-+
-+ # Act
-+ reposync_object.update_permissions(path_to_update)
-+
- # Assert
-- assert False
-+ assert mocked_subprocess.mock_calls == expected_calls
diff --git a/cobbler.spec b/cobbler.spec
index 69d7d40..5fcad3b 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -8,7 +8,7 @@
%bcond check 0
Name: cobbler
-Version: 3.3.7
+Version: 3.3.9
Release: %autorelease
Summary: Boot server configurator
URL: https://cobbler.github.io/
@@ -22,16 +22,10 @@ Source4: %{name}.fc
# Do not run coverage tests
Patch0: cobbler-nocov.patch
-# Python 3.13 support (backport of https://github.com/cobbler/cobbler/pull/3842)
-# https://bugzilla.redhat.com/show_bug.cgi?id=2335620
-Patch1: cobbler-python3.13.patch
# Upstream fix for reposync --tries
# https://bugzilla.redhat.com/show_bug.cgi?id=2401605
# Backport of https://github.com/cobbler/cobbler/pull/3378
Patch2: cobbler-reposync.patch
-# Use systemctl is-active to prevent some SELinux denials checking service status
-# https://bugzilla.redhat.com/show_bug.cgi?id=2353898
-Patch3: https://github.com/cobbler/cobbler/pull/3945.patch
BuildArch: noarch
BuildRequires: make
diff --git a/sources b/sources
index ba2585a..8806f66 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (cobbler-3.3.7.tar.gz) = df6570dd7c6cbe50464624267df1bbecbb29e60513bba312a6c726502d4670670f3113f24b6b7e465d0b3353c0721e6fe3725dbc4569b4f624ec2b4a29682d1a
+SHA512 (cobbler-3.3.9.tar.gz) = bf2b594b55e7d64c68319cfd9d908469e2f100da1f2921eca18adb4d129bca1f0d9db991b798e671aaac1f840faf0c9473f6fc4a2efd19bede8ce2cdee15c1a1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-01 4:03 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-01 4:03 [rpms/cobbler] rawhide: Update to 3.3.9 Orion Poplawski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox