From 1dd05bea879df2a747adf4f18c1d7ec0f9104c1f Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Aug 30 2021 07:24:31 +0000 Subject: PR#2991: CLI channels, hosts methods works with older hub Merges #2991 https://pagure.io/koji/pull-request/2991 Fixes: #2990 https://pagure.io/koji/issue/2990 list-channels is not working when Koji 1.26 CLI and older hub --- diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index 19b3a0e..9f67540 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -312,7 +312,19 @@ def handle_add_channel(goptions, session, args): if len(args) != 1: parser.error(_("Please specify one channel name")) activate_session(session, goptions) - channel_id = session.addChannel(args[0], description=options.description) + channel_name = args[0] + try: + channel_id = session.addChannel(channel_name, description=options.description) + except koji.GenericError as ex: + msg = str(ex) + if 'channel %s already exists' % channel_name in msg: + error("channel %s already exists" % channel_name) + elif 'Invalid method:' in msg: + version = session.getKojiVersion() + error("addChannel is available on hub from Koji 1.26 version, your version is %s" % + version) + else: + error(msg) print("%s added: id %d" % (args[0], channel_id)) @@ -365,7 +377,16 @@ def handle_edit_channel(goptions, session, args): cinfo = session.getChannel(args[0]) if not cinfo: error("No such channel: %s" % args[0]) - result = session.editChannel(args[0], **vals) + try: + result = session.editChannel(args[0], **vals) + except koji.GenericError as ex: + msg = str(ex) + if 'Invalid method:' in msg: + version = session.getKojiVersion() + error("editChannel is available on hub from Koji 1.26 version, your version is %s" % + version) + else: + print(msg) if not result: error(_("No changes made, please correct the command line")) @@ -2988,8 +3009,11 @@ def anon_handle_list_channels(goptions, session, args): opts = {} if options.enabled is not None: opts['enabled'] = options.enabled - channels = sorted([x for x in session.listChannels(**opts)], key=lambda x: x['name']) - + try: + channels = sorted([x for x in session.listChannels(**opts)], key=lambda x: x['name']) + except koji.ParameterError: + channels = sorted([x for x in session.listChannels()], key=lambda x: x['name']) + first_item = channels[0] session.multicall = True for channel in channels: session.listHosts(channelID=channel['id']) @@ -2999,14 +3023,17 @@ def anon_handle_list_channels(goptions, session, args): channel['ready'] = len([x for x in hosts if x['ready']]) channel['capacity'] = sum([x['capacity'] for x in hosts]) channel['load'] = sum([x['task_load'] for x in hosts]) - channel['comment'] = truncate_string(channel['comment']) - channel['description'] = truncate_string(channel['description']) + if 'comment' in first_item: + channel['comment'] = truncate_string(channel['comment']) + if 'description' in first_item: + channel['description'] = truncate_string(channel['description']) if channel['capacity']: channel['perc_load'] = channel['load'] / channel['capacity'] * 100.0 else: channel['perc_load'] = 0.0 - if not channel['enabled']: - channel['name'] = channel['name'] + ' [disabled]' + if 'enabled' in first_item: + if not channel['enabled']: + channel['name'] = channel['name'] + ' [disabled]' if channels: longest_channel = max([len(ch['name']) for ch in channels]) else: @@ -3021,16 +3048,16 @@ def anon_handle_list_channels(goptions, session, args): hdr = '{channame:<{longest_channel}}Enabled Ready Disbld Load Cap ' \ 'Perc ' hdr = hdr.format(longest_channel=longest_channel, channame='Channel') - if options.description: + if options.description and 'description' in first_item: hdr += "Description".ljust(53) - if options.comment: + if options.comment and 'comment' in first_item: hdr += "Comment".ljust(53) print(hdr) mask = "%%(name)-%ss %%(enabled_host)6d %%(ready)6d %%(disabled)6d %%(load)6d %%(" \ "capacity)6d %%(perc_load)6d%%%%" % longest_channel - if options.description: + if options.description and 'description' in first_item: mask += " %(description)-50s" - if options.comment: + if options.comment and 'comment' in first_item: mask += " %(comment)-50s" for channel in channels: print(mask % channel) @@ -3110,19 +3137,24 @@ def anon_handle_list_hosts(goptions, session, args): if options.show_channels: with session.multicall() as m: result = [m.listChannels(host['id']) for host in hosts] + first_line_channel = result[0].result for host, channels in zip(hosts, result): list_channels = [] for c in channels.result: - if c['enabled']: - list_channels.append(c['name']) + if 'enabled' in first_line_channel: + if c['enabled']: + list_channels.append(c['name']) + else: + list_channels.append('*' + c['name']) else: - list_channels.append('*' + c['name']) + list_channels.append(c['name']) host['channels'] = ','.join(sorted(list_channels)) if hosts: longest_host = max([len(h['name']) for h in hosts]) else: longest_host = 8 + if not options.quiet: hdr = "{hostname:<{longest_host}} Enb Rdy Load/Cap Arches " \ "Last Update " @@ -7974,7 +8006,7 @@ def handle_version(goptions, session, args): version = session.getKojiVersion() print("Hub: %s" % version) except koji.GenericError: - print("Hub: Can' determine (older than 1.23)") + print("Hub: Can't determine (older than 1.23)") def anon_handle_userinfo(goptions, session, args): diff --git a/tests/test_cli/test_add_channel.py b/tests/test_cli/test_add_channel.py index b693a66..0e5b048 100644 --- a/tests/test_cli/test_add_channel.py +++ b/tests/test_cli/test_add_channel.py @@ -37,13 +37,35 @@ class TestAddChannel(utils.CliTestCase): @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.commands.activate_session') def test_handle_add_channel_exist(self, activate_session_mock, stderr): - expected = 'channel %(name)s already exists (id=%(id)i)' + expected_api = 'channel %s already exists (id=%s)' % (self.channel_name, self.channel_id) + expected = 'channel %s already exists\n' % self.channel_name - self.session.addChannel.side_effect = koji.GenericError(expected) - with self.assertRaises(koji.GenericError) as ex: + self.session.addChannel.side_effect = koji.GenericError(expected_api) + with self.assertRaises(SystemExit) as ex: handle_add_channel(self.options, self.session, ['--description', self.description, self.channel_name]) - self.assertEqual(str(ex.exception), expected) + self.assertExitCode(ex, 1) + actual = stderr.getvalue() + self.assertMultiLineEqual(actual, expected) + activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.addChannel.assert_called_once_with(self.channel_name, + description=self.description) + + @mock.patch('sys.stderr', new_callable=six.StringIO) + @mock.patch('koji_cli.commands.activate_session') + def test_handle_add_channel_older_hub(self, activate_session_mock, stderr): + expected_api = 'Invalid method: addChannel' + expected = 'addChannel is available on hub from Koji 1.26 version, your version ' \ + 'is 1.25.1\n' + self.session.getKojiVersion.return_value = '1.25.1' + + self.session.addChannel.side_effect = koji.GenericError(expected_api) + with self.assertRaises(SystemExit) as ex: + handle_add_channel(self.options, self.session, + ['--description', self.description, self.channel_name]) + self.assertExitCode(ex, 1) + actual = stderr.getvalue() + self.assertMultiLineEqual(actual, expected) activate_session_mock.assert_called_once_with(self.session, self.options) self.session.addChannel.assert_called_once_with(self.channel_name, description=self.description) @@ -79,7 +101,7 @@ class TestAddChannel(utils.CliTestCase): self.assertMultiLineEqual(actual, expected_stderr) activate_session_mock.assert_not_called() - def test_handle_add_host_help(self): + def test_handle_add_channel_help(self): self.assert_help( handle_add_channel, """Usage: %s add-channel [options] diff --git a/tests/test_cli/test_edit_channel.py b/tests/test_cli/test_edit_channel.py index 5522441..58f37cb 100644 --- a/tests/test_cli/test_edit_channel.py +++ b/tests/test_cli/test_edit_channel.py @@ -6,6 +6,7 @@ import unittest import mock import six +import koji from koji_cli.commands import handle_edit_channel from . import utils @@ -61,6 +62,26 @@ Options: self.session.editChannel.assert_called_once_with(self.channel_old, name=self.channel_new, description=self.description) + @mock.patch('sys.stderr', new_callable=six.StringIO) + @mock.patch('koji_cli.commands.activate_session') + def test_handle_edit_channel_older_hub(self, activate_session_mock, stderr): + expected_api = 'Invalid method: editChannel' + expected = 'editChannel is available on hub from Koji 1.26 version, your version ' \ + 'is 1.25.1\n' + self.session.getKojiVersion.return_value = '1.25.1' + + self.session.editChannel.side_effect = koji.GenericError(expected_api) + with self.assertRaises(SystemExit) as ex: + handle_edit_channel(self.options, self.session, + [self.channel_old, '--name', self.channel_new, + '--description', self.description]) + self.assertExitCode(ex, 1) + actual = stderr.getvalue() + self.assertMultiLineEqual(actual, expected) + activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.editChannel.assert_called_once_with(self.channel_old, name=self.channel_new, + description=self.description) + if __name__ == '__main__': unittest.main()