From e690d4032263f906a5fc38d1e3d708670f56db02 Mon Sep 17 00:00:00 2001 From: Aurélien Bompard Date: Mar 24 2022 10:40:22 +0000 Subject: [PATCH 1/2] Use Bodhi Client >= 6.0.0 Signed-off-by: Aurélien Bompard --- diff --git a/fedpkg/__init__.py b/fedpkg/__init__.py index a52c70d..5779cac 100644 --- a/fedpkg/__init__.py +++ b/fedpkg/__init__.py @@ -22,10 +22,8 @@ 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 +from bodhi.client.bindings import BodhiClient +from bodhi.client.constants import UPDATE_TYPES, REQUEST_TYPES try: from distro import linux_distribution # noqa @@ -33,57 +31,6 @@ except ImportError: from platform import linux_distribution # noqa -if _BodhiClient is not None: - from fedora.client import AuthError - - def clear_csrf_and_retry(func): - """Clear csrf token and retry - - fedpkg uses Bodhi Python binding API list_overrides first before other - save and extend APIs. That causes a readonly csrf token is received, - which will be got again when next time to construct request data to - modify updates. That is not expected and AuthError will be raised. - - So, the solution is to capture the AuthError error, clear the token and - try to modify update again by requesting another token with user's - credential. - """ - def _decorator(self, *args, **kwargs): - try: - return func(self, *args, **kwargs) - except AuthError: - self._session.cookies.clear() - self.csrf_token = None - return func(self, *args, **kwargs) - return _decorator - - class BodhiClient(_BodhiClient): - """Customized BodhiClient for fedpkg""" - - UPDATE_TYPES = ['bugfix', 'security', 'enhancement', 'newpackage'] - REQUEST_TYPES = ['testing', 'stable'] - - @clear_csrf_and_retry - def save(self, *args, **kwargs): - return super(BodhiClient, self).save(*args, **kwargs) - - @clear_csrf_and_retry - def save_override(self, *args, **kwargs): - return super(BodhiClient, self).save_override(*args, **kwargs) - - @clear_csrf_and_retry - 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): def __init__(self, *args, **kwargs): @@ -344,8 +291,7 @@ class Commands(pyrpkg.Commands): def update(self, bodhi_config, template='bodhi.template', bugs=[]): """Submit an update to bodhi using the provided template.""" - bodhi = BodhiClient(username=self.user, - staging=bodhi_config['staging']) + bodhi = BodhiClient(staging=bodhi_config['staging']) update_details = bodhi.parse_file(template) @@ -353,10 +299,10 @@ class Commands(pyrpkg.Commands): if not detail['type']: raise ValueError( 'Missing update type, which is required to create update.') - if detail['type'] not in BodhiClient.UPDATE_TYPES: + if detail['type'] not in UPDATE_TYPES: raise ValueError( 'Incorrect update type {0}'.format(detail['type'])) - if detail['request'] not in BodhiClient.REQUEST_TYPES: + if detail['request'] not in REQUEST_TYPES: raise ValueError( 'Incorrect request type {0}'.format(detail['request'])) @@ -368,8 +314,7 @@ class Commands(pyrpkg.Commands): def create_buildroot_override(self, bodhi_config, build, duration, notes=''): - bodhi = BodhiClient(username=self.user, - staging=bodhi_config['staging']) + bodhi = BodhiClient(staging=bodhi_config['staging']) result = bodhi.list_overrides(builds=build) if result['total'] == 0: try: @@ -398,8 +343,7 @@ class Commands(pyrpkg.Commands): 'not expired.', build) def extend_buildroot_override(self, bodhi_config, build, duration): - bodhi = BodhiClient(username=self.user, - staging=bodhi_config['staging']) + bodhi = BodhiClient(staging=bodhi_config['staging']) result = bodhi.list_overrides(builds=build) if result['total'] == 0: @@ -448,7 +392,11 @@ class Commands(pyrpkg.Commands): try: self.log.debug('Extend override expiration date to %s', new_expiration_date) - override = bodhi.extend_override(override, new_expiration_date) + override = bodhi.save_override( + nvr=override["nvr"], + notes=override["notes"], + expiration_date=new_expiration_date + ) except Exception as e: self.log.error('Cannot extend override expiration.') raise pyrpkg.rpkgError(str(e)) diff --git a/requirements.txt b/requirements.txt index 7e52a2c..20b00b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ argcomplete -bodhi-client +bodhi-client>=6.0.0 openidc-client python-bugzilla rpkg diff --git a/test/test_cli.py b/test/test_cli.py index 7bc5aef..5f1ec66 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -161,9 +161,7 @@ class TestUpdate(CliTestCase): @patch('bodhi.client.bindings.BodhiClient.csrf') @patch('bodhi.client.bindings.BodhiClient.send_request') - # Do not operate OpenIDC session file with lock - @patch('fedora.client.OpenIdBaseClient._load_cookies') - def assert_bodhi_update(self, cli, _load_cookies, send_request, csrf, + def assert_bodhi_update(self, cli, send_request, csrf, update_type=None, request_type=None, notes=None, stable_karma=None, unstable_karma=None): csrf.return_value = '123456' @@ -1581,10 +1579,8 @@ class TestBodhiOverride(CliTestCase): @patch('bodhi.client.bindings.BodhiClient.list_overrides') @patch('bodhi.client.bindings.BodhiClient.save_override') @patch('bodhi.client.bindings.BodhiClient.override_str') - # Do not acquire lock for local openidc cache file - @patch('fedora.client.OpenIdBaseClient._load_cookies') def test_create_for_given_build( - self, _load_cookies, override_str, save_override, list_overrides): + self, override_str, save_override, list_overrides): list_overrides.return_value = {'total': 0} expiration_date = datetime.now() + timedelta(days=7) new_override = { @@ -1695,46 +1691,6 @@ class TestBodhiOverride(CliTestCase): 'Buildroot override for %s already exists and not ' 'expired.', 'rpkg-1.54-2.fc28') - @patch('fedora.client.OpenIdBaseClient._load_cookies') - @patch('bodhi.client.bindings.BodhiClient.list_overrides') - @patch('bodhi.client.bindings.BodhiClient.save_override') - @patch('fedpkg.Commands.nvr', new_callable=PropertyMock) - def test_retry_create( - self, nvr, save_override, list_overrides, _load_cookies): - nvr.return_value = 'rpkg-1.54-2.fc28' - list_overrides.return_value = {'total': 0} - - # For save_override raises AuthError twice. - from fedora.client import AuthError - save_override.side_effect = AuthError - - cli_cmd = [ - 'fedpkg', '--path', self.cloned_repo_path, - 'override', 'create', - '--duration', '7', '--notes', 'build for fedpkg', - ] - - with patch('sys.argv', new=cli_cmd): - cli = self.new_cli() - - # This is raised when call save_override in the second time due to - # the AuthError is raised again. This is expected for running this - # test. - six.assertRaisesRegex(self, rpkgError, 'Cannot create override', - cli.create_buildroot_override) - - # First call to save_override should raise AuthError, and it must be - # called twice. - self.assertEqual(2, save_override.call_count) - save_override.assert_has_calls([ - call(nvr='rpkg-1.54-2.fc28', - duration=7, - notes='build for fedpkg'), - call(nvr='rpkg-1.54-2.fc28', - duration=7, - notes='build for fedpkg') - ]) - def test_invalid_duration_option(self): cli_cmds = ( ( @@ -1780,15 +1736,10 @@ class TestBodhiOverrideExtend(CliTestCase): self.anon_kojisession_m = self.anon_kojisession_p.start() self.kojisession = self.anon_kojisession_m.return_value - self.load_cookies_p = patch( - 'fedora.client.OpenIdBaseClient._load_cookies') - self.mock_load_cookies = self.load_cookies_p.start() - # Fake build returned from Koji for the specified build NVR in tests self.kojisession.getBuild.return_value = {'build_id': 1} def tearDown(self): - self.load_cookies_p.stop() self.anon_kojisession_p.stop() self.cbv_p.stop() super(TestBodhiOverrideExtend, self).tearDown() @@ -1871,7 +1822,6 @@ class TestBodhiOverrideExtend(CliTestCase): '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( @@ -1928,7 +1878,6 @@ class TestBodhiOverrideExtend(CliTestCase): '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( @@ -1986,7 +1935,6 @@ class TestBodhiOverrideExtend(CliTestCase): '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( @@ -1994,10 +1942,10 @@ class TestBodhiOverrideExtend(CliTestCase): @patch('fedpkg.BodhiClient.list_overrides') @patch('fedpkg.BodhiClient.csrf') - @patch('fedpkg.BodhiClient.extend_override') + @patch('fedpkg.BodhiClient.save_override') def test_error_handled_properly_when_fail_to_request( - self, extend_override, csrf, list_overrides): - extend_override.side_effect = Exception + self, save_override, csrf, list_overrides): + save_override.side_effect = Exception utcnow = datetime.utcnow() override_expiration_date = utcnow + timedelta(days=7) @@ -2025,72 +1973,6 @@ class TestBodhiOverrideExtend(CliTestCase): six.assertRaisesRegex(self, rpkgError, '', cli.extend_buildroot_override) - @patch('fedpkg.BodhiClient.list_overrides') - @patch('fedpkg.BodhiClient.csrf') - @patch('fedpkg.BodhiClient.send_request') - def test_retry_to_extend_override_by_days( - self, send_request, csrf, list_overrides): - utcnow = datetime.utcnow() - override_expiration_date = utcnow + timedelta(days=7) - - from fedora.client import AuthError - send_request.side_effect = AuthError - - csrf.side_effect = ['123456', '678901'] - - 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() - - # This error is expected due to the design for this test. See also - # above explanation to test of `override create`. - six.assertRaisesRegex( - self, rpkgError, '', 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) - - send_request.assert_has_calls([ - call('overrides/', verb='POST', auth=True, data={ - 'expiration_date': expected_expiration_date, - 'nvr': build_nvr, - 'notes': build_override['notes'], - 'edited': build_nvr, - 'csrf_token': token, - }) - for token in csrf.side_effect - ]) - @freeze_time('2018-07-22') @patch('fedpkg.BodhiClient.list_overrides') def test_raise_error_if_duration_less_than_today(self, list_overrides): diff --git a/tox.ini b/tox.ini index 009f3ae..1be6026 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,7 @@ commands = python -m pytest {posargs} setenv= PYCURL_SSL_LIBRARY=openssl + HOME={envtmpdir}/home [testenv:py27] deps = From 456a492b5dc82c7eccbcfae5ed93f5001a05fed9 Mon Sep 17 00:00:00 2001 From: Aurélien Bompard Date: Mar 24 2022 10:40:22 +0000 Subject: [PATCH 2/2] Drop support for Python 2 Since Bodhi Client >= 6 is not compatible with Python 2. Signed-off-by: Aurélien Bompard --- diff --git a/Makefile b/Makefile index f0008b3..2c23f7a 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,5 @@ test: $(default_targets) tox: @python3 -m venv .env @.env/bin/pip install tox - @.env/bin/tox -e py27,py36,py39,flake8,flake8python2 --parallel=auto ${TOX_POSARGS} + @.env/bin/tox -e py36,py39,flake8 --parallel=auto ${TOX_POSARGS} .PHONY: tox diff --git a/README.rst b/README.rst index 51ad961..9615e5f 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ Introduction This is the fedpkg project, which mostly is a subclass of the rpkg project. -rpkg works with Python 2.7, 3.6, 3.9 and 3.10. +rpkg works with Python 3.6, 3.9 and 3.10. License ======= @@ -17,8 +17,7 @@ Install from distribution packages ---------------------------------- fedpkg is available in Fedora and EPEL repositories. It can be installed with -package manager command. There is Python 3 package for Fedora and EPEL8; -and Python 2 package in EPEL7. +package manager command. There is a Python 3 package for Fedora and EPEL8. Install in a Fedora system:: @@ -35,7 +34,7 @@ Contribution ============ You are welcome to write patches to fix or improve rpkg. All code should work -with Python 2.7 and 3. Before you create a PR to propose your changes, +with Python 3. Before you create a PR to propose your changes, make sure Sign-off commit @@ -54,7 +53,7 @@ Before make a pull request, ensure local changes pass all test cases. Before run tests, install these packages:: - sudo dnf install python27 python36 python37 git make gcc rpm-build \ + sudo dnf install python36 python37 git make gcc rpm-build \ libcurl-devel krb5-devel openssl-devel To run tests simply, ``make test``. diff --git a/jenkins_test_py2.dockerfile b/jenkins_test_py2.dockerfile deleted file mode 100644 index 75c2e22..0000000 --- a/jenkins_test_py2.dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM centos:7 -LABEL \ - name="fedpkg test for Python 2" \ - description="Run tests using tox with Python 2" \ - vendor="fedpkg developers" \ - license="MIT" - -RUN yum -y update && yum install -y epel-release -RUN yum -y install \ - pytest \ - python2-six \ - python2-mock \ - git \ - GitPython \ - python-requests \ - PyYAML \ - python2-cccolutils \ - python2-koji \ - python2-bugzilla \ - python2-freezegun \ - bodhi-client \ - python-flake8 \ - python2-fedora \ - python2-distro \ - rpm-build -RUN yum clean all - -WORKDIR /src - -ENV PYTHONPATH "${PYTHONPATH}:./rpkg" - -CMD ["python", "-m", "pytest" ,"test"] diff --git a/requirements-py2.txt b/requirements-py2.txt deleted file mode 100644 index e1de6c2..0000000 --- a/requirements-py2.txt +++ /dev/null @@ -1,5 +0,0 @@ -argcomplete -openidc-client -python-bugzilla < 3.0.0 -rpkg -six diff --git a/setup.py b/setup.py index c7bef6d..6c9566d 100755 --- a/setup.py +++ b/setup.py @@ -63,8 +63,6 @@ setup( 'Intended Audience :: Developers', 'Topic :: Software Development :: Build Tools', 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.9', diff --git a/tox.ini b/tox.ini index 1be6026..d44425d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,13 @@ [tox] -envlist = py27,py36,py39,py310,flake8 +envlist = py36,py39,py310,flake8 [testenv] sitepackages=false basepython= - py27: {env:TOXPYTHON:python2.7} py36: {env:TOXPYTHON:python3.6} py39: {env:TOXPYTHON:python3.9} py310: {env:TOXPYTHON:python3.10} flake8: {env:TOXPYTHON:python3.6} - flake8python2: {env:TOXPYTHON:python2.7} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/tests-requirements.txt @@ -20,15 +18,6 @@ setenv= PYCURL_SSL_LIBRARY=openssl HOME={envtmpdir}/home -[testenv:py27] -deps = - -r{toxinidir}/requirements-py2.txt - -r{toxinidir}/tests-requirements.txt - [testenv:flake8] deps = flake8 commands = python -m flake8 fedpkg/ test/ - -[testenv:flake8python2] -deps = flake8 -commands = python -m flake8 fedpkg/ test/