From 5d37978ac0912f9ae6c31c46d727eb424b7ca234 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Dec 03 2025 14:59:59 +0000
Subject: [PATCH 1/2] write-signed-rpm: fix nvr fallback


---

diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py
index 42d9339..6eddb50 100644
--- a/cli/koji_cli/commands.py
+++ b/cli/koji_cli/commands.py
@@ -1865,33 +1865,55 @@ def handle_write_signed_rpm(goptions, session, args):
     elif options.buildid:
         rpms = session.listRPMs(int(options.buildid))
     else:
-        nvrs = []
-        rpms = []
+        # for historical reasons, we accept either rpms or builds on command line
+        rpm_args = []
+        build_args = []
+
+        # first filter out invalid nvras, as getRPM will error on them
+        for arg in args:
+            if arg.isdigit():
+                # we also accept rpm ids
+                rpm_args.append(int(arg))
+            else:
+                try:
+                    koji.parse_NVRA(arg)
+                    rpm_args.append(arg)
+                    # note that this is not perfect, many NVRs will succeed here
+                except koji.GenericError:
+                    build_args.append(arg)
 
+        # look up rpms on hub
+        rpms = []
         with session.multicall() as m:
-            result = [m.getRPM(nvra, strict=False) for nvra in args]
-        for rpm, nvra in zip(result, args):
-            rpm = rpm.result
-            if rpm:
-                rpms.append(rpm)
+            calls = [m.getRPM(r, strict=False) for r in rpm_args]
+        for call in calls:
+            rpminfo = call.result
+            if rpminfo:
+                rpms.append(rpminfo)
             else:
-                nvrs.append(nvra)
+                # fetch the unmatched arg from call args
+                build_args.append(call.args[0])
 
-        # for historical reasons, we also accept nvrs
-        with session.multicall() as m:
-            result = [m.getBuild(nvr, strict=True) for nvr in nvrs]
+        # look up builds on hub
         builds = []
-        for nvr, build in zip(nvrs, result):
+        with session.multicall() as m:
+            calls = [m.getBuild(nvr, strict=True) for nvr in build_args]
+        for call in calls:
             try:
-                builds.append(build.result['id'])
+                builds.append(call.result['id'])
             except koji.GenericError:
-                raise koji.GenericError("No such rpm or build: %s" % nvr)
+                # fetch the unmatched arg from call args
+                raise koji.GenericError("No such rpm or build: %s" % call.args[0])
 
+        # look up rpms for builds
         with session.multicall() as m:
             rpm_lists = [m.listRPMs(buildID=build_id) for build_id in builds]
         for rpm_list in rpm_lists:
             rpms.extend(rpm_list.result)
 
+    if not rpms:
+        warn('No rpms found')
+
     with session.multicall(strict=True) as m:
         for i, rpminfo in enumerate(rpms):
             nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % rpminfo

From 126cb52e5e9696014ea6495056ecd1fa2e144c96 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Dec 03 2025 14:59:59 +0000
Subject: [PATCH 2/2] fix unit test


---

diff --git a/tests/test_cli/test_write_signed_rpm.py b/tests/test_cli/test_write_signed_rpm.py
index d12128f..3816336 100644
--- a/tests/test_cli/test_write_signed_rpm.py
+++ b/tests/test_cli/test_write_signed_rpm.py
@@ -128,8 +128,11 @@ class TestWriteSignedRPM(utils.CliTestCase):
         session = mock.MagicMock()
         mcall = session.multicall.return_value.__enter__.return_value
 
-        def vm(result):
-            m = koji.VirtualCall('mcall_method', [], {})
+        # helper function for mocking multicall
+        def vm(result, args=None):
+            if args is None:
+                args = []
+            m = koji.VirtualCall('mcall_method', args, {})
             if isinstance(result, dict) and result.get('faultCode'):
                 m._result = result
             else:
@@ -151,7 +154,7 @@ class TestWriteSignedRPM(utils.CliTestCase):
 
         mcall.getRPM.side_effect = [
             vm(rpm_data[0]),            # bash-4.4.12-5.fc26.src
-            vm(None),                   # bash-4.4.12-5.fc26
+            vm(None, args=['bash-4.4.12-5.fc26']),  # bash-4.4.12-5.fc26
         ]
         mcall.getBuild.return_value = vm({
             'package_name': 'bash',
@@ -207,8 +210,9 @@ class TestWriteSignedRPM(utils.CliTestCase):
         # result: raise koji.GenericError
         mcall.writeSignedRPM.reset_mock()
         mcall.getRPM.side_effect = None
-        mcall.getRPM.return_value = vm(None)
-        mcall.getBuild.return_value = vm({'faultCode': 1000, 'faultString': 'x'})
+        mcall.getRPM.return_value = vm(None, args=['gawk-4.1.4-3.fc26.x86_64'])
+        mcall.getBuild.return_value = vm({'faultCode': 1000, 'faultString': 'x'},
+                                         args=['gawk-4.1.4-3.fc26.x86_64'])
 
         args = arguments + ['gawk-4.1.4-3.fc26.x86_64']
         with self.assertRaises(koji.GenericError) as cm:

