Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-osc-tiny for openSUSE:Factory 
checked in at 2022-12-13 18:55:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
 and      /work/SRC/openSUSE:Factory/.python-osc-tiny.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-osc-tiny"

Tue Dec 13 18:55:24 2022 rev:25 rq:1042475 version:0.7.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes  
2022-11-03 19:14:28.724111325 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-osc-tiny.new.1835/python-osc-tiny.changes    
    2022-12-13 18:55:41.899277236 +0100
@@ -1,0 +2,8 @@
+Mon Dec 12 09:09:04 UTC 2022 - Andreas Hasenkopf <ahasenk...@suse.com>
+
+- Release 0.7.9
+  * Simplified handling of SSH keys (fixes #114)
+  * Replaced `Request.cmd` with `Request.update` (fixes #113)
+  * Added a comment parameter to project and package `set_meta`
+
+-------------------------------------------------------------------

Old:
----
  osc-tiny-0.7.7.tar.gz

New:
----
  osc-tiny-0.7.9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.BzirB0/_old  2022-12-13 18:55:44.019288551 +0100
+++ /var/tmp/diff_new_pack.BzirB0/_new  2022-12-13 18:55:44.027288594 +0100
@@ -18,7 +18,7 @@
 
 %define skip_python2 1
 Name:           python-osc-tiny
-Version:        0.7.7
+Version:        0.7.9
 Release:        0
 Summary:        Client API for openSUSE BuildService
 License:        MIT

++++++ osc-tiny-0.7.7.tar.gz -> osc-tiny-0.7.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/PKG-INFO new/osc-tiny-0.7.9/PKG-INFO
--- old/osc-tiny-0.7.7/PKG-INFO 2022-11-02 13:06:41.584857200 +0100
+++ new/osc-tiny-0.7.9/PKG-INFO 2022-12-12 13:21:46.650442600 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: osc-tiny
-Version: 0.7.7
+Version: 0.7.9
 Summary: Client API for openSUSE BuildService
 Home-page: http://github.com/crazyscientist/osc-tiny
 Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osc_tiny.egg-info/PKG-INFO 
new/osc-tiny-0.7.9/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.7.7/osc_tiny.egg-info/PKG-INFO       2022-11-02 
13:06:41.000000000 +0100
+++ new/osc-tiny-0.7.9/osc_tiny.egg-info/PKG-INFO       2022-12-12 
13:21:46.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: osc-tiny
-Version: 0.7.7
+Version: 0.7.9
 Summary: Client API for openSUSE BuildService
 Home-page: http://github.com/crazyscientist/osc-tiny
 Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/__init__.py 
new/osc-tiny-0.7.9/osctiny/__init__.py
--- old/osc-tiny-0.7.7/osctiny/__init__.py      2022-11-02 13:06:32.000000000 
+0100
+++ new/osc-tiny-0.7.9/osctiny/__init__.py      2022-12-12 13:21:36.000000000 
+0100
@@ -6,4 +6,4 @@
 
 __all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
            'projects', 'search', 'users']
-__version__ = "0.7.7"
+__version__ = "0.7.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/extensions/bs_requests.py 
new/osc-tiny-0.7.9/osctiny/extensions/bs_requests.py
--- old/osc-tiny-0.7.7/osctiny/extensions/bs_requests.py        2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/extensions/bs_requests.py        2022-12-12 
13:21:36.000000000 +0100
@@ -4,6 +4,8 @@
 """
 from urllib.parse import urljoin
 
+from lxml.etree import XMLSyntaxError
+
 from ..utils.base import ExtensionBase
 
 
@@ -63,6 +65,37 @@
 
         return self.osc.get_objectified_xml(response)
 
+    def update(self, request_id, **kwargs):
+        """
+        Update request or execute command
+
+        .. note::
+
+            In most cases, the API returns an XML response, so this method 
will try to return an
+            objectified XML element. Otherwise, if parsing fails due to a 
syntax error, the response
+            body is returned as plain text. In case of all other errors, this 
method lets the
+            caller handle the exception.
+
+        :param request_id: ID of the request
+        :param kwargs: See Build Service
+                       `API documentation 
<https://build.opensuse.org/apidocs/index>`_ for accepted
+                       keys and values.
+        :return: Response content
+        :rtype: lxml.objectify.ObjectifiedElement or plain text
+
+        .. versionadded:: 0.7.8
+        """
+        request_id = self._validate_id(request_id)
+        response = self.osc.request(
+            url=urljoin(self.osc.url, self.base_path + request_id),
+            method="POST",
+            params=kwargs
+        )
+        try:
+            return self.osc.get_objectified_xml(response)
+        except XMLSyntaxError:
+            return response.text
+
     def cmd(self, request_id, cmd="diff", **kwargs):
         """
         Get the result of the specified command
@@ -88,34 +121,14 @@
 
             * Added ``addreview`` to list of allowed commands
             * Added validation for arguments of command ``changereviewstate``
-        """
-        allowed_cmds = ['diff', 'changereviewstate', 'addreview']
-        allowed_review_states = ['new', 'accepted', 'declined', 'deleted',
-                                 'revoked', 'superseded']
-        if cmd not in allowed_cmds:
-            raise ValueError("Invalid command: '{}'. Use one of: {}".format(
-                cmd, ", ".join(allowed_cmds)
-            ))
 
-        if cmd == "changereviewstate"\
-                and kwargs.get("newstate", None) not in allowed_review_states:
-            raise ValueError(
-                "Invalid review state: '{}'. Use one of: {}".format(
-                    kwargs.get("newstate", None), allowed_review_states
-                )
-            )
+        .. deprecated:: 0.7.8
 
+            * Replaced by :py:meth:`update`
+        """
         kwargs["cmd"] = cmd
         request_id = self._validate_id(request_id)
-        response = self.osc.request(
-            url=urljoin(self.osc.url, self.base_path + request_id),
-            method="POST",
-            params=kwargs
-        )
-
-        if kwargs.get("view", "plain") == "xml":
-            return self.osc.get_objectified_xml(response)
-        return response.text
+        return self.update(request_id=request_id, **kwargs)
 
     def add_comment(self, request_id, comment, parent_id=None):
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/extensions/packages.py 
new/osc-tiny-0.7.9/osctiny/extensions/packages.py
--- old/osc-tiny-0.7.7/osctiny/extensions/packages.py   2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/extensions/packages.py   2022-12-12 
13:21:36.000000000 +0100
@@ -115,7 +115,7 @@
 
     # pylint: disable=too-many-arguments,protected-access
     def set_meta(self, project, package, title=None, description=None,
-                 meta=None):
+                 meta=None, comment=None):
         """
         Set package metadata
 
@@ -130,12 +130,17 @@
 
         .. versionadded:: 0.1.2
 
+        .. versionchanged:: 0.7.8
+
+           Added an optional ``comment`` argument to be used as commit message
+
         :param project: Project name
         :param package: New package name
         :param title: Title for meta
         :param description: Description for meta
         :param meta: New content for meta
         :type meta: str or lxml.objectify.ObjectifiedElement
+        :param comment: Optional comment to use as commit message
         :return:
         """
         if isinstance(meta, (str, bytes)):
