From 4434b1f5f46fe4ec84582e57c265f11ff5c368b5 Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Jun 08 2018 09:02:18 +0000 Subject: [PATCH 1/3] Extend override by number of days or specific date This patch adds a new subcommand extend to command override, which is able to extend an override expiration date. Fixes #67 Signed-off-by: Chenxiong Qi --- diff --git a/fedpkg/__init__.py b/fedpkg/__init__.py index 7f09097..fa8e08b 100644 --- a/fedpkg/__init__.py +++ b/fedpkg/__init__.py @@ -15,12 +15,31 @@ import git import re import platform -from datetime import datetime +from datetime import datetime, timedelta from . import cli # noqa from .lookaside import FedoraLookasideCache from pyrpkg.utils import cached_property +try: + from bodhi.client.bindings import BodhiClient as _BodhiClient +except ImportError: + _BodhiClient = None + + +if _BodhiClient is not None: + class BodhiClient(_BodhiClient): + def extend_override(self, override, expiration_date): + data = dict( + nvr=override['nvr'], + notes=override['notes'], + expiration_date=expiration_date, + edited=override['nvr'], + csrf_token=self.csrf(), + ) + return self.send_request( + 'overrides/', verb='POST', auth=True, data=data) + class Commands(pyrpkg.Commands): @@ -238,8 +257,6 @@ class Commands(pyrpkg.Commands): def create_buildroot_override(self, bodhi_config, build, duration, notes=''): - from bodhi.client.bindings import BodhiClient - bodhi = BodhiClient(staging=bodhi_config['staging']) result = bodhi.list_overrides(builds=build) if result['total'] == 0: @@ -271,6 +288,64 @@ class Commands(pyrpkg.Commands): self.log.info('Buildroot override for %s already exists and ' 'not expired.', build) + def extend_buildroot_override(self, bodhi_config, build, duration): + bodhi = BodhiClient(username=self.user, + staging=bodhi_config['staging']) + result = bodhi.list_overrides(builds=build) + + if result['total'] == 0: + self.log.info('No buildroot override for build %s', build) + return + + override = result['overrides'][0] + expiration_date = datetime.strptime(override['expiration_date'], + '%Y-%m-%d %H:%M:%S') + utcnow = datetime.utcnow() + + # bodhi-client binding API save_override calculates expiration + # date by adding duration to datetime.utcnow + # This comparison should use utcnow as well. + if expiration_date < utcnow: + self.log.debug('Buildroot override is expired on %s', + override['expiration_date']) + self.log.debug('Extend expiration date from today in UTC.') + base_date = utcnow + else: + self.log.debug( + 'Extend expiration date from future expiration date.') + base_date = expiration_date + + if isinstance(duration, datetime): + if duration < utcnow: + raise pyrpkg.rpkgError( + 'At least, specified expiration date {0} should be ' + 'future date.'.format(duration.strftime('%Y-%m-%d'))) + if duration < base_date: + self.log.warning( + 'Expiration date %s to be set is before override current' + ' expiration date %s', + duration, base_date) + # Keep time unchanged + new_expiration_date = datetime( + year=duration.year, + month=duration.month, + day=duration.day, + hour=base_date.hour, + minute=base_date.minute, + second=base_date.second) + else: + new_expiration_date = base_date + timedelta(days=duration) + + try: + self.log.debug('Extend override expiration date to %s', + new_expiration_date) + override = bodhi.extend_override(override, new_expiration_date) + except Exception as e: + self.log.error('Cannot extend override expiration.') + raise pyrpkg.rpkgError(str(e)) + else: + self.log.info(bodhi.override_str(override, minimal=False)) + if __name__ == "__main__": from fedpkg.__main__ import main diff --git a/fedpkg/cli.py b/fedpkg/cli.py index d55259a..9442030 100644 --- a/fedpkg/cli.py +++ b/fedpkg/cli.py @@ -22,6 +22,8 @@ import pkg_resources import six import textwrap +from datetime import datetime + from six.moves.configparser import NoSectionError from six.moves.configparser import NoOptionError from six.moves.urllib_parse import urlparse @@ -243,6 +245,16 @@ and created: raise argparse.ArgumentTypeError( 'override should have 1 day to exist at least.') + def validate_extend_duration(value): + if value.isdigit(): + return validate_duration(value) + match = re.match(r'(\d{4})-(\d{1,2})-(\d{1,2})', value) + if not match: + raise argparse.ArgumentTypeError( + 'Invalid expiration date. Valid format: yyyy-mm-dd.') + y, m, d = match.groups() + return datetime(year=int(y), month=int(m), day=int(d)) + override_parser = self.subparsers.add_parser( 'override', help='Manage buildroot overrides') @@ -286,6 +298,48 @@ Create for a specified build: ' guessed from current release branch.') create_parser.set_defaults(command=self.create_buildroot_override) + extend_parser = override_subparser.add_parser( + 'extend', + help='Extend buildroot override expiration', + formatter_class=argparse.RawDescriptionHelpFormatter, + description='''\ +Extend buildroot override expiration. + +An override expiration date could be extended by number of days or a specific +date. If override is expired, expiration date will be extended from the date +of today, otherwise from the expiration date. + +Command extend accepts an optional build NVR to find out its override in +advance. If there is no such an override created previously, please use +`override create` to create one. If build NVR is omitted, command extend must +run inside a package repository and build will be guessed from current release +branch. + +Examples: + +1. To give 2 days to override for build somepkg-0.2-1.fc28 + + {0} override extend 2 somepkg-0.2-1.fc28 + +2. To extend expiration date to 2018-7-1 + + cd /path/to/somepkg + {0} switch-branch f28 + {0} override extend 2018-7-1 +'''.format(self.name)) + extend_parser.add_argument( + 'duration', + type=validate_extend_duration, + help='Number of days to extend the expiration date, or set the ' + 'expiration date directly. Valid date format: yyyy-mm-dd.') + extend_parser.add_argument( + 'NVR', + nargs='?', + help='Buildroot override expiration for this build will be ' + 'extended. If omitted, build will be guessed from current ' + 'release branch.') + extend_parser.set_defaults(command=self.extend_buildroot_override) + # Target functions go here def retire(self): # Skip if package is already retired... @@ -698,3 +752,15 @@ suggest_reboot=False build=self.args.NVR or self.cmd.nvr, duration=self.args.duration, notes=self.args.notes) + + def extend_buildroot_override(self): + check_bodhi_version() + if self.args.NVR: + if not self.cmd.anon_kojisession.getBuild(self.args.NVR): + raise rpkgError( + 'Build {0} does not exist.'.format(self.args.NVR)) + bodhi_config = self._get_bodhi_config() + self.cmd.extend_buildroot_override( + bodhi_config, + build=self.args.NVR or self.cmd.nvr, + duration=self.args.duration) diff --git a/test/test_cli.py b/test/test_cli.py index a71c6ba..4024505 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -29,6 +29,7 @@ except ImportError: from datetime import datetime, timedelta from tempfile import mkdtemp from os import rmdir +from freezegun import freeze_time import six from six.moves.configparser import NoOptionError @@ -1138,7 +1139,7 @@ class TestBodhiOverride(CliTestCase): """Test command override""" @patch('fedpkg.cli.check_bodhi_version') - @patch('bodhi.client.bindings.BodhiClient') + @patch('fedpkg.BodhiClient') def test_create_for_given_build(self, BodhiClient, check_bodhi_version): bodhi_client = BodhiClient.return_value bodhi_client.list_overrides.return_value = {'total': 0} @@ -1171,7 +1172,7 @@ class TestBodhiOverride(CliTestCase): notes='build for fedpkg') @patch('fedpkg.cli.check_bodhi_version') - @patch('bodhi.client.bindings.BodhiClient') + @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) def test_create_from_current_branch( self, nvr, BodhiClient, check_bodhi_version): @@ -1195,7 +1196,7 @@ class TestBodhiOverride(CliTestCase): notes='build for fedpkg') @patch('fedpkg.cli.check_bodhi_version') - @patch('bodhi.client.bindings.BodhiClient') + @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) def test_override_already_exists_but_expired( self, nvr, BodhiClient, check_bodhi_version): @@ -1226,7 +1227,7 @@ class TestBodhiOverride(CliTestCase): 'rpkg-1.54-2.fc28') @patch('fedpkg.cli.check_bodhi_version') - @patch('bodhi.client.bindings.BodhiClient') + @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) def test_override_already_exists_but_not_expired( self, nvr, BodhiClient, check_bodhi_version): @@ -1254,3 +1255,264 @@ class TestBodhiOverride(CliTestCase): log.info.assert_any_call( 'Buildroot override for %s already exists and not ' 'expired.', 'rpkg-1.54-2.fc28') + + +@unittest.skipUnless(bodhi, 'Skip if no supported bodhi-client is available') +class TestBodhiOverrideExtend(CliTestCase): + """Test command `override extend`""" + + def setUp(self): + super(TestBodhiOverrideExtend, self).setUp() + + # No need to check bodhi version for tests + self.cbv_p = patch('fedpkg.cli.check_bodhi_version') + self.cbv_p.start() + + self.anon_kojisession_p = patch('fedpkg.Commands.anon_kojisession', + new_callable=PropertyMock) + self.anon_kojisession_m = self.anon_kojisession_p.start() + self.kojisession = self.anon_kojisession_m.return_value + + # Fake build returned from Koji for the specified build NVR in tests + self.kojisession.getBuild.return_value = {'build_id': 1} + + def tearDown(self): + self.anon_kojisession_p.stop() + self.cbv_p.stop() + super(TestBodhiOverrideExtend, self).tearDown() + + def test_specified_build_not_exist(self): + self.kojisession.getBuild.return_value = None + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', '7', 'somepkg-1.54-2.fc28' + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + six.assertRaisesRegex( + self, rpkgError, 'Build somepkg-1.54-2.fc28 does not exist.', + cli.extend_buildroot_override) + + @patch('fedpkg.BodhiClient.list_overrides') + def test_no_override_for_build(self, list_overrides): + list_overrides.return_value = {'total': 0} + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', '7', 'somepkg-1.54-2.fc28' + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + with patch.object(cli.cmd, 'log') as log: + cli.extend_buildroot_override() + log.info.assert_any_call('No buildroot override for build %s', + 'somepkg-1.54-2.fc28') + + @patch('fedpkg.BodhiClient.list_overrides') + @patch('fedpkg.BodhiClient.csrf') + @patch('fedpkg.BodhiClient.send_request') + def test_extend_override_by_days( + self, send_request, csrf, list_overrides): + utcnow = datetime.utcnow() + override_expiration_date = utcnow + timedelta(days=7) + build_nvr = 'somepkg-1.54-2.fc28' + build_override = { + 'expiration_date': + override_expiration_date.strftime('%Y-%m-%d %H:%M:%S'), + 'nvr': build_nvr, + 'notes': 'build for other package', + 'build': {'nvr': build_nvr}, + 'submitter': {'name': 'someone'}, + 'expired_date': utcnow - timedelta(days=20) + } + + list_overrides.return_value = { + 'total': 1, + 'overrides': [build_override] + } + edited_override = build_override.copy() + expected_expiration_date = override_expiration_date + timedelta(days=2) + edited_override['expiration_date'] = \ + expected_expiration_date.strftime('%Y-%m-%d %H:%M:%S') + send_request.return_value = edited_override + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', '2', build_nvr + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + cli.extend_buildroot_override() + + # Ensure no microsecond is included in the expected expiration data + new_date = override_expiration_date + timedelta(days=2) + expected_expiration_date = datetime(year=new_date.year, + month=new_date.month, + day=new_date.day, + hour=new_date.hour, + minute=new_date.minute, + second=new_date.second) + request_data = { + 'expiration_date': expected_expiration_date, + 'nvr': build_nvr, + 'notes': build_override['notes'], + 'edited': build_nvr, + 'csrf_token': csrf.return_value, + } + send_request.assert_called_once_with( + 'overrides/', verb='POST', auth=True, data=request_data) + + @patch('fedpkg.BodhiClient.list_overrides') + @patch('fedpkg.BodhiClient.csrf') + @patch('fedpkg.BodhiClient.send_request') + def test_extend_override_by_specific_date( + self, send_request, csrf, list_overrides): + utcnow = datetime.utcnow() + override_expiration_date = utcnow + timedelta(days=7) + build_nvr = 'somepkg-1.54-2.fc28' + build_override = { + 'expiration_date': + override_expiration_date.strftime('%Y-%m-%d %H:%M:%S'), + 'nvr': build_nvr, + 'notes': 'build for other package', + 'build': {'nvr': build_nvr}, + 'submitter': {'name': 'someone'}, + 'expired_date': utcnow - timedelta(days=20) + } + + list_overrides.return_value = { + 'total': 1, + 'overrides': [build_override] + } + + new_expiration_date = override_expiration_date + timedelta(days=4) + # Ensure no microsecond is included in the expected expiration data + expected_expiration_date = datetime( + year=new_expiration_date.year, + month=new_expiration_date.month, + day=new_expiration_date.day, + hour=override_expiration_date.hour, + minute=override_expiration_date.minute, + second=override_expiration_date.second) + + edited_override = build_override.copy() + edited_override['expiration_date'] = \ + expected_expiration_date.strftime('%Y-%m-%d %H:%M:%S') + send_request.return_value = edited_override + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', new_expiration_date.strftime('%Y-%m-%d'), + build_nvr + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + cli.extend_buildroot_override() + + request_data = { + 'expiration_date': expected_expiration_date, + 'nvr': build_nvr, + 'notes': build_override['notes'], + 'edited': build_nvr, + 'csrf_token': csrf.return_value, + } + send_request.assert_called_once_with( + 'overrides/', verb='POST', auth=True, data=request_data) + + @patch('fedpkg.BodhiClient.list_overrides') + @patch('fedpkg.BodhiClient.csrf') + @patch('fedpkg.BodhiClient.send_request') + @freeze_time('2018-06-08 16:17:30') + def test_extend_for_expired_override( + self, send_request, csrf, list_overrides): + utcnow = datetime.utcnow() + # Make override expired + override_expiration_date = utcnow - timedelta(days=7) + build_nvr = 'somepkg-1.54-2.fc28' + build_override = { + 'expiration_date': + override_expiration_date.strftime('%Y-%m-%d %H:%M:%S'), + 'nvr': build_nvr, + 'notes': 'build for other package', + 'build': {'nvr': build_nvr}, + 'submitter': {'name': 'someone'}, + 'expired_date': utcnow - timedelta(days=20) + } + + list_overrides.return_value = { + 'total': 1, + 'overrides': [build_override] + } + + # Ensure no microsecond is included in the expected expiration data + new_date = utcnow + timedelta(days=2) + expected_expiration_date = datetime( + year=new_date.year, + month=new_date.month, + day=new_date.day, + hour=new_date.hour, + minute=new_date.minute, + second=new_date.second) + + edited_override = build_override.copy() + edited_override['expiration_date'] = \ + expected_expiration_date.strftime('%Y-%m-%d %H:%M:%S') + send_request.return_value = edited_override + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', '2', build_nvr + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + cli.extend_buildroot_override() + + request_data = { + 'expiration_date': expected_expiration_date, + 'nvr': build_nvr, + 'notes': build_override['notes'], + 'edited': build_nvr, + 'csrf_token': csrf.return_value, + } + send_request.assert_called_once_with( + 'overrides/', verb='POST', auth=True, data=request_data) + + @patch('fedpkg.BodhiClient.list_overrides') + @patch('fedpkg.BodhiClient.csrf') + @patch('fedpkg.BodhiClient.extend_override') + def test_error_handled_properly_when_fail_to_request( + self, extend_override, csrf, list_overrides): + extend_override.side_effect = Exception + + utcnow = datetime.utcnow() + override_expiration_date = utcnow + timedelta(days=7) + build_nvr = 'somepkg-1.54-2.fc28' + + list_overrides.return_value = { + 'total': 1, + 'overrides': [{ + 'expiration_date': + override_expiration_date.strftime('%Y-%m-%d %H:%M:%S'), + 'nvr': build_nvr, + 'notes': 'build for other package', + 'build': {'nvr': build_nvr}, + 'submitter': {'name': 'someone'}, + 'expired_date': utcnow - timedelta(days=20) + }] + } + + cli_cmd = [ + 'fedpkg', '--path', self.cloned_repo_path, + 'override', 'extend', '2', build_nvr + ] + + with patch('sys.argv', new=cli_cmd): + cli = self.new_cli() + six.assertRaisesRegex(self, rpkgError, '', + cli.extend_buildroot_override) diff --git a/tests-requirements.txt b/tests-requirements.txt index cdfe964..81997f0 100644 --- a/tests-requirements.txt +++ b/tests-requirements.txt @@ -1,3 +1,4 @@ mock == 1.0.1 nose == 1.3.7 nose-cov +freezegun From ec096d2992a7ef3cb57305352db215832497628f Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Jun 11 2018 03:39:45 +0000 Subject: [PATCH 2/3] Refine command override create * Pass username to BodhiClient class * Use datetime.utcnow instead of datetime.now, which is same as what bodhi-client API does * Print created override by call to BodhiClient.override_str rather than printing by fedpkg itself * Show fedpkg or fedpkg-stage in description accordingly * Update tests. Signed-off-by: Chenxiong Qi --- diff --git a/fedpkg/__init__.py b/fedpkg/__init__.py index fa8e08b..77e500e 100644 --- a/fedpkg/__init__.py +++ b/fedpkg/__init__.py @@ -257,7 +257,8 @@ class Commands(pyrpkg.Commands): def create_buildroot_override(self, bodhi_config, build, duration, notes=''): - bodhi = BodhiClient(staging=bodhi_config['staging']) + bodhi = BodhiClient(username=self.user, + staging=bodhi_config['staging']) result = bodhi.list_overrides(builds=build) if result['total'] == 0: try: @@ -271,15 +272,12 @@ class Commands(pyrpkg.Commands): self.log.error(str(e)) raise pyrpkg.rpkgError('Cannot create override.') else: - self.log.info('Override is created.') - self.log.info('Expiration date: %s', - override['expiration_date']) - self.log.info('Notes: %s', override['notes']) + self.log.info(bodhi.override_str(override, minimal=False)) else: override = result['overrides'][0] expiration_date = datetime.strptime(override['expiration_date'], '%Y-%m-%d %H:%M:%S') - if expiration_date < datetime.now(): + if expiration_date < datetime.utcnow(): self.log.info( 'Buildroot override for %s exists and is expired. Consider' ' using command `override extend` to extend duration.', diff --git a/fedpkg/cli.py b/fedpkg/cli.py index 9442030..a0e7123 100644 --- a/fedpkg/cli.py +++ b/fedpkg/cli.py @@ -274,13 +274,13 @@ Examples: Create a buildroot override from build guessed from release branch. Note that, command must run inside a package repository. - fedpkg switch-branch f28 - fedpkg override create --duration 5 + {0} switch-branch f28 + {0} override create --duration 5 Create for a specified build: - fedpkg override create --duration 5 package-1.0-1.fc28 -''') + {0} override create --duration 5 package-1.0-1.fc28 +'''.format(self.name)) create_parser.add_argument( '--duration', type=validate_duration, @@ -746,6 +746,10 @@ suggest_reboot=False def create_buildroot_override(self): """Create a buildroot override in Bodhi""" check_bodhi_version() + if self.args.NVR: + if not self.cmd.anon_kojisession.getBuild(self.args.NVR): + raise rpkgError( + 'Build {0} does not exist.'.format(self.args.NVR)) bodhi_config = self._get_bodhi_config() self.cmd.create_buildroot_override( bodhi_config, diff --git a/test/test_cli.py b/test/test_cli.py index 4024505..aa922b4 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -1138,9 +1138,27 @@ class TestCheckBodhiVersion(unittest.TestCase): class TestBodhiOverride(CliTestCase): """Test command override""" - @patch('fedpkg.cli.check_bodhi_version') + def setUp(self): + super(TestBodhiOverride, self).setUp() + + self.cbv_p = patch('fedpkg.cli.check_bodhi_version') + self.cbv_m = self.cbv_p.start() + + self.anon_kojisession_p = patch('fedpkg.Commands.anon_kojisession', + new_callable=PropertyMock) + self.anon_kojisession_m = self.anon_kojisession_p.start() + self.kojisession = self.anon_kojisession_m.return_value + + # Fake build returned from Koji for the specified build NVR in tests + self.kojisession.getBuild.return_value = {'build_id': 1} + + def tearDown(self): + self.anon_kojisession_p.stop() + self.cbv_p.stop() + super(TestBodhiOverride, self).tearDown() + @patch('fedpkg.BodhiClient') - def test_create_for_given_build(self, BodhiClient, check_bodhi_version): + def test_create_for_given_build(self, BodhiClient): bodhi_client = BodhiClient.return_value bodhi_client.list_overrides.return_value = {'total': 0} expiration_date = datetime.now() + timedelta(days=7) @@ -1162,20 +1180,20 @@ class TestBodhiOverride(CliTestCase): with patch.object(cli.cmd, 'log') as log: cli.create_buildroot_override() - log.info.assert_any_call('Expiration date: %s', - new_override['expiration_date']) - log.info.assert_any_call('Notes: %s', new_override['notes']) + bodhi_client.override_str.assert_called_once_with( + bodhi_client.save_override.return_value, + minimal=False) + log.info.assert_any_call( + bodhi_client.override_str.return_value) bodhi_client.save_override.assert_called_once_with( nvr='rpkg-1.54-1.fc28', duration=7, notes='build for fedpkg') - @patch('fedpkg.cli.check_bodhi_version') @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) - def test_create_from_current_branch( - self, nvr, BodhiClient, check_bodhi_version): + def test_create_from_current_branch(self, nvr, BodhiClient): nvr.return_value = 'rpkg-1.54-2.fc28' bodhi_client = BodhiClient.return_value bodhi_client.list_overrides.return_value = {'total': 0} @@ -1195,11 +1213,9 @@ class TestBodhiOverride(CliTestCase): duration=7, notes='build for fedpkg') - @patch('fedpkg.cli.check_bodhi_version') @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) - def test_override_already_exists_but_expired( - self, nvr, BodhiClient, check_bodhi_version): + def test_override_already_exists_but_expired(self, nvr, BodhiClient): nvr.return_value = 'rpkg-1.54-2.fc28' today = datetime.today() fake_expiration_date = today - timedelta(days=10) @@ -1226,11 +1242,9 @@ class TestBodhiOverride(CliTestCase): ' using command `override extend` to extend duration.', 'rpkg-1.54-2.fc28') - @patch('fedpkg.cli.check_bodhi_version') @patch('fedpkg.BodhiClient') @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) - def test_override_already_exists_but_not_expired( - self, nvr, BodhiClient, check_bodhi_version): + def test_override_already_exists_but_not_expired(self, nvr, BodhiClient): nvr.return_value = 'rpkg-1.54-2.fc28' today = datetime.today() fake_expiration_date = today + timedelta(days=10) From 251f3107febf7808938435f2429298d088039a7a Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Jun 11 2018 09:44:27 +0000 Subject: [PATCH 3/3] Handle Bodhi login automatically This refers to what Bodhi CLI errorhandler does. The reason to handle login automatically is, in fedpkg implementation, list_overrides is called pior to save_overrides and send_request. That causes Bodhi cookies is stored, and then it results in AuthError during subsequent call, e.g. to save_overrides. So, the result behavior is similar with bodhi CLI, that is password is required to be entered only once until it is unavailable. Signed-off-by: Chenxiong Qi --- diff --git a/fedpkg/__init__.py b/fedpkg/__init__.py index 77e500e..7888a1a 100644 --- a/fedpkg/__init__.py +++ b/fedpkg/__init__.py @@ -28,7 +28,17 @@ except ImportError: if _BodhiClient is not None: + from fedora.client import AuthError + class BodhiClient(_BodhiClient): + def save_override(self, *args, **kwargs): + try: + super(BodhiClient, self).save_override(*args, **kwargs) + except AuthError: + self._session.clear() + self.csrf_token = None + super(BodhiClient, self).save_override(*args, **kwargs) + def extend_override(self, override, expiration_date): data = dict( nvr=override['nvr'], @@ -37,8 +47,14 @@ if _BodhiClient is not None: edited=override['nvr'], csrf_token=self.csrf(), ) - return self.send_request( - 'overrides/', verb='POST', auth=True, data=data) + try: + return self.send_request( + 'overrides/', verb='POST', auth=True, data=data) + except AuthError: + self._session.clear() + self.csrf_token = None + return self.send_request( + 'overrides/', verb='POST', auth=True, data=data) class Commands(pyrpkg.Commands):