From 0c58cd954d461352c1f61464ff94b40e2810ce7a Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Oct 23 2023 12:24:16 +0000
Subject: Retrieve task_id for older OSBS builds


Related: https://pagure.io/koji/issue/3906

---

diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py
index 55cdb7a..b954cff 100644
--- a/cli/koji_cli/commands.py
+++ b/cli/koji_cli/commands.py
@@ -24,7 +24,7 @@ import six.moves.xmlrpc_client
 from six.moves import filter, map, range, zip
 
 import koji
-from koji.util import base64encode, md5_constructor, to_list
+from koji.util import base64encode, extract_build_task, md5_constructor, to_list
 from koji_cli.lib import (
     TimeOption,
     DatetimeJSONEncoder,
@@ -3600,8 +3600,9 @@ def anon_handle_buildinfo(goptions, session, args):
             error_hit = True
             continue
         task = None
-        if info['task_id']:
-            task = session.getTaskInfo(info['task_id'], request=True)
+        task_id = extract_build_task(info)
+        if task_id:
+            task = session.getTaskInfo(task_id, request=True)
         taglist = []
         for tag in session.listTags(build):
             taglist.append(tag['name'])
diff --git a/koji/util.py b/koji/util.py
index f3e5dce..2ffa03c 100644
--- a/koji/util.py
+++ b/koji/util.py
@@ -970,3 +970,19 @@ def format_shell_cmd(cmd, text_width=80):
     if line:
         s.append(line)
     return ' \\\n'.join(s)
+
+
+def extract_build_task(binfo):
+    """
+    Helper for extracting task id from buildinfo. CGs and older OSBS approach
+    can put it into different places in binfo
+
+    :param dict binfo: buildinfo
+    :returns int: task id
+    """
+
+    task_id = binfo.get('task_id')
+    if task_id is None:
+        # legacy OSBS task id location
+        task_id = binfo.get('extra', {}).get('container_koji_task_id')
+    return task_id
diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py
index a99e225..30e59f3 100644
--- a/kojihub/kojihub.py
+++ b/kojihub/kojihub.py
@@ -68,6 +68,7 @@ from koji.util import (
     base64encode,
     decode_bytes,
     dslice,
+    extract_build_task,
     joinpath,
     md5_constructor,
     move_and_symlink,
@@ -5968,7 +5969,7 @@ def apply_volume_policy(build, strict=False):
     volume we be retained.
     """
     policy_data = {'build': build}
-    task_id = build['task_id']
+    task_id = extract_build_task(build)
     if task_id:
         policy_data.update(policy_data_from_task(task_id))
     volume = check_volume_policy(policy_data, strict=strict)
@@ -9690,14 +9691,15 @@ class SourceTest(koji.policy.MatchTest):
             data[self.field] = data['source']
         elif 'build' in data:
             build = get_build(data['build'])
+            task_id = extract_build_task(build)
             if build['source'] is not None:
                 data[self.field] = build['source']
-            elif build['task_id'] is None:
+            elif task_id is None:
                 # no source to match against
                 return False
             else:
                 # crack open the build task
-                task = Task(build['task_id'])
+                task = Task(task_id)
                 info = task.getInfo(request=True)
                 method = info['method']
                 request = info['request']
@@ -9718,8 +9720,7 @@ class SourceTest(koji.policy.MatchTest):
                 elif 'url' in params:
                     data[self.field] = params['url']
                 else:
-                    print("Unable to determine source from task '{}'".format(
-                        build['task_id']))
+                    print("Unable to determine source from task '{}'".format(task_id))
                     return False
         else:
             return False
diff --git a/tests/test_lib/test_utils.py b/tests/test_lib/test_utils.py
index f0d576d..3e977b7 100644
--- a/tests/test_lib/test_utils.py
+++ b/tests/test_lib/test_utils.py
@@ -1634,6 +1634,16 @@ class TestFormatShellCmd(unittest.TestCase):
         for inp, out in cases:
             self.assertEqual(koji.util.format_shell_cmd(inp, text_width=40), out)
 
+class TestExtractBuildTask(unittest.TestCase):
+    def test_valid_binfos(self):
+        binfos = [
+            {'id': 1, 'task_id': 123},
+            {'id': 1, 'extra': {'container_koji_task_id': 123}},
+        ]
+        for binfo in binfos:
+            res = koji.util.extract_build_task(binfo)
+            self.assertEqual(res, 123)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index b58bd98..af56d89 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -37,6 +37,7 @@ from koji.tasks import parse_task_params
 import kojiweb.util
 from koji.server import ServerRedirect
 from kojiweb.util import _genHTML, _getValidTokens, _initValues
+from koji.util import extract_build_task
 
 
 # Convenience definition of a commonly-used sort function
@@ -1295,8 +1296,9 @@ def buildinfo(environ, buildID):
             values[header] = koji.fixEncoding(result.get(header))
         values['changelog'] = server.getChangelogEntries(build['id'])
 
-    if build['task_id']:
-        task = server.getTaskInfo(build['task_id'], request=True)
+    task_id = extract_build_task(build)
+    if task_id:
+        task = server.getTaskInfo(task_id, request=True)
         # get the summary, description, and changelogs from the built srpm
         # if the build is not yet complete
         if build['state'] != koji.BUILD_STATES['COMPLETE']:
@@ -2510,8 +2512,9 @@ def recentbuilds(environ, user=None, tag=None, package=None):
 
     server.multicall = True
     for build in builds:
-        if build['task_id']:
-            server.getTaskInfo(build['task_id'], request=True)
+        task_id = extract_build_task(build)
+        if task_id:
+            server.getTaskInfo(task_id, request=True)
         else:
             server.echo(None)
     tasks = server.multiCall()