@@ -157,6 +162,7 @@
                 "/".join((self.base_path, project, package, "_meta"))
             ),
             data=tounicode(meta_xml),
+            params={"comment": comment},
             method="PUT"
         )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/extensions/projects.py 
new/osc-tiny-0.7.9/osctiny/extensions/projects.py
--- old/osc-tiny-0.7.7/osctiny/extensions/projects.py   2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/extensions/projects.py   2022-12-12 
13:21:36.000000000 +0100
@@ -72,6 +72,7 @@
 
         .. deprecated:: 0.7.2
            Use :meth:`set_meta` instead
+
         :param project: name of project
         :param metafile: Complete metafile
         :type metafile: str or ElementTree
@@ -85,11 +86,11 @@
         warn("Deprecated. Use projects.set_meta instead")
 
         return self.set_meta(project, metafile, title, description, bugowner,
-                      maintainer)
+                             maintainer)
 
     # pylint: disable=too-many-arguments
     def set_meta(self, project, metafile=None, title=None, description=None,
-                 bugowner=None, maintainer=None):
+                 bugowner=None, maintainer=None, comment=None):
         """
         Edit project meta data or create a new project
 
@@ -97,6 +98,10 @@
 
         .. versionadded:: 0.7.2
 
+        .. versionchanged:: 0.7.8
+
+           Added an optional ``comment`` argument to be used as commit message
+
         :param project: name of project
         :param metafile: Complete metafile
         :type metafile: str or ElementTree
@@ -104,6 +109,7 @@
         :param description: Description for meta file
         :param bugowner: Bugowner for meta file
         :param maintainer: Maintainer for meta file
+        :param comment: Optional comment to use as commit message
         :return: ``True``, if successful. Otherwise API response
         :rtype: bool or lxml.objectify.ObjectifiedElement
         """
@@ -143,7 +149,8 @@
             url=urljoin(self.osc.url,
                         "/".join((self.base_path, project, "_meta"))),
             method="PUT",
-            data=tounicode(metafile)
+            data=tounicode(metafile),
+            params={"comment": comment}
         )
 
         parsed = self.osc.get_objectified_xml(response)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/tests/test_packages.py 
