From fad0eed2f57263a973d1f070bde6b54d4d0fb508 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 01 2022 13:33:36 +0000 Subject: PR#3406: Add a utility function to watch builds Merges #3406 https://pagure.io/koji/pull-request/3406 Fixes: #2981 https://pagure.io/koji/issue/2981 Add a utility function to watch builds --- diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index 5dd9967..9e2cc1b 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -45,6 +45,7 @@ from koji_cli.lib import ( print_task_recurse, unique_path, warn, + wait_repo, watch_logs, watch_tasks, truncate_string @@ -7044,8 +7045,6 @@ def anon_handle_wait_repo(options, session, args): "value only") (suboptions, args) = parser.parse_args(args) - start = time.time() - builds = [koji.parse_NVR(build) for build in suboptions.builds] if len(args) < 1: parser.error("Please specify a tag name") @@ -7087,38 +7086,13 @@ def anon_handle_wait_repo(options, session, args): warn("nvr %s is not current in tag %s\n latest build in %s is %s" % (expected_nvr, tag, tag, present_nvr)) - last_repo = None - repo = session.getRepo(tag_id) - - while True: - if builds and repo and repo != last_repo: - if koji.util.checkForBuilds(session, tag_id, builds, repo['create_event'], - latest=True): - if not suboptions.quiet: - print("Successfully waited %s for %s to appear in the %s repo" % - (koji.util.duration(start), koji.util.printList(suboptions.builds), tag)) - return - - if (time.time() - start) >= (suboptions.timeout * 60.0): - if not suboptions.quiet: - if builds: - error("Unsuccessfully waited %s for %s to appear in the %s repo" % - (koji.util.duration(start), koji.util.printList(suboptions.builds), tag)) - else: - error("Unsuccessfully waited %s for a new %s repo" % - (koji.util.duration(start), tag)) - error() - - time.sleep(options.poll_interval) - last_repo = repo - repo = session.getRepo(tag_id) - - if not builds: - if repo != last_repo: - if not suboptions.quiet: - print("Successfully waited %s for a new %s repo" % - (koji.util.duration(start), tag)) - return + success, msg = wait_repo(session, tag_id, builds, + poll_interval=options.poll_interval, timeout=suboptions.timeout) + if success: + if not suboptions.quiet: + print(msg) + else: + error('' if suboptions.quiet else msg) def handle_regen_repo(options, session, args): diff --git a/cli/koji_cli/lib.py b/cli/koji_cli/lib.py index e5821d8..2c69ff6 100644 --- a/cli/koji_cli/lib.py +++ b/cli/koji_cli/lib.py @@ -831,6 +831,51 @@ def _list_tasks(options, session): return tasklist +def wait_repo(session, tag_id, builds, poll_interval=5, timeout=120): + """Watch for given builds to appear in given tag. If no builds are given, + watch for new repo for given tag. + + :param session: Koji session object + :param int tag_id: Tag id + :param [dict] builds: List of builds as NVR dicts + :param int poll_interval: Poll interval in seconds + :param int timeout: Watch timeout in minutes + :returns bool, msg: False if timeouted + """ + last_repo = None + repo = session.getRepo(tag_id) + + # String representations for logs and exceptions + builds_str = koji.util.printList([koji.buildLabel(build) for build in builds]) + tag_info = session.getTag(tag_id, strict=True) + tag_name = tag_info['name'] + + start = time.time() + while True: + if builds and repo and repo != last_repo: + if koji.util.checkForBuilds(session, tag_id, builds, + repo['create_event'], latest=True): + return (True, "Successfully waited %s for %s to appear in the %s repo" % + (koji.util.duration(start), builds_str, tag_name)) + + if (time.time() - start >= timeout * 60.0): + if builds: + return (False, "Unsuccessfully waited %s for %s to appear in the %s repo" % + (koji.util.duration(start), builds_str, tag_name)) + else: + return (False, "Unsuccessfully waited %s for a new %s repo" % + (koji.util.duration(start), tag_name)) + + time.sleep(poll_interval) + last_repo = repo + repo = session.getRepo(tag_id) + + if not builds: + if repo != last_repo: + return (True, "Successfully waited %s for a new %s repo" % + (koji.util.duration(start), tag_name)) + + def format_inheritance_flags(parent): """Return a human readable string of inheritance flags""" flags = '' diff --git a/tests/test_cli/test_wait_repo.py b/tests/test_cli/test_wait_repo.py index 25fe82b..a4da3a2 100644 --- a/tests/test_cli/test_wait_repo.py +++ b/tests/test_cli/test_wait_repo.py @@ -36,7 +36,7 @@ class TestWaitRepo(utils.CliTestCase): self.options = mock.MagicMock() self.options.quiet = True - self.options.poll_interval = 1 # second + self.options.poll_interval = 0.0001 # keep it fast self.options.weburl = 'https://localhost.local' self.session = mock.MagicMock() diff --git a/tests/test_lib/test_build_label.py b/tests/test_lib/test_build_label.py new file mode 100644 index 0000000..f835af3 --- /dev/null +++ b/tests/test_lib/test_build_label.py @@ -0,0 +1,72 @@ +from __future__ import absolute_import +import mock +import os +import rpm +import unittest + +import koji + +class TestBuildLabel(unittest.TestCase): + def test_buildLabel(self): + """Test the buildLabel method""" + + self.assertRaises(AttributeError, koji.buildLabel, None) + self.assertRaises(AttributeError, koji.buildLabel, 1) + self.assertRaises(AttributeError, koji.buildLabel, []) + + input = {} + ret = koji.buildLabel(input) + self.assertEqual(ret, "None-None-None") + + input = {"name": "foo"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "foo-None-None") + + input = {"version": "1.0.2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "None-1.0.2-None") + + input = {"release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "None-None-2") + + input = {"name": "foo", "version": "1.0.2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "foo-1.0.2-None") + + input = {"name": "foo", "release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "foo-None-2") + + input = {"version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "None-1.0.2-2") + + input = {"name": "foo", "version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "foo-1.0.2-2") + + input = {"package_name": "bar", "version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "bar-1.0.2-2") + + input = { + "package_name": "bar", + "name": "foo", + "version": "1.0.2", + "release": "2" + } + ret = koji.buildLabel(input) + self.assertEqual(ret, "bar-1.0.2-2") + + input = {"epoch": 7, "name": "foo", "version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input) + self.assertEqual(ret, "foo-1.0.2-2") + + input = {"epoch": 7, "name": "foo", "version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input, True) + self.assertEqual(ret, "7:foo-1.0.2-2") + + input = {"name": "foo", "version": "1.0.2", "release": "2"} + ret = koji.buildLabel(input, True) + self.assertEqual(ret, "foo-1.0.2-2")