Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-copr for openSUSE:Factory checked in at 2022-04-22 21:55:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-copr (Old) and /work/SRC/openSUSE:Factory/.python-copr.new.1538 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-copr" Fri Apr 22 21:55:04 2022 rev:3 rq:972178 version:1.119 Changes: -------- --- /work/SRC/openSUSE:Factory/python-copr/python-copr.changes 2022-03-07 17:48:38.867090271 +0100 +++ /work/SRC/openSUSE:Factory/.python-copr.new.1538/python-copr.changes 2022-04-22 21:56:18.930946921 +0200 @@ -1,0 +2,13 @@ +Fri Apr 22 12:08:48 UTC 2022 - Matej Cepl <[email protected]> + +- Update to 1.119: + - Bugfixes + - Kerberos/GSSAPI authentication for API and copr-cli + - Copr-cli re-tries connections with Copr Frontend + - Large queue improvements + - Smaller fixes + - More copr-cli options for editing chroots + - Signing packages with SHA256 + - Remote refs in committish + +------------------------------------------------------------------- Old: ---- copr-1.115.tar.gz New: ---- copr-1.119.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-copr.spec ++++++ --- /var/tmp/diff_new_pack.H0uu3Q/_old 2022-04-22 21:56:19.342947391 +0200 +++ /var/tmp/diff_new_pack.H0uu3Q/_new 2022-04-22 21:56:19.342947391 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-copr -Version: 1.115 +Version: 1.119 Release: 0 Summary: Python client for copr service License: GPL-2.0-or-later @@ -27,9 +27,12 @@ BuildRequires: %{python_module setuptools} BuildRequires: python-rpm-macros # SECTION test requirements +BuildRequires: %{python_module filelock} +BuildRequires: %{python_module future} BuildRequires: %{python_module marshmallow} BuildRequires: %{python_module munch} BuildRequires: %{python_module pytest} +BuildRequires: %{python_module requests-gssapi} BuildRequires: %{python_module requests-toolbelt} BuildRequires: %{python_module requests} BuildRequires: %{python_module six} ++++++ copr-1.115.tar.gz -> copr-1.119.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/PKG-INFO new/copr-1.119/PKG-INFO --- old/copr-1.115/PKG-INFO 2022-02-03 13:17:46.887011500 +0100 +++ new/copr-1.119/PKG-INFO 2022-04-05 10:50:41.658881400 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: copr -Version: 1.115 +Version: 1.119 Summary: Python client for copr service. Home-page: https://pagure.io/copr/copr Author: Valentin Gologuzov diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/README.rst new/copr-1.119/copr/README.rst --- old/copr-1.115/copr/README.rst 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/copr/README.rst 2022-04-05 10:49:51.000000000 +0200 @@ -14,7 +14,7 @@ - Website: https://pagure.io/copr/copr - Python-copr documentation: http://python-copr.readthedocs.org - Git: https://pagure.io/copr/copr.git -- Test instance: http://copr-fe-dev.cloud.fedoraproject.org/ +- Test instance: http://copr.stg.fedoraproject.org/ Usage: ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/test/client_v3/test_builds.py new/copr-1.119/copr/test/client_v3/test_builds.py --- old/copr-1.115/copr/test/client_v3/test_builds.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/test/client_v3/test_builds.py 2022-04-05 10:49:51.000000000 +0200 @@ -7,7 +7,7 @@ @mock.patch.object(Request, "send") class TestBuildProxy(object): - config = {"copr_url": "http://copr"} + config = {"copr_url": "http://copr", "login": "test", "token": "test"} def test_get(self, send): response = mock.Mock(spec=Response) @@ -20,14 +20,14 @@ assert build.foo == "bar" [email protected]("copr.v3.proxies.build.Request") -def test_build_distgit(request): [email protected]('copr.v3.proxies.Request.send') +def test_build_distgit(send): mock_client = Client.create_from_config_file(config_location) mock_client.build_proxy.create_from_distgit( "praiskup", "ping", "mock", committish="master", ) - assert len(request.call_args_list) == 1 - call = request.call_args_list[0] + assert len(send.call_args_list) == 1 + call = send.call_args_list[0] args = call[1] assert args['method'] == 'POST' assert args['endpoint'] == '/build/create/distgit' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/test/client_v3/test_helpers.py new/copr-1.119/copr/test/client_v3/test_helpers.py --- old/copr-1.115/copr/test/client_v3/test_helpers.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/test/client_v3/test_helpers.py 2022-04-05 10:49:51.000000000 +0200 @@ -39,7 +39,8 @@ @mock.patch("copr.v3.proxies.build.BuildProxy.get") def test_wait_custom_list(self, mock_get): - builds = List([Munch(id=1, state="succeeded"), Munch(id=2, state="failed")], proxy=BuildProxy({})) + builds = List([Munch(id=1, state="succeeded"), Munch(id=2, state="failed")], + proxy=BuildProxy({"copr_url": "http://copr", "login": "test", "token": "test"})) mock_get.side_effect = lambda id: builds[id-1] assert wait(builds) @@ -65,4 +66,4 @@ class MunchMock(Munch): - __proxy__ = BuildProxy({}) + __proxy__ = BuildProxy({"copr_url": "http://copr", "login": "test", "token": "test"}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/test/client_v3/test_modules.py new/copr-1.119/copr/test/client_v3/test_modules.py --- old/copr-1.115/copr/test/client_v3/test_modules.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/test/client_v3/test_modules.py 2022-04-05 10:49:51.000000000 +0200 @@ -24,7 +24,7 @@ shutil.rmtree(self.tmpdir) @pytest.mark.parametrize('distgit_opt', [None, 'fedora']) - @mock.patch('copr.v3.requests.requests.request') + @mock.patch('copr.v3.requests.requests.Session.request') def test_module_dist_git_choice_url(self, request, distgit_opt): proxy = ModuleProxy(self.config_auth) proxy.build_from_url('owner', 'project', 'http://test.yaml', @@ -42,7 +42,7 @@ assert json['scmurl'] == 'http://test.yaml' @pytest.mark.parametrize('distgit_opt', [None, 'fedora']) - @mock.patch('copr.v3.requests.requests.request') + @mock.patch('copr.v3.requests.requests.Session.request') def test_module_dist_git_choice_upload(self, request, distgit_opt): proxy = ModuleProxy(self.config_auth) proxy.build_from_file('owner', 'project', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/test/client_v3/test_packages.py new/copr-1.119/copr/test/client_v3/test_packages.py --- old/copr-1.115/copr/test/client_v3/test_packages.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/test/client_v3/test_packages.py 2022-04-05 10:49:51.000000000 +0200 @@ -9,7 +9,7 @@ @pytest.mark.parametrize('method_name', ['add', 'edit']) [email protected]("copr.v3.proxies.package.Request") [email protected]("copr.v3.proxies.Request.send") def test_package_distgit(request, method_name): mock_client = Client.create_from_config_file(config_location) method = getattr(mock_client.package_proxy, method_name) @@ -17,7 +17,7 @@ {"committish": "master", "distgit": "fedora"}) assert len(request.call_args_list) == 1 call = request.call_args_list[0] - endpoint = call[0][0] + endpoint = call[1]["endpoint"] args = call[1] assert args['method'] == 'POST' base_url = "/package/{0}".format(method_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/test/client_v3/test_requests.py new/copr-1.119/copr/test/client_v3/test_requests.py --- old/copr-1.115/copr/test/client_v3/test_requests.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/test/client_v3/test_requests.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,7 +1,6 @@ -import pytest from requests import Response from copr.test import mock -from copr.v3.requests import Request, handle_errors, CoprRequestException, munchify +from copr.v3.requests import Request, munchify class TestResponse(object): @@ -20,17 +19,17 @@ class TestRequest(object): def test_endpoint_url(self): - r1 = Request(endpoint="foo", api_base_url="http://copr/api_3") - assert r1.endpoint_url == "http://copr/api_3/foo" + r1 = Request(api_base_url="http://copr/api_3") + assert r1.endpoint_url("foo") == "http://copr/api_3/foo" # Leading and/or trailing slash should not be a problem - r2 = Request(endpoint="/foo/bar", api_base_url="http://copr/api_3/") - assert r2.endpoint_url == "http://copr/api_3/foo/bar" + r2 = Request(api_base_url="http://copr/api_3/") + assert r2.endpoint_url("/foo/bar") == "http://copr/api_3/foo/bar" - @mock.patch("requests.request") + @mock.patch('requests.Session.request') def test_send(self, request): - req1 = Request(endpoint="foo", api_base_url="http://copr/api_3") - resp1 = req1.send() + req1 = Request(api_base_url="http://copr/api_3") + resp1 = req1.send(endpoint="foo") request.assert_called_once() args, kwargs = request.call_args diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/__init__.py new/copr-1.119/copr/v3/__init__.py --- old/copr-1.115/copr/v3/__init__.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/v3/__init__.py 2022-04-05 10:49:51.000000000 +0200 @@ -15,7 +15,8 @@ CoprNoResultException, CoprValidationException, CoprNoConfigException, - CoprConfigException) + CoprConfigException, + CoprAuthException) __all__ = [ @@ -36,4 +37,5 @@ "CoprValidationException", "CoprNoConfigException", "CoprConfigException", + "CoprAuthException", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/exceptions.py new/copr-1.119/copr/v3/exceptions.py --- old/copr-1.115/copr/v3/exceptions.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/v3/exceptions.py 2022-04-05 10:49:51.000000000 +0200 @@ -54,6 +54,7 @@ class CoprNoConfigException(CoprException): """ Exception thrown when no config file is found + We left this exception in our code because someone can still catch it """ pass @@ -63,3 +64,9 @@ Exception thrown when the config file is incomplete or malformed. """ pass + + +class CoprAuthException(CoprException): + """ + Copr authentication failure + """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/helpers.py new/copr-1.119/copr/v3/helpers.py --- old/copr-1.115/copr/v3/helpers.py 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/copr/v3/helpers.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,9 +1,11 @@ +from __future__ import absolute_import + from functools import wraps import os import time import configparser from munch import Munch -from .exceptions import CoprNoConfigException, CoprConfigException, CoprException +from .exceptions import CoprConfigException, CoprException class List(list): @@ -25,12 +27,14 @@ raise CoprConfigException(str(ex)) if not exists: - raise CoprNoConfigException("There is no config file: {}".format(path)) + raw_config["copr-cli"] = {"copr_url": "https://copr.fedorainfracloud.org"} try: - for field in ["username", "login", "token", "copr_url"]: + for field in ["username", "login", "token", "copr_url", "gssapi"]: config[field] = raw_config["copr-cli"].get(field, None) config["encrypted"] = raw_config["copr-cli"].getboolean("encrypted", True) + config["gssapi"] = raw_config["copr-cli"].getboolean("gssapi") + except configparser.Error as err: raise CoprConfigException("Bad configuration file: {0}".format(err)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/__init__.py new/copr-1.119/copr/v3/proxies/__init__.py --- old/copr-1.115/copr/v3/proxies/__init__.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/__init__.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,7 +1,21 @@ +import errno +import json +import time import os -from ..helpers import config_from_file -from ..requests import Request, munchify -from ..helpers import for_all_methods, bind_proxy +from filelock import FileLock + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + +from future.utils import raise_from + +import requests_gssapi + +from ..requests import Request, munchify, requests, handle_errors +from ..helpers import for_all_methods, bind_proxy, config_from_file +from ..exceptions import CoprAuthException @for_all_methods(bind_proxy) @@ -12,6 +26,9 @@ def __init__(self, config): self.config = config + self._auth_token_cached = None + self._auth_username = None + self.request = Request(api_base_url=self.api_base_url, connection_attempts=config.get("connection_attempts", 1)) @classmethod def create_from_config_file(cls, path=None): @@ -24,7 +41,95 @@ @property def auth(self): - return self.config["login"], self.config["token"] + if self._auth_token_cached: + return self._auth_token_cached + if self.config.get("token"): + self._auth_token_cached = self.config["login"], self.config["token"] + self._auth_username = self.config.get("username") + elif self.config.get("gssapi"): + session_data = self._get_session_cookie_via_gssapi() + self._auth_token_cached = session_data["session"] + self._auth_username = session_data["name"] + else: + msg = "GSSAPI disabled and login:token is invalid ({0}:{1})".format( + self.config.get("login", "NOT_SET"), + self.config.get("token", "NOT_SET"), + ) + raise CoprAuthException(msg) + return self._auth_token_cached + + def _get_session_cookie_via_gssapi(self): + """ + Return the cached session for the configured username. If not already + cached, new self.get_session_via_gssapi() is performed and result is + cached into ~/.config/copr/<session_file>. + """ + url = urlparse(self.config["copr_url"]).netloc + cachedir = os.path.join(os.path.expanduser("~"), ".cache", "copr") + + try: + os.makedirs(cachedir) + except OSError as err: + if err.errno != errno.EEXIST: + raise + + session_file = os.path.join(cachedir, url + "-session") + session_data = self._load_or_download_session(session_file) + return session_data + + @staticmethod + def _load_session_from_file(session_file): + session_data = None + if os.path.exists(session_file): + with open(session_file, "r") as file: + session_data = json.load(file) + + if session_data and session_data["expiration"] > time.time(): + return session_data + return None + + def _load_or_download_session(self, session_file): + lock = FileLock(session_file + ".lock") + with lock: + session = BaseProxy._load_session_from_file(session_file) + if session: + return session + # TODO: create Munch sub-class that returns serializable dict, we + # have something like that in Cli: cli/copr_cli/util.py:serializable() + session_data = self.get_session_via_gssapi() + session_data = session_data.__dict__ + session_data.pop("__response__", None) + session_data.pop("__proxy__", None) + BaseProxy._save_session(session_file, session_data) + return session_data + + @staticmethod + def _save_session(session_file, session_data): + with open(session_file, "w") as file: + session_data["expiration"] = time.time() + 10 * 3600 # +10 hours + file.write(json.dumps(session_data, indent=4) + "\n") + + def get_session_via_gssapi(self): + """ + Obtain a _new_ session using GSSAPI route + + :return: Munch, provides user's "id", "name", "session" cookie, and + "expiration". + """ + url = self.config["copr_url"] + "/api_3/gssapi_login/" + session = requests.Session() + auth = requests_gssapi.HTTPSPNEGOAuth(opportunistic_auth=True) + try: + response = session.get(url, auth=auth) + except requests_gssapi.exceptions.SPNEGOExchangeError as err: + msg = "Can not get session for {0} cookie via GSSAPI: {1}".format( + self.config["copr_url"], err) + raise_from(CoprAuthException(msg), err) + + handle_errors(response) + retval = munchify(response) + retval.session = response.cookies.get("session") + return retval def home(self): """ @@ -33,8 +138,7 @@ :return: Munch """ endpoint = "" - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) def auth_check(self): @@ -44,6 +148,15 @@ :return: Munch """ endpoint = "/auth-check" - request = Request(endpoint, api_base_url=self.api_base_url, auth=self.auth) - response = request.send() + response = self.request.send(endpoint=endpoint, auth=self.auth) return munchify(response) + + def auth_username(self): + """ + Return the username (string) assigned to this configuration. May + contact the server and authenticate if needed. + """ + if not self._auth_username: + # perform authentication as a side effect + _ = self.auth + return self._auth_username diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/build.py new/copr-1.119/copr/v3/proxies/build.py --- old/copr-1.115/copr/v3/proxies/build.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/build.py 2022-04-05 10:49:51.000000000 +0200 @@ -2,7 +2,7 @@ import os from . import BaseProxy -from ..requests import Request, FileRequest, munchify, POST +from ..requests import FileRequest, munchify, POST from ..exceptions import CoprValidationException from ..helpers import for_all_methods, bind_proxy @@ -17,8 +17,7 @@ :return: Munch """ endpoint = "/build/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) def get_source_chroot(self, build_id): @@ -29,8 +28,7 @@ :return: Munch """ endpoint = "/build/source-chroot/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) def get_source_build_config(self, build_id): @@ -41,8 +39,7 @@ :return: Munch """ endpoint = "/build/source-build-config/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) def get_built_packages(self, build_id): @@ -53,8 +50,7 @@ :return: Munch """ endpoint = "/build/built-packages/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) def get_list(self, ownername, projectname, packagename=None, status=None, pagination=None): @@ -77,8 +73,7 @@ } params.update(pagination or {}) - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def cancel(self, build_id): @@ -89,8 +84,8 @@ :return: Munch """ endpoint = "/build/cancel/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, method=POST, auth=self.auth) return munchify(response) def create_from_urls(self, ownername, projectname, urls, buildopts=None, project_dirname=None): @@ -296,20 +291,21 @@ def _create(self, endpoint, data, files=None, buildopts=None): data = data.copy() - request_class = Request - kwargs = {"endpoint": endpoint, "api_base_url": self.api_base_url, - "data": data,"method": POST, "auth": self.auth} - if files: - request_class = FileRequest - kwargs["files"] = files - + kwargs = {"api_base_url": self.api_base_url} if files and buildopts and "progress_callback" in buildopts: kwargs["progress_callback"] = buildopts["progress_callback"] del buildopts["progress_callback"] data.update(buildopts or {}) - request = request_class(**kwargs) - response = request.send() + if not files: + response = self.request.send( + endpoint=endpoint, data=data, method=POST, auth=self.auth) + else: + kwargs["files"] = files + kwargs["connection_attempts"] = self.config.get("connection_attempts", 1) + request = FileRequest(**kwargs) + response = request.send( + endpoint=endpoint, data=data, method=POST, auth=self.auth) return munchify(response) def delete(self, build_id): @@ -320,8 +316,8 @@ :return: Munch """ endpoint = "/build/delete/{0}".format(build_id) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, method=POST, auth=self.auth) return munchify(response) def delete_list(self, build_ids): @@ -334,6 +330,6 @@ endpoint = "/build/delete/list" data = {"builds": build_ids} - request = Request(endpoint, data=data, api_base_url=self.api_base_url, method=POST, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, data=data, method=POST, auth=self.auth) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/build_chroot.py new/copr-1.119/copr/v3/proxies/build_chroot.py --- old/copr-1.115/copr/v3/proxies/build_chroot.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/build_chroot.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,7 +1,7 @@ from __future__ import absolute_import from . import BaseProxy -from ..requests import Request, munchify +from ..requests import munchify from ..helpers import for_all_methods, bind_proxy @@ -20,8 +20,7 @@ "build_id": build_id, "chrootname": chrootname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_list(self, build_id, pagination=None): @@ -38,8 +37,7 @@ "build_id": build_id, } params.update(pagination or {}) - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_build_config(self, build_id, chrootname): @@ -55,8 +53,7 @@ "build_id": build_id, "chrootname": chrootname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_built_packages(self, build_id, chrootname): @@ -72,6 +69,5 @@ "build_id": build_id, "chrootname": chrootname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/mock_chroot.py new/copr-1.119/copr/v3/proxies/mock_chroot.py --- old/copr-1.115/copr/v3/proxies/mock_chroot.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/mock_chroot.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,8 +1,7 @@ from __future__ import absolute_import -import os from . import BaseProxy -from ..requests import Request, munchify +from ..requests import munchify from ..helpers import for_all_methods, bind_proxy @@ -10,11 +9,11 @@ class MockChrootProxy(BaseProxy): def get_list(self, pagination=None): + # TODO: implement pagination """List all currently available chroots. :return: Munch """ endpoint = "/mock-chroots/list" - request = Request(endpoint, api_base_url=self.api_base_url) - response = request.send() + response = self.request.send(endpoint=endpoint) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/module.py new/copr-1.119/copr/v3/proxies/module.py --- old/copr-1.115/copr/v3/proxies/module.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/module.py 2022-04-05 10:49:51.000000000 +0200 @@ -2,7 +2,7 @@ import os from . import BaseProxy -from ..requests import Request, FileRequest, munchify, POST +from ..requests import FileRequest, munchify, POST from ..helpers import for_all_methods, bind_proxy @@ -31,9 +31,13 @@ } if distgit is not None: data["distgit"] = distgit - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def build_from_file(self, ownername, projectname, path, distgit=None): @@ -57,7 +61,16 @@ data = None if distgit is not None: data = {"distgit": distgit} - request = FileRequest(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, files=files, data=data, auth=self.auth) - response = request.send() + request = FileRequest( + files=files, + api_base_url=self.api_base_url, + connection_attempts=self.config.get("connection_attempts", 1) + ) + response = request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/monitor.py new/copr-1.119/copr/v3/proxies/monitor.py --- old/copr-1.115/copr/v3/proxies/monitor.py 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/monitor.py 2022-04-05 10:49:51.000000000 +0200 @@ -3,7 +3,7 @@ """ from copr.v3 import proxies -from copr.v3.requests import Request, munchify +from copr.v3.requests import munchify from copr.v3.helpers import for_all_methods, bind_proxy @@ -47,6 +47,5 @@ "project_dirname": project_dirname, "additional_fields[]": additional_fields, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/package.py new/copr-1.119/copr/v3/proxies/package.py --- old/copr-1.115/copr/v3/proxies/package.py 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/package.py 2022-04-05 10:49:51.000000000 +0200 @@ -1,7 +1,7 @@ from __future__ import absolute_import from . import BaseProxy from .build import BuildProxy -from ..requests import Request, munchify, POST +from ..requests import munchify, POST from ..helpers import for_all_methods, bind_proxy @@ -31,8 +31,7 @@ "with_latest_build": with_latest_build, "with_latest_succeeded_build": with_latest_succeeded_build, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_list(self, ownername, projectname, pagination=None, @@ -59,8 +58,7 @@ } params.update(pagination or {}) - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def add(self, ownername, projectname, packagename, source_type, source_dict): @@ -85,9 +83,13 @@ "package_name": packagename, } data.update(source_dict) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def edit(self, ownername, projectname, packagename, source_type=None, source_dict=None): @@ -112,9 +114,13 @@ "package_name": packagename, } data.update(source_dict or {}) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def reset(self, ownername, projectname, packagename): @@ -134,8 +140,8 @@ "projectname": projectname, "package_name": packagename, } - request = Request(endpoint, api_base_url=self.api_base_url, data=data, method=POST, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, data=data, method=POST, auth=self.auth) return munchify(response) def build(self, ownername, projectname, packagename, buildopts=None, project_dirname=None): @@ -174,6 +180,6 @@ "projectname": projectname, "package_name": packagename, } - request = Request(endpoint, api_base_url=self.api_base_url, data=data, method=POST, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, data=data, method=POST, auth=self.auth) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/project.py new/copr-1.119/copr/v3/proxies/project.py --- old/copr-1.115/copr/v3/proxies/project.py 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/project.py 2022-04-05 10:49:51.000000000 +0200 @@ -3,7 +3,7 @@ import warnings from . import BaseProxy -from ..requests import Request, munchify, POST, GET, PUT +from ..requests import munchify, POST, GET, PUT from ..helpers import for_all_methods, bind_proxy @@ -30,8 +30,7 @@ "ownername": ownername, "projectname": projectname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_list(self, ownername=None, pagination=None): @@ -47,8 +46,7 @@ "ownername": ownername, } params.update(pagination or {}) - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def search(self, query, pagination=None): @@ -64,8 +62,7 @@ "query": query, } params.update(pagination or {}) - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def add(self, ownername, projectname, chroots, description=None, instructions=None, homepage=None, @@ -136,9 +133,13 @@ _compat_use_bootstrap_container(data, use_bootstrap_container) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def edit(self, ownername, projectname, chroots=None, description=None, instructions=None, homepage=None, @@ -207,9 +208,13 @@ _compat_use_bootstrap_container(data, use_bootstrap_container) - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def delete(self, ownername, projectname): @@ -228,9 +233,13 @@ data = { "verify": True, } - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def fork(self, ownername, projectname, dstownername, dstprojectname, confirm=False): @@ -255,9 +264,13 @@ "ownername": dstownername, "confirm": confirm, } - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) def get_permissions(self, ownername, projectname): @@ -277,14 +290,8 @@ "ownername": ownername, "projectname": projectname, } - request = Request( - endpoint, - api_base_url=self.api_base_url, - auth=self.auth, - method=GET, - params=params) - - response = request.send() + response = self.request.send( + endpoint=endpoint, params=params, auth=self.auth) return munchify(response) def set_permissions(self, ownername, projectname, permissions): @@ -312,15 +319,13 @@ "ownername": ownername, "projectname": projectname, } - request = Request( - endpoint, - api_base_url=self.api_base_url, - auth=self.auth, - method=PUT, - params=params, - data=permissions) - - request.send() + self.request.send( + endpoint=endpoint, + method=PUT, + params=params, + data=permissions, + auth=self.auth, + ) def request_permissions(self, ownername, projectname, permissions): """ @@ -341,15 +346,13 @@ "ownername": ownername, "projectname": projectname, } - request = Request( - endpoint, - api_base_url=self.api_base_url, - auth=self.auth, - method=PUT, - params=params, - data=permissions) - - request.send() + self.request.send( + endpoint=endpoint, + method=PUT, + params=params, + data=permissions, + auth=self.auth, + ) def regenerate_repos(self, ownername, projectname): """ @@ -363,13 +366,6 @@ "ownername": ownername, "projectname": projectname } - request = Request( - endpoint, - api_base_url=self.api_base_url, - auth=self.auth, - method=PUT, - params=params) - - request.send() - response = request.send() + response = self.request.send( + endpoint=endpoint, method=PUT, params=params, auth=self.auth) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/project_chroot.py new/copr-1.119/copr/v3/proxies/project_chroot.py --- old/copr-1.115/copr/v3/proxies/project_chroot.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/project_chroot.py 2022-04-05 10:49:51.000000000 +0200 @@ -2,7 +2,7 @@ import os from . import BaseProxy -from ..requests import Request, FileRequest, munchify, POST +from ..requests import FileRequest, munchify, POST from ..helpers import for_all_methods, bind_proxy @@ -24,8 +24,7 @@ "projectname": projectname, "chrootname": chrootname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) def get_build_config(self, ownername, projectname, chrootname): @@ -43,14 +42,14 @@ "projectname": projectname, "chrootname": chrootname, } - request = Request(endpoint, api_base_url=self.api_base_url, params=params) - response = request.send() + response = self.request.send(endpoint=endpoint, params=params) return munchify(response) # pylint: disable=too-many-arguments def edit(self, ownername, projectname, chrootname, additional_packages=None, additional_repos=None, - comps=None, delete_comps=False, with_opts=None, without_opts=None, - bootstrap=None, bootstrap_image=None, isolation=None): + additional_modules=None, comps=None, delete_comps=False, with_opts=None, without_opts=None, + bootstrap=None, bootstrap_image=None, isolation=None, + reset_fields=None): """ Edit a chroot configuration in a project @@ -59,6 +58,7 @@ :param str chrootname: :param list additional_packages: buildroot packages for the chroot :param list additional_repos: buildroot additional additional_repos + :param list additional_modules: additional modules for the chroot :param str comps: file path to the comps.xml file :param bool delete_comps: if True, current comps.xml will be removed :param list with_opts: Mock --with option @@ -68,6 +68,10 @@ :param str bootstrap_image: Implies 'bootstrap=image'. :param str isolation: Mock isolation feature setup. Possible values are 'default', 'simple', 'nspawn'. + :param list reset_fields: list of chroot attributes, that should be + reseted to their respective defaults. Possible values are + `additional_packages`, `additional_modules`, `isolation`, etc. See + the output of `ProjectProxy.get` for all the possible field names. :return: Munch """ endpoint = "/project-chroot/edit/{ownername}/{projectname}/{chrootname}" @@ -83,19 +87,30 @@ data = { "additional_repos": additional_repos, "additional_packages": additional_packages, + "additional_modules": additional_modules, "delete_comps": delete_comps, "with_opts": with_opts, "without_opts": without_opts, "bootstrap": bootstrap, "bootstrap_image": bootstrap_image, "isolation": isolation, + "reset_fields": reset_fields, } files = {} if comps: comps_f = open(comps, "rb") files["upload_comps"] = (os.path.basename(comps_f.name), comps_f, "application/text") - request = FileRequest(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, data=data, files=files, auth=self.auth) - response = request.send() + request = FileRequest( + api_base_url=self.api_base_url, + files=files, + connection_attempts=self.config.get("connection_attempts", 1) + ) + response = request.send( + endpoint=endpoint, + method=POST, + params=params, + data=data, + auth=self.auth, + ) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/proxies/webhook.py new/copr-1.119/copr/v3/proxies/webhook.py --- old/copr-1.115/copr/v3/proxies/webhook.py 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/copr/v3/proxies/webhook.py 2022-04-05 10:49:51.000000000 +0200 @@ -5,7 +5,7 @@ from __future__ import absolute_import from . import BaseProxy -from ..requests import Request, munchify, POST +from ..requests import munchify, POST from ..helpers import for_all_methods, bind_proxy @@ -29,7 +29,6 @@ "ownername": ownername, "projectname": projectname, } - request = Request(endpoint, api_base_url=self.api_base_url, method=POST, - params=params, auth=self.auth) - response = request.send() + response = self.request.send( + endpoint=endpoint, method=POST, params=params, auth=self.auth) return munchify(response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr/v3/requests.py new/copr-1.119/copr/v3/requests.py --- old/copr-1.115/copr/v3/requests.py 2022-02-01 00:11:50.000000000 +0100 +++ new/copr-1.119/copr/v3/requests.py 2022-04-05 10:49:51.000000000 +0200 @@ -2,11 +2,14 @@ import os import json +import time import requests +import requests_gssapi +from copr.v3.helpers import List from munch import Munch +from future.utils import raise_from from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor -from .helpers import List -from .exceptions import CoprRequestException, CoprNoResultException, CoprTimeoutException +from .exceptions import CoprRequestException, CoprNoResultException, CoprTimeoutException, CoprAuthException GET = "GET" @@ -18,67 +21,80 @@ # This should be a replacement of the _fetch method from APIv1 # We can have Request, FileRequest, AuthRequest/UnAuthRequest, ... - def __init__(self, endpoint, api_base_url=None, method=None, data=None, params=None, auth=None): + def __init__(self, api_base_url=None, connection_attempts=1): """ - :param endpoint: :param api_base_url: - :param method: - :param data: dict - :param params: dict for constructing query params in URL (e.g. ?key1=val1) - :param auth: tuple (login, token) + :param connection_attempts: @TODO maybe don't have both params and data, but rather only one variable @TODO and send it as data on POST and as params on GET """ - self.endpoint = endpoint self.api_base_url = api_base_url - self._method = method or GET - self.data = data - self.params = params or {} - self.auth = auth - self.headers = None - - @property - def endpoint_url(self): - endpoint = self.endpoint.strip("/").format(**self.params) + self.connection_attempts = connection_attempts + + def endpoint_url(self, endpoint, params=None): + params = params or {} + endpoint = endpoint.strip("/").format(**params) return os.path.join(self.api_base_url, endpoint) - @property - def method(self): - return self._method.upper() - - def send(self): - try: - response = requests.request(**self._request_params) - except requests.exceptions.ConnectionError: - raise CoprRequestException("Unable to connect to {0}.".format(self.api_base_url)) + def send(self, endpoint, method=GET, data=None, params=None, headers=None, + auth=None): + session = requests.Session() + if not isinstance(auth, tuple): + # api token not available, set session cookie obtained via gssapi + session.cookies.set("session", auth) + + request_params = self._request_params( + endpoint, method, data, params, headers, auth) + + response = self._send_request_repeatedly(session, request_params) handle_errors(response) return response - @property - def _request_params(self): - return { - "url": self.endpoint_url, - "auth": self.auth, - "json": self.data, - "method": self.method, - "params": self.params, - "headers": self.headers, + def _send_request_repeatedly(self, session, request_params): + """ + Repeat the request until it succeeds, or connection retry reaches its limit. + """ + sleep = 5 + for i in range(1, self.connection_attempts + 1): + try: + response = session.request(**request_params) + except requests_gssapi.exceptions.SPNEGOExchangeError as e: + raise_from(CoprAuthException("GSSAPI authentication failed."), e) + except requests.exceptions.ConnectionError: + if i < self.connection_attempts: + time.sleep(sleep) + else: + return response + raise CoprRequestException("Unable to connect to {0}.".format(self.api_base_url)) + + def _request_params(self, endpoint, method=GET, data=None, params=None, + headers=None, auth=None): + params = { + "url": self.endpoint_url(endpoint, params), + "json": data, + "method": method.upper(), + "params": params, + "headers": headers, } + # We usually use a tuple (login, token). If this is not available, + # we use gssapi auth, which works with cookies. + if isinstance(auth, tuple): + params["auth"] = auth + return params class FileRequest(Request): - def __init__(self, endpoint, files=None, progress_callback=None, **kwargs): - super(FileRequest, self).__init__(endpoint, **kwargs) + def __init__(self, files=None, progress_callback=None, **kwargs): + super(FileRequest, self).__init__(**kwargs) self.files = files self.progress_callback = progress_callback - @property - def _request_params(self): - params = super(FileRequest, self)._request_params + def _request_params(self, *args, **kwargs): + params = super(FileRequest, self)._request_params(*args, **kwargs) data = self.files or {} - data["json"] = ("json", json.dumps(self.data), "application/json") + data["json"] = ("json", json.dumps(params["json"]), "application/json") callback = self.progress_callback or (lambda x: x) m = MultipartEncoder(data) @@ -102,6 +118,9 @@ if "error" not in response_json: return + if response.status_code == 403: + raise CoprAuthException(response_json["error"], response=response) + if response.status_code == 404: raise CoprNoResultException(response_json["error"], response=response) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr.egg-info/PKG-INFO new/copr-1.119/copr.egg-info/PKG-INFO --- old/copr-1.115/copr.egg-info/PKG-INFO 2022-02-03 13:17:46.000000000 +0100 +++ new/copr-1.119/copr.egg-info/PKG-INFO 2022-04-05 10:50:41.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: copr -Version: 1.115 +Version: 1.119 Summary: Python client for copr service. Home-page: https://pagure.io/copr/copr Author: Valentin Gologuzov diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/copr.egg-info/requires.txt new/copr-1.119/copr.egg-info/requires.txt --- old/copr-1.115/copr.egg-info/requires.txt 2022-02-03 13:17:46.000000000 +0100 +++ new/copr-1.119/copr.egg-info/requires.txt 2022-04-05 10:50:41.000000000 +0200 @@ -1,6 +1,9 @@ +filelock marshmallow requests requests-toolbelt setuptools six munch +requests-gssapi +future diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/docs/client_v2/resources_usage.rst new/copr-1.119/docs/client_v2/resources_usage.rst --- old/copr-1.115/docs/client_v2/resources_usage.rst 2022-01-04 01:09:47.000000000 +0100 +++ new/copr-1.119/docs/client_v2/resources_usage.rst 2022-04-05 10:49:51.000000000 +0200 @@ -12,7 +12,7 @@ >>> from copr import create_client2_from_params # using dev server for test - >>> cl = create_client2_from_params(root_url="http://copr-fe-dev.cloud.fedoraproject.org/") + >>> cl = create_client2_from_params(root_url="http://copr.stg.fedoraproject.org/") >>> projects = cl.projects.get_list(name="copr", limit=3) >>> for p in projects: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/python-copr.spec new/copr-1.119/python-copr.spec --- old/copr-1.115/python-copr.spec 2022-02-02 22:55:33.000000000 +0100 +++ new/copr-1.119/python-copr.spec 2022-04-05 10:49:51.000000000 +0200 @@ -9,7 +9,7 @@ %endif Name: python-copr -Version: 1.115 +Version: 1.119 Release: 1%{?dist} Summary: Python interface for Copr @@ -35,9 +35,12 @@ BuildRequires: python-six >= 1.9.0 BuildRequires: python-mock BuildRequires: python-munch +BuildRequires: python-filelock BuildRequires: python-configparser BuildRequires: pytest BuildRequires: python2-devel +BuildRequires: python2-requests-gssapi +BuildRequires: python-future # for doc package BuildRequires: python-sphinx BuildRequires: python-docutils @@ -47,11 +50,13 @@ BuildRequires: python2-requests-toolbelt BuildRequires: python2-marshmallow BuildRequires: python2-six >= 1.9.0 -BuildRequires: python2-mock BuildRequires: python2-pytest BuildRequires: python2-devel BuildRequires: python-munch +BuildRequires: python2-filelock BuildRequires: python2-configparser +BuildRequires: python2-requests-gssapi +BuildRequires: python-future # for doc package BuildRequires: python2-sphinx BuildRequires: python2-docutils @@ -78,18 +83,23 @@ Requires: python-configparser Requires: python-marshmallow Requires: python-munch +Requires: python-filelock Requires: python-requests Requires: python-requests-toolbelt Requires: python-setuptools Requires: python-six >= 1.9.0 +Requires: python-future %else Requires: python2-configparser Requires: python2-marshmallow Requires: python2-munch +Requires: python2-filelock Requires: python2-requests Requires: python2-requests-toolbelt Requires: python2-setuptools +Requires: python2-requests-gssapi Requires: python2-six >= 1.9.0 +Requires: python-future %endif %{?python_provide:%python_provide python2-copr} @@ -108,6 +118,7 @@ BuildRequires: python3-devel BuildRequires: python3-docutils BuildRequires: python3-munch +BuildRequires: python3-filelock BuildRequires: python3-marshmallow BuildRequires: python3-pytest BuildRequires: python3-setuptools @@ -115,13 +126,18 @@ BuildRequires: python3-requests-toolbelt BuildRequires: python3-six BuildRequires: python3-sphinx +BuildRequires: python3-requests-gssapi +BuildRequires: python3-future Requires: python3-marshmallow Requires: python3-munch +Requires: python3-filelock Requires: python3-requests Requires: python3-requests-toolbelt Requires: python3-setuptools Requires: python3-six +Requires: python3-requests-gssapi +Requires: python3-future %endif %{?python_provide:%python_provide python3-copr} @@ -130,6 +146,9 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx BuildRequires: python3-pytest +BuildRequires: python3-requests-gssapi +BuildRequires: python3-future +BuildRequires: python3-filelock %generate_buildrequires %pyproject_buildrequires -r @@ -221,6 +240,21 @@ %doc %{_pkgdocdir} %changelog +* Mon Apr 04 2022 Pavel Raiskup <[email protected]> 1.119-1 +- really depend on filelock component + +* Mon Apr 04 2022 Pavel Raiskup <[email protected]> 1.118-1 +- drop the python-mock build-requires again + +* Mon Apr 04 2022 Pavel Raiskup <[email protected]> 1.117-1 +- support for GSSAPI added (gssapi=true config option) +- better error message when authentication fails +- add a connection_attempts, retries connection to Frontend upon failure + +* Fri Mar 18 2022 Pavel Raiskup <[email protected]> 1.116-1 +- add support for resetting fields +- allow setting modules in 'edit-chroot' methods + * Wed Feb 02 2022 Silvie Chlupova <[email protected]> 1.115-1 - don't BuildRequires pyproject-rpm-macros directly - fix exception caused by default msg value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/requirements.txt new/copr-1.119/requirements.txt --- old/copr-1.115/requirements.txt 2021-12-12 16:37:48.000000000 +0100 +++ new/copr-1.119/requirements.txt 2022-04-05 10:49:51.000000000 +0200 @@ -2,5 +2,4 @@ # Use this file by running "$ pip install -r requirements.txt" pytest -mock sphinx diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/copr-1.115/setup.py new/copr-1.119/setup.py --- old/copr-1.115/setup.py 2022-02-02 22:55:33.000000000 +0100 +++ new/copr-1.119/setup.py 2022-04-05 10:49:51.000000000 +0200 @@ -14,12 +14,15 @@ This part is a python client to the copr service.""" requires = [ + 'filelock', 'marshmallow', 'requests', 'requests-toolbelt', 'setuptools', 'six', 'munch', + 'requests-gssapi', + 'future', ] __description__ = "Python client for copr service." @@ -30,7 +33,7 @@ setup( name='copr', - version="1.115", + version="1.119", description=__description__, long_description=long_description, author=__author__,
