From 3282a07637212b7af639bba67c68b0d7960d2c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 30 Apr 2026 11:52:16 +0200 Subject: [PATCH] Allow passing explicit releasever I do not have "fedora-40" repos configured. I only have the normal fedora repos. Now I can use this like this: $ python fedora_revdep_check.py --repo={fedora,updates}{,-source} --releasever=43 python-dotenv 1.2.2 --- fedora_revdep_check.py | 34 ++++++------ tests/e2e/test_full_workflow.py | 92 +++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 30 deletions(-) diff --git a/fedora_revdep_check.py b/fedora_revdep_check.py index 04bfd60..63191a0 100755 --- a/fedora_revdep_check.py +++ b/fedora_revdep_check.py @@ -37,16 +37,18 @@ class FedoraRevDepChecker: """Check reverse dependencies for Fedora package updates.""" - def __init__(self, verbose=False, base=None, repos=None): + def __init__(self, verbose=False, base=None, repos=None, releasever=None): """Initialize the checker with DNF base and cached repo data. Args: verbose: Enable verbose output base: Optional DNF base object for testing (if None, creates real DNF base) repos: List of repository IDs to enable (default: ['rawhide', 'rawhide-source', 'koji', 'koji-source']) + releasever: Fedora release version (e.g. '44', 'rawhide'). Auto-detected from repos if not set. """ self.verbose = verbose self.base = base + self.releasever = releasever self.repos = repos if repos is not None else ['rawhide', 'rawhide-source', 'koji', 'koji-source'] if self.base is None: self._init_dnf() @@ -114,19 +116,17 @@ def _init_dnf(self): print("Initializing DNF 5 and loading repository metadata...") self.base = libdnf5.base.Base() - # Detect releasever from first repo name, or use 'rawhide' as default - # Extract version from repo names like 'fedora-40', 'f40', or use 'rawhide' - releasever = 'rawhide' - if self.repos: - first_repo = self.repos[0] - # Check if repo contains a version number - import re - version_match = re.search(r'(\d+)', first_repo) - if version_match: - releasever = version_match.group(1) - elif 'rawhide' not in first_repo.lower(): - # If no version found and not rawhide, still use rawhide as fallback - releasever = 'rawhide' + # Use explicitly provided releasever, or detect from repo names + if self.releasever: + releasever = self.releasever + else: + releasever = 'rawhide' + if self.repos: + first_repo = self.repos[0] + import re + version_match = re.search(r'(\d+)', first_repo) + if version_match: + releasever = version_match.group(1) # Configure releasever vars_map = self.base.get_vars() @@ -679,6 +679,7 @@ def main(): %(prog)s python-requests 2.32.0 --verbose %(prog)s pytest 8.0.0 --repo fedora --repo fedora-source %(prog)s numpy 2.0.0 --repo fedora-40 --repo fedora-40-source + %(prog)s pytest 8.0.0 --releasever 44 """ ) @@ -690,11 +691,14 @@ def main(): help='Repository ID to enable (can be specified multiple times). ' 'Default: rawhide, rawhide-source, koji, and koji-source. ' 'Known repositories will be auto-configured if not in /etc/yum.repos.d/') + parser.add_argument('--releasever', + help='Fedora release version (e.g. 44, rawhide). ' + 'Auto-detected from repo names if not specified.') args = parser.parse_args() try: - checker = FedoraRevDepChecker(verbose=args.verbose, repos=args.repos) + checker = FedoraRevDepChecker(verbose=args.verbose, repos=args.repos, releasever=args.releasever) results = checker.simulate_version_change(args.srpm_name, args.new_version) checker.print_results(results) diff --git a/tests/e2e/test_full_workflow.py b/tests/e2e/test_full_workflow.py index a991392..742f543 100644 --- a/tests/e2e/test_full_workflow.py +++ b/tests/e2e/test_full_workflow.py @@ -9,6 +9,68 @@ from fedora_revdep_check import main, FedoraRevDepChecker +class TestReleasever: + """Test --releasever CLI argument and auto-detection logic.""" + + def test_releasever_passed_to_checker(self, monkeypatch, mock_dnf_base): + """Test that --releasever CLI arg is passed through to FedoraRevDepChecker.""" + monkeypatch.setattr('sys.argv', ['fedora-revdep-check', 'pytest', '8.0.0', '--releasever', '44']) + + captured_releasever = [] + original_init = FedoraRevDepChecker.__init__ + + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + captured_releasever.append(releasever) + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) + + monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) + main() + + assert captured_releasever == ['44'] + + def test_releasever_none_when_not_specified(self, monkeypatch, mock_dnf_base): + """Test that releasever is None when --releasever is not passed.""" + monkeypatch.setattr('sys.argv', ['fedora-revdep-check', 'pytest', '8.0.0']) + + captured_releasever = [] + original_init = FedoraRevDepChecker.__init__ + + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + captured_releasever.append(releasever) + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) + + monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) + main() + + assert captured_releasever == [None] + + def test_releasever_rawhide(self, monkeypatch, mock_dnf_base): + """Test that --releasever accepts 'rawhide'.""" + monkeypatch.setattr('sys.argv', ['fedora-revdep-check', 'pytest', '8.0.0', '--releasever', 'rawhide']) + + captured_releasever = [] + original_init = FedoraRevDepChecker.__init__ + + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + captured_releasever.append(releasever) + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) + + monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) + main() + + assert captured_releasever == ['rawhide'] + + def test_releasever_stored_on_instance(self, mock_dnf_base): + """Test that releasever is stored on the checker instance.""" + checker = FedoraRevDepChecker(verbose=False, base=mock_dnf_base, releasever='42') + assert checker.releasever == '42' + + def test_releasever_default_is_none(self, mock_dnf_base): + """Test that releasever defaults to None.""" + checker = FedoraRevDepChecker(verbose=False, base=mock_dnf_base) + assert checker.releasever is None + + class TestFullWorkflow: """Test complete CLI workflow through main() function.""" @@ -19,8 +81,8 @@ def test_main_with_conflicts_exit_code_one(self, monkeypatch, jupyterlab_base, c # Mock FedoraRevDepChecker to use test base original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos, releasever=releasever) monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -40,8 +102,8 @@ def test_main_verbose_flag(self, monkeypatch, mock_pytest_base, capsys): original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=mock_pytest_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=mock_pytest_base if base is None else base, repos=repos, releasever=releasever) monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -58,8 +120,8 @@ def test_main_nonexistent_package(self, monkeypatch, mock_dnf_base, capsys): original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -77,7 +139,7 @@ def test_main_exception_handling(self, monkeypatch, capsys): monkeypatch.setattr('sys.argv', ['fedora-revdep-check', 'test', '1.0.0']) # Mock FedoraRevDepChecker to raise an exception - def mock_init(self, verbose=False, base=None, repos=None): + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): raise RuntimeError("Test error message") monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -96,8 +158,8 @@ def test_main_output_format_consistency(self, monkeypatch, jupyterlab_base, caps original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos, releasever=releasever) monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -118,8 +180,8 @@ def test_main_deterministic_output(self, monkeypatch, jupyterlab_base): original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=jupyterlab_base if base is None else base, repos=repos, releasever=releasever) monkeypatch.setattr(FedoraRevDepChecker, '__init__', mock_init) @@ -147,8 +209,8 @@ def test_main_exit_code_zero_for_already_broken_only(self, monkeypatch, mock_dnf original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) def mock_simulate(self, srpm_name, new_version): return { @@ -185,8 +247,8 @@ def test_main_exit_code_one_for_mixed_conflicts(self, monkeypatch, mock_dnf_base original_init = FedoraRevDepChecker.__init__ - def mock_init(self, verbose=False, base=None, repos=None): - original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos) + def mock_init(self, verbose=False, base=None, repos=None, releasever=None): + original_init(self, verbose=verbose, base=mock_dnf_base if base is None else base, repos=repos, releasever=releasever) # Mock simulate_version_change to return mixed conflicts def mock_simulate(self, srpm_name, new_version):