new/osc-tiny-0.7.9/osctiny/tests/test_packages.py
--- old/osc-tiny-0.7.7/osctiny/tests/test_packages.py   2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/tests/test_packages.py   2022-12-12 
13:21:36.000000000 +0100
@@ -336,6 +336,23 @@
                 self.assertEqual(bodies[-1], expected)
 
     @responses.activate
+    def test_set_meta_with_comment(self):
+        def callback(headers, params, request):
+            status, body = 200, ""
+
+            return status, headers, body
+
+        self.mock_request(
+            method=responses.PUT,
+            url=re.compile(self.osc.url + '/source/(?P<project>[^/]+)/'
+                                          '(?P<package>[^/]+)/_meta'),
+            callback=CallbackFactory(callback)
+        )
+        self.osc.packages.set_meta("test:project", "test.package", "test 
title", "test description",
+                                   comment="test comment")
+        self.assertEqual(responses.calls[-1].request.params["comment"], "test 
comment")
+
+    @responses.activate
     def test_push_file(self):
         content = """
         ლ(ಠ益ಠ)ლ            ლ(ಠ益ಠ)ლ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/tests/test_projects.py 
new/osc-tiny-0.7.9/osctiny/tests/test_projects.py
--- old/osc-tiny-0.7.7/osctiny/tests/test_projects.py   2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/tests/test_projects.py   2022-12-12 
13:21:36.000000000 +0100
@@ -177,6 +177,14 @@
             self.assertEqual(sent_meta.description.text, "test description")
             self.assertEqual(len(sent_meta.xpath("person")), 2)
 
+        with self.subTest("Valid Metafile with comment"):
+            meta = fromstring(TEMPLATE_META)
+            meta.set("name", "project:foo")
+            meta.title._setText("Hello World")
+            self.assertTrue(self.osc.projects.set_meta(project="project:foo", 
metafile=meta, 
+                                                       comment="Test"))
+            self.assertEqual(responses.calls[-1].request.params["comment"], 
"Test")
+
     @responses.activate
     def test_get_files(self):
         def callback(headers, params, request):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/tests/test_requests.py 
new/osc-tiny-0.7.9/osctiny/tests/test_requests.py
--- old/osc-tiny-0.7.7/osctiny/tests/test_requests.py   2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/tests/test_requests.py   2022-12-12 
13:21:36.000000000 +0100
@@ -372,20 +372,16 @@
             self.assertEqual(len(response.xpath("//request/history")), 5)
 
     @responses.activate
-    def test_cmd(self):
-        with self.subTest("plain diff"):
-            response = self.osc.requests.cmd(30902, "diff")
-            self.assertTrue(isinstance(response, str))
-            self.assertIn("changes files:", response)
-            self.assertIn("+++ perl-XML-DOM-XPath.changes", response)
-        with self.subTest("xml diff"):
-            response = self.osc.requests.cmd(30902, "diff", view="xml")
-            self.assertTrue(isinstance(response, ObjectifiedElement))
-        with self.subTest("changereviewstate"):
-            self.assertRaises(
-                ValueError,
-                self.osc.requests.cmd, 30902, "changereviewstate"
-            )
+    def test_update(self):
+        for method in (self.osc.requests.update, self.osc.requests.cmd):
+            with self.subTest(f"{method}, cmd=diff, plain"):
+                response = method(30902, cmd="diff")
+                self.assertTrue(isinstance(response, str))
+                self.assertIn("changes files:", response)
+                self.assertIn("+++ perl-XML-DOM-XPath.changes", response)
+            with self.subTest(f"{method}, cmd=diff, xml"):
+                response = method(30902, cmd="diff", view="xml")
+                self.assertTrue(isinstance(response, ObjectifiedElement))
 
     @responses.activate
     def test_comment(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/tests/test_utils.py 
new/osc-tiny-0.7.9/osctiny/tests/test_utils.py
--- old/osc-tiny-0.7.7/osctiny/tests/test_utils.py      2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/tests/test_utils.py      2022-12-12 
13:21:36.000000000 +0100
@@ -396,7 +396,8 @@
 
 @mock.patch("osctiny.utils.auth.time", return_value=123456)
 class TestAuth(TestCase):
-    def setUp(self):
+    @mock.patch("osctiny.utils.auth.is_ssh_key_readable", return_value=True)
+    def setUp(self, *_):
         super().setUp()
         mocked_path = mock.MagicMock(spec=Path)
         mocked_path.configure_mock(**{"is_file.return_value": True})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/utils/auth.py 
new/osc-tiny-0.7.9/osctiny/utils/auth.py
--- old/osc-tiny-0.7.7/osctiny/utils/auth.py    2022-11-02 13:06:32.000000000 
+0100
+++ new/osc-tiny-0.7.9/osctiny/utils/auth.py    2022-12-12 13:21:36.000000000 
+0100
@@ -7,9 +7,8 @@
 import typing
 from base64 import b64decode, b64encode
 import logging
-import os
 from pathlib import Path
-from subprocess import Popen, PIPE
+from subprocess import Popen, PIPE, DEVNULL
 import re
 import sys
 from time import time
@@ -55,6 +54,32 @@
     return None
 
 
+def is_ssh_key_readable(ssh_key_file: Path, password: typing.Optional[str]) -> 
bool:
+    """
+    Check whether SSH key can be read/unlocked
+
+    :param ssh_key_file: Path to SSH key
+    :param password: Passphrase
+    :return: ``True``, if SSH key is accessible
+
+    .. versionadded:: 0.6.3
+
+    .. versionchanged:: 0.7.8
+
+        * Moved from ``HttpSignatureAuth.is_ssh_agent_available``
+    """
+    cmd = ['ssh-keygen', '-y', '-f', ssh_key_file.as_posix()]
+    if password:
+        cmd += ['-P', password]
+
+    with Popen(cmd, stdin=DEVNULL, stderr=DEVNULL, stdout=DEVNULL) as proc:
+        proc.communicate()
+        if proc.returncode == 0:
+            return True
+
+    return False
+
+
 class HttpSignatureAuth(HTTPDigestAuth):
     """
     Implementation of the "Signature authentication scheme"
@@ -70,17 +95,24 @@
 
         .. _reference implementation for osc: 
https://github.com/openSUSE/osc/pull/1032
 
+    .. note::
+
+        1. It is recommended to use SSH keys with a passphrase.
+        2. If ``ssh-agent`` is running, the passphrase is not required at 
initialization of this
+           class.
+        3. If you use an SSH key without passphrase, you don't need to specify 
it.
+
     :param username: The username
-    :param password: Passphrase for SSH key. This can be omitted, if 
``ssh-agent`` is also installed
-    :param ssh_key_file: Path of SSK key
+    :param password: Passphrase for SSH key
+    :param ssh_key_file: Path of SSH key
     """
     def __init__(self, username: str, password: typing.Optional[str], 
ssh_key_file: Path):
         super().__init__(username=username, password=password)
         if not ssh_key_file.is_file():
             raise FileNotFoundError(f"SSH key at location does not exist: 
{ssh_key_file}")
-        if not password and not self.is_ssh_agent_available():
-            raise RuntimeError("SSH signing impossible: No password/passphrase 
provided and no SSH "
-                               "agent running! ")
+        if not is_ssh_key_readable(ssh_key_file=ssh_key_file, 
password=password):
+            raise RuntimeError("SSH signing impossible: Unable to decrypt 
key.")
+
         self.ssh_key_file = ssh_key_file
         self.pattern = re.compile(r"(?<=\)) (?=\()")
 
@@ -96,19 +128,6 @@
         parts = self.pattern.split(headers)
         return [part.strip("()") for part in parts]
 
-    @staticmethod
-    def is_ssh_agent_available() -> bool:
-        """
-        Check whether SSH agent is running/available
-
-        :return: ``True``, if agent is running
-
-        .. versionadded:: 0.6.3
-        """
-        relevant_keys = {'SSH_AUTH_SOCK', 'SSH_AGENT_PID'}
-        overlap = os.environ.keys() & relevant_keys
-        return len(overlap) > 0
-
     def ssh_sign(self) -> str:
         """
         Solve the challenge via SSH signing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/osctiny/utils/changelog.py 
new/osc-tiny-0.7.9/osctiny/utils/changelog.py
--- old/osc-tiny-0.7.7/osctiny/utils/changelog.py       2022-11-02 
13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/osctiny/utils/changelog.py       2022-12-12 
13:21:36.000000000 +0100
@@ -118,6 +118,7 @@
         cl.write()
 
     .. py:attribute:: entry_factory
+        :noindex:
 
         A class used to store entry data.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.7/setup.py new/osc-tiny-0.7.9/setup.py
--- old/osc-tiny-0.7.7/setup.py 2022-11-02 13:06:32.000000000 +0100
+++ new/osc-tiny-0.7.9/setup.py 2022-12-12 13:21:36.000000000 +0100
@@ -26,7 +26,7 @@
 
 setup(
     name='osc-tiny',
-    version='0.7.7',
+    version='0.7.9',
     description='Client API for openSUSE BuildService',
     long_description=long_description,
     long_description_content_type="text/markdown",

Reply via email to