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 2024-06-28 15:47:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
and /work/SRC/openSUSE:Factory/.python-osc-tiny.new.18349 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-osc-tiny"
Fri Jun 28 15:47:44 2024 rev:34 rq:1183801 version:0.10.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes 2024-05-22 21:32:44.714567797 +0200
+++ /work/SRC/openSUSE:Factory/.python-osc-tiny.new.18349/python-osc-tiny.changes 2024-06-28 15:51:23.487491514 +0200
@@ -1,0 +2,7 @@
+Thu Jun 27 15:45:09 UTC 2024 - Chen Huang
+
+- Release 0.10.0
+ * Added capability to create requests (#165)
+ * Install the theme for the docs (#163)
+
+-------------------------------------------------------------------
Old:
----
osc-tiny-0.9.1.tar.gz
New:
----
osc-tiny-0.10.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.Iu2a4S/_old 2024-06-28 15:51:28.563677205 +0200
+++ /var/tmp/diff_new_pack.Iu2a4S/_new 2024-06-28 15:51:28.567677352 +0200
@@ -19,7 +19,7 @@
%define skip_python2 1
%{?sle15allpythons}
Name: python-osc-tiny
-Version: 0.9.1
+Version: 0.10.0
Release: 0
Summary: Client API for openSUSE BuildService
License: MIT
++++++ osc-tiny-0.9.1.tar.gz -> osc-tiny-0.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/PKG-INFO new/osc-tiny-0.10.0/PKG-INFO
--- old/osc-tiny-0.9.1/PKG-INFO 2024-05-22 10:58:11.398337600 +0200
+++ new/osc-tiny-0.10.0/PKG-INFO 2024-06-27 13:00:45.511684400 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.9.1
+Version: 0.10.0
Summary: Client API for openSUSE BuildService
Home-page: https://github.com/SUSE/osc-tiny
Author: Andreas Hasenkopf
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osc_tiny.egg-info/PKG-INFO new/osc-tiny-0.10.0/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.9.1/osc_tiny.egg-info/PKG-INFO 2024-05-22 10:58:11.000000000 +0200
+++ new/osc-tiny-0.10.0/osc_tiny.egg-info/PKG-INFO 2024-06-27 13:00:45.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.9.1
+Version: 0.10.0
Summary: Client API for openSUSE BuildService
Home-page: https://github.com/SUSE/osc-tiny
Author: Andreas Hasenkopf
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osc_tiny.egg-info/SOURCES.txt new/osc-tiny-0.10.0/osc_tiny.egg-info/SOURCES.txt
--- old/osc-tiny-0.9.1/osc_tiny.egg-info/SOURCES.txt 2024-05-22 10:58:11.000000000 +0200
+++ new/osc-tiny-0.10.0/osc_tiny.egg-info/SOURCES.txt 2024-06-27 13:00:45.000000000 +0200
@@ -26,6 +26,7 @@
osctiny/extensions/staging.py
osctiny/extensions/users.py
osctiny/models/__init__.py
+osctiny/models/request.py
osctiny/models/staging.py
osctiny/tests/__init__.py
osctiny/tests/base.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/__init__.py new/osc-tiny-0.10.0/osctiny/__init__.py
--- old/osc-tiny-0.9.1/osctiny/__init__.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/osctiny/__init__.py 2024-06-27 13:00:41.000000000 +0200
@@ -6,4 +6,4 @@
__all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
'projects', 'search', 'users']
-__version__ = "0.9.1"
+__version__ = "0.10.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/extensions/bs_requests.py new/osc-tiny-0.10.0/osctiny/extensions/bs_requests.py
--- old/osc-tiny-0.9.1/osctiny/extensions/bs_requests.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/osctiny/extensions/bs_requests.py 2024-06-27 13:00:41.000000000 +0200
@@ -8,7 +8,8 @@
from lxml.etree import XMLSyntaxError
from lxml.objectify import ObjectifiedElement
-from ..models import IntOrString, ParamsType
+from ..models import E, IntOrString, ParamsType
+from ..models.request import Action, Review
from ..utils.base import ExtensionBase
@@ -27,6 +28,41 @@
)
return request_id
+ # pylint: disable=too-many-arguments
+ def create(self, actions: typing.Iterable[Action],
+ reviewers: typing.Optional[typing.Iterable[Review]] = None,
+ addrevision: bool = False, ignore_delegate: bool = False,
+ ignore_build_state: bool = False) -> int:
+ """
+ Create a request
+
+ :param actions: Actions to be included in request
+ :param reviewers: Reviewers to be assigned
+ :param addrevision: Ask the server to add revisions of the current sources to the request.
+ :param ignore_delegate: Enforce a new package instance in a project which has
+ ``OBS:DelegateRequestTarget`` set
+ :param ignore_build_state: Skip the build state check
+ :return: Request ID
+
+ .. versionadded:: 0.10.0
+ """
+ request = E.request(*(action.asxml() for action in actions),
+ *(review.asxml() for review in reviewers or []))
+
+ response = self.osc.request(
+ url=urljoin(self.osc.url, self.base_path),
+ method="POST",
+ data=request,
+ params={
+ "cmd": "create",
+ "addrevision": addrevision,
+ "ignore_delegate": ignore_delegate,
+ "ignore_build_state": ignore_build_state
+ },
+ )
+ data = self.osc.get_objectified_xml(response)
+ return int(data.get("id"))
+
def get_list(self, **params: ParamsType) -> ObjectifiedElement:
"""
Get a list or request objects
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/models/__init__.py new/osc-tiny-0.10.0/osctiny/models/__init__.py
--- old/osc-tiny-0.9.1/osctiny/models/__init__.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/osctiny/models/__init__.py 2024-06-27 13:00:41.000000000 +0200
@@ -5,8 +5,13 @@
from io import BufferedReader, BytesIO, StringIO
import typing
-from lxml.objectify import ObjectifiedElement
+from lxml.objectify import ElementMaker, ObjectifiedElement
+#: XML maker without python type annotations
+E = ElementMaker(annotate=False)
+#: Acceptable types for HTTP parameters
ParamsType = typing.Union[bytes, str, StringIO, BytesIO, BufferedReader, dict, ObjectifiedElement]
+
+#: Int or string with only numbers
IntOrString = typing.Union[int, str]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/models/request.py new/osc-tiny-0.10.0/osctiny/models/request.py
--- old/osc-tiny-0.9.1/osctiny/models/request.py 1970-01-01 01:00:00.000000000 +0100
+++ new/osc-tiny-0.10.0/osctiny/models/request.py 2024-06-27 13:00:41.000000000 +0200
@@ -0,0 +1,105 @@
+"""
+Models for requests
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 0.10.0
+"""
+# pylint: disable=missing-function-docstring,no-member
+# Note: The `no-member` rule needs to be disabled due to this bug:
+# https://github.com/pylint-dev/pylint/issues/7891
+import enum
+import typing
+
+from lxml.objectify import ObjectifiedElement
+
+from . import E
+
+
+class ActionType(enum.Enum):
+ """
+ Request action types as defined in OpenBuildService
+ """
+ ADD_ROLE = "add_role"
+ CHANGE_DEVEL = "change_devel"
+ DELETE = "delete"
+ MAINTENANCE_INCIDENT = "maintenance_incident"
+ MAINTENANCE_RELEASE = "maintenance_release"
+ RELEASE = "release"
+ SET_BUGOWNER = "set_bugowner"
+ SUBMIT = "submit"
+
+
+class Person(typing.NamedTuple):
+ """
+ Person model for use in actions
+ """
+ name: str
+
+ def asxml(self) -> ObjectifiedElement:
+ return E.person(name=self.name)
+
+
+class Source(typing.NamedTuple):
+ """
+ Source for an action
+ """
+ project: str
+ package: str
+ rev: typing.Optional[str] = None
+
+ def asxml(self) -> ObjectifiedElement:
+ return E.source(**{field: getattr(self, field)
+ for field in self._fields
+ if getattr(self, field, None) is not None})
+
+
+class Target(typing.NamedTuple):
+ """
+ Target for an action
+ """
+ project: str
+ package: str
+ releaseproject: typing.Optional[str] = None
+
+ def asxml(self) -> ObjectifiedElement:
+ return E.target(**{field: getattr(self, field)
+ for field in self._fields
+ if getattr(self, field, None) is not None})
+
+
+class Action(typing.NamedTuple):
+ """
+ Request action
+ """
+ type: ActionType
+ target: Target
+ person: typing.Optional[Person] = None
+ source: typing.Optional[Source] = None
+
+ def asxml(self) -> ObjectifiedElement:
+ sub_elems = [self.target.asxml()]
+ for field in (self.person, self.source):
+ if field is not None:
+ sub_elems.append(field.asxml())
+ return E.action(*sub_elems, type=self.type.value)
+
+
+class By(enum.Enum):
+ """
+ Types by which reviews can be assigned
+ """
+ USER = "by_user"
+ GROUP = "by_group"
+ PROJECT = "by_project"
+ PACKAGE = "by_package"
+
+
+class Review(typing.NamedTuple):
+ """
+ Assign a review
+ """
+ by: By
+ name: str
+
+ def asxml(self) -> ObjectifiedElement:
+ return E.review(**{self.by.value: self.name})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/models/staging.py new/osc-tiny-0.10.0/osctiny/models/staging.py
--- old/osc-tiny-0.9.1/osctiny/models/staging.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/osctiny/models/staging.py 2024-06-27 13:00:41.000000000 +0200
@@ -1,15 +1,16 @@
"""
Models for Staging
^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 0.9.0
"""
# pylint: disable=missing-class-docstring,missing-function-docstring
import enum
import typing
-from lxml.objectify import ObjectifiedElement, ElementMaker
-
+from lxml.objectify import ObjectifiedElement
-E = ElementMaker(annotate=False)
+from ..models import E
class ExcludedRequest(typing.NamedTuple):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/osctiny/tests/test_requests.py new/osc-tiny-0.10.0/osctiny/tests/test_requests.py
--- old/osc-tiny-0.9.1/osctiny/tests/test_requests.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/osctiny/tests/test_requests.py 2024-06-27 13:00:41.000000000 +0200
@@ -1,10 +1,13 @@
# -*- coding: utf-8 -*-
import re
+from unittest import mock
from urllib.parse import urlparse, parse_qs
from lxml.objectify import ObjectifiedElement
+from requests.models import Response
import responses
+from ..models.request import Action, ActionType, Person, Review, Source, Target, By
from .base import OscTest, CallbackFactory
@@ -304,6 +307,9 @@
and "changereviewstate" in params.get("cmd", [])):
status = 403
body = "Forbidden for url: http://api.example.com/request/30902"
+ elif request.method == "POST" and re.search("/request/?\?", request.url):
+ status = 200
+ body = """<request id="42"/>"""
else:
status = 404
body = """
@@ -343,6 +349,91 @@
)
@responses.activate
+ def test_create(self):
+ target = Target(project="Foo:Bar:Factory", package="hello-world")
+ actions = [
+ Action(
+ type=ActionType.SUBMIT,
+ source=Source(project="Foo:Bar", package="hello-world"),
+ target=target
+ ),
+ Action(
+ type=ActionType.DELETE,
+ target=target
+ )
+ ]
+ reviewers = [
+ Review(by=By.USER, name="nemo"),
+ Review(by=By.GROUP, name="superusers")
+ ]
+
+ with self.subTest("HTTP Request, only Actions"):
+ self.assertEqual(42, self.osc.requests.create(actions=actions))
+
+ with self.subTest("HTTP Request, with Reviewers"):
+ self.assertEqual(42, self.osc.requests.create(actions=actions,
+ reviewers=reviewers))
+
+ mock_response = Response()
+ mock_response.status_code = 200
+ mock_response._content = b"""<request id="42"/>"""
+
+ with self.subTest("XML content, only Actions"), \
+ mock.patch.object(self.osc.session, "send",
+ return_value=mock_response) as mock_session:
+ self.osc.requests.create(actions=actions)
+ self.assertEqual(
+ mock_session.call_args[0][0].body,
+ b"<?xml version='1.0' encoding='utf-8'?>\n"
+ b'<request>'
+ b'<action type="submit">'
+ b'<target project="Foo:Bar:Factory" package="hello-world"/>'
+ b'<source project="Foo:Bar" package="hello-world"/>'
+ b'</action>'
+ b'<action type="delete">'
+ b'<target project="Foo:Bar:Factory" package="hello-world"/>'
+ b'</action>'
+ b'</request>'
+ )
+
+ with self.subTest("XML content, with Reviewers"), \
+ mock.patch.object(self.osc.session, "send",
+ return_value=mock_response) as mock_session:
+ self.osc.requests.create(actions=actions, reviewers=reviewers)
+ self.assertEqual(
+ mock_session.call_args[0][0].body,
+ b"<?xml version='1.0' encoding='utf-8'?>\n"
+ b'<request>'
+ b'<action type="submit">'
+ b'<target project="Foo:Bar:Factory" package="hello-world"/>'
+ b'<source project="Foo:Bar" package="hello-world"/>'
+ b'</action>'
+ b'<action type="delete">'
+ b'<target project="Foo:Bar:Factory" package="hello-world"/>'
+ b'</action>'
+ b'<review by_user="nemo"/>'
+ b'<review by_group="superusers"/>'
+ b'</request>'
+ )
+
+ with self.subTest("XML content, set bugowner"), \
+ mock.patch.object(self.osc.session, "send",
+ return_value=mock_response) as mock_session:
+ self.osc.requests.create(actions=[Action(type=ActionType.SET_BUGOWNER,
+ target=Target(project="Foo:Bar", package="p"),
+ person=Person(name="nemo"))])
+ self.assertEqual(
+ mock_session.call_args[0][0].body,
+ b"<?xml version='1.0' encoding='utf-8'?>\n"
+ b'<request>'
+ b'<action type="set_bugowner">'
+ b'<target project="Foo:Bar" package="p"/>'
+ b'<person name="nemo"/>'
+ b'</action>'
+ b'</request>'
+ )
+
+ @responses.activate
def test_get_list(self):
response = self.osc.requests.get_list()
self.assertEqual(response.tag, "directory")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-tiny-0.9.1/setup.py new/osc-tiny-0.10.0/setup.py
--- old/osc-tiny-0.9.1/setup.py 2024-05-22 10:58:07.000000000 +0200
+++ new/osc-tiny-0.10.0/setup.py 2024-06-27 13:00:41.000000000 +0200
@@ -26,7 +26,7 @@
setup(
name='osc-tiny',
- version='0.9.1',
+ version='0.10.0',
description='Client API for openSUSE BuildService',
long_description=long_description,
long_description_content_type="text/markdown",