#4 Package python-ldap 3.0.0b4
Merged 4 years ago by churchyard. Opened 4 years ago by cheimes.
rpms/ cheimes/python-ldap python-ldap-3.0.0b1  into  master

file modified
+4
@@ -4,3 +4,7 @@ 

  /python-ldap-2.4.16.tar.gz

  /python-ldap-2.4.17.tar.gz

  /python-ldap-2.4.25.tar.gz

+ /python-ldap-3.0.0b1.tar.gz

+ /python-ldap-3.0.0b2.tar.gz

+ /python-ldap-3.0.0b3.tar.gz

+ /python-ldap-3.0.0b4.tar.gz

@@ -0,0 +1,37 @@ 

+ From e587e8a3020a2967e95278e80a98f4a86b2fd861 Mon Sep 17 00:00:00 2001

+ From: Christian Heimes <cheimes@redhat.com>

+ Date: Wed, 10 Jan 2018 14:53:44 +0100

+ Subject: [PATCH] Ignore SASL methods in DSE test

+ 

+ Closes: https://github.com/python-ldap/python-ldap/issues/160

+ Signed-off-by: Christian Heimes <cheimes@redhat.com>

+ ---

+  Tests/t_ldapobject.py | 9 ++++++---

+  1 file changed, 6 insertions(+), 3 deletions(-)

+ 

+ diff --git a/Tests/t_ldapobject.py b/Tests/t_ldapobject.py

+ index 27deadc..2c8ce75 100644

+ --- a/Tests/t_ldapobject.py

+ +++ b/Tests/t_ldapobject.py

+ @@ -520,12 +520,15 @@ class Test00_SimpleLDAPObject(SlapdTestCase):

+          dse = self._ldap_conn.read_rootdse_s()

+          self.assertIsInstance(dse, dict)

+          self.assertEqual(dse[u'supportedLDAPVersion'], [b'3'])

+ +        keys = set(dse)

+ +        # SASL info may be missing in restricted build environments

+ +        keys.discard(u'supportedSASLMechanisms')

+          self.assertEqual(

+ -            sorted(dse),

+ -            [u'configContext', u'entryDN', u'namingContexts', u'objectClass',

+ +            keys,

+ +            {u'configContext', u'entryDN', u'namingContexts', u'objectClass',

+               u'structuralObjectClass', u'subschemaSubentry',

+               u'supportedControl', u'supportedExtension', u'supportedFeatures',

+ -             u'supportedLDAPVersion', u'supportedSASLMechanisms']

+ +             u'supportedLDAPVersion'}

+          )

+          self.assertEqual(

+              self._ldap_conn.get_naming_contexts(),

+ -- 

+ 2.14.3

+ 

@@ -0,0 +1,53 @@ 

+ From b18b8ad1a5d826a54cff8e3656eb4b8bc9678692 Mon Sep 17 00:00:00 2001

+ From: Christian Heimes <cheimes@redhat.com>

+ Date: Wed, 10 Jan 2018 14:35:24 +0100

+ Subject: [PATCH] Use correct types for BER en/decode

+ 

+ ber_scanf() and ber_printf() "i" format uses ber_int_t. lber_types.h

+ defines the type as int but Python code assumes the type to be unsigned

+ long:

+ 

+ typedef LBER_INT_T ber_int_t;

+ 

+ The code was working fine on little endian machines but broke on big

+ endian machines. ber_int_t is now correctly parsed as signed int.

+ 

+ Signed-off-by: Christian Heimes <cheimes@redhat.com>

+ ---

+  Modules/ldapcontrol.c | 6 +++---

+  1 file changed, 3 insertions(+), 3 deletions(-)

+ 

+ diff --git a/Modules/ldapcontrol.c b/Modules/ldapcontrol.c

+ index 9522d57..ec50625 100644

+ --- a/Modules/ldapcontrol.c

+ +++ b/Modules/ldapcontrol.c

+ @@ -242,7 +242,7 @@ encode_rfc2696(PyObject *self, PyObject *args)

+      BerElement *ber = 0;

+      struct berval cookie, *ctrl_val;

+      Py_ssize_t cookie_len;

+ -    unsigned long size;

+ +    int size = 0; /* ber_int_t is int */

+      ber_tag_t tag;

+  

+      if (!PyArg_ParseTuple(args, "is#:encode_page_control", &size,

+ @@ -300,7 +300,7 @@ decode_rfc2696(PyObject *self, PyObject *args)

+      struct berval ldctl_value;

+      ber_tag_t tag;

+      struct berval *cookiep;

+ -    unsigned long count = 0;

+ +    int count = 0;  /* ber_int_t is int */

+      Py_ssize_t ldctl_value_len;

+  

+      if (!PyArg_ParseTuple(args, "s#:decode_page_control",

+ @@ -320,7 +320,7 @@ decode_rfc2696(PyObject *self, PyObject *args)

+          goto endlbl;

+      }

+  

+ -    res = Py_BuildValue("(kO&)", count, LDAPberval_to_object, cookiep);

+ +    res = Py_BuildValue("(iO&)", count, LDAPberval_to_object, cookiep);

+      ber_bvfree(cookiep);

+  

+   endlbl:

+ -- 

+ 2.14.3

+ 

@@ -1,168 +0,0 @@ 

- From a89bd2361a3971d0dc11908707509bbf5e1fd1ac Mon Sep 17 00:00:00 2001

- From: Ilya Etingof <etingof@gmail.com>

- Date: Wed, 11 Oct 2017 20:27:41 +0200

- Subject: [PATCH] accommodate changed pyasn1 behaviour

- 

- pyasn1 versions prior to 0.2.3 indicate absent value by

- returning `None` object, later pyasn1 versions use

- the `noValue` sentinel object which is the basis for

- the `.hasValue()` method call (and .isValue property).

- 

- This fix makes the code compatible with both `None` sentinel

- and the `.hasValue()` test thus making it compatible with all

- reasonable pyasn1 versions in circulation.

- ---

- Index: Lib/ldap/syncrepl.py

- ===================================================================

- RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/syncrepl.py,v

- retrieving revision 1.9

- diff -u -r1.9 syncrepl.py

- --- Lib/ldap/syncrepl.py	9 Oct 2017 15:09:28 -0000	1.9

- +++ Lib/ldap/syncrepl.py	7 Nov 2017 13:40:32 -0000

- @@ -131,11 +131,13 @@

-          d = decoder.decode(encodedControlValue, asn1Spec = syncStateValue())

-          state = d[0].getComponentByName('state')

-          uuid = UUID(bytes=d[0].getComponentByName('entryUUID'))

- -        self.cookie = d[0].getComponentByName('cookie')

- +        cookie = d[0].getComponentByName('cookie')

- +        if cookie is None or not cookie.hasValue():

- +            self.cookie = None

- +        else:

- +            self.cookie = str(cookie)

-          self.state = self.__class__.opnames[int(state)]

-          self.entryUUID = str(uuid)

- -        if self.cookie is not None:

- -            self.cookie = str(self.cookie)

-  

-  KNOWN_RESPONSE_CONTROLS[SyncStateControl.controlType] = SyncStateControl

-  

- @@ -165,10 +167,10 @@

-  

-      def decodeControlValue(self, encodedControlValue):

-          d = decoder.decode(encodedControlValue, asn1Spec = syncDoneValue())

- -        self.cookie = d[0].getComponentByName('cookie')

- +        cookie = d[0].getComponentByName('cookie')

- +        if cookie is not None and cookie.hasValue():

- +            self.cookie = str(cookie)

-          self.refreshDeletes = d[0].getComponentByName('refreshDeletes')

- -        if self.cookie is not None:

- -            self.cookie = str(self.cookie)

-          if self.refreshDeletes is not None:

-              self.refreshDeletes = bool(self.refreshDeletes)

-  

- @@ -263,7 +265,7 @@

-          for attr in [ 'newcookie', 'refreshDelete', 'refreshPresent', 'syncIdSet']:

-              comp = d[0].getComponentByName(attr)

-  

- -            if comp is not None:

- +            if comp is not None and comp.hasValue():

-  

-                  if attr == 'newcookie':

-                      self.newcookie = str(comp)

- @@ -272,7 +274,7 @@

-                  val = dict()

-  

-                  cookie = comp.getComponentByName('cookie')

- -                if cookie is not None:

- +                if cookie is not None and cookie.hasValue():

-                      val['cookie'] = str(cookie)

-  

-                  if attr.startswith('refresh'):

- Index: Lib/ldap/controls/ppolicy.py

- ===================================================================

- RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/controls/ppolicy.py,v

- retrieving revision 1.6

- diff -u -r1.6 ppolicy.py

- --- Lib/ldap/controls/ppolicy.py	9 Oct 2017 15:09:28 -0000	1.6

- +++ Lib/ldap/controls/ppolicy.py	7 Nov 2017 13:40:32 -0000

- @@ -71,7 +71,7 @@

-    def decodeControlValue(self,encodedControlValue):

-      ppolicyValue,_ = decoder.decode(encodedControlValue,asn1Spec=PasswordPolicyResponseValue())

-      warning = ppolicyValue.getComponentByName('warning')

- -    if warning is None:

- +    if warning is None or not warning.hasValue():

-        self.timeBeforeExpiration,self.graceAuthNsRemaining = None,None

-      else:

-        timeBeforeExpiration = warning.getComponentByName('timeBeforeExpiration')

- @@ -85,7 +85,7 @@

-        else:

-          self.graceAuthNsRemaining = None

-      error = ppolicyValue.getComponentByName('error')

- -    if error is None:

- +    if error is None or not error.hasValue():

-        self.error = None

-      else:

-        self.error = int(error)

- Index: Lib/ldap/controls/psearch.py

- ===================================================================

- RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/controls/psearch.py,v

- retrieving revision 1.6

- diff -u -r1.6 psearch.py

- --- Lib/ldap/controls/psearch.py	9 Oct 2017 15:09:28 -0000	1.6

- +++ Lib/ldap/controls/psearch.py	7 Nov 2017 13:40:32 -0000

- @@ -115,18 +115,16 @@

-    def decodeControlValue(self,encodedControlValue):

-      ecncValue,_ = decoder.decode(encodedControlValue,asn1Spec=EntryChangeNotificationValue())

-      self.changeType = int(ecncValue.getComponentByName('changeType'))

- -    if len(ecncValue)==3:

- -      self.previousDN = str(ecncValue.getComponentByName('previousDN'))

- -      self.changeNumber = int(ecncValue.getComponentByName('changeNumber'))

- -    elif len(ecncValue)==2:

- -      if self.changeType==8:

- -        self.previousDN = str(ecncValue.getComponentByName('previousDN'))

- -        self.changeNumber = None

- -      else:

- -        self.previousDN = None

- -        self.changeNumber = int(ecncValue.getComponentByName('changeNumber'))

- +    previousDN = ecncValue.getComponentByName('previousDN')

- +    if previousDN is None or not previousDN.hasValue():

- +      self.previousDN = None

-      else:

- -      self.previousDN,self.changeNumber = None,None

- +      self.previousDN = str(previousDN)

- +    changeNumber = ecncValue.getComponentByName('changeNumber')

- +    if changeNumber is None or not changeNumber.hasValue():

- +      self.changeNumber = None

- +    else:

- +      self.changeNumber = int(changeNumber)

-      return (self.changeType,self.previousDN,self.changeNumber)

-  

-  KNOWN_RESPONSE_CONTROLS[EntryChangeNotificationControl.controlType] = EntryChangeNotificationControl

- Index: Lib/ldap/controls/sss.py

- ===================================================================

- RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/controls/sss.py,v

- retrieving revision 1.5

- diff -u -r1.5 sss.py

- --- Lib/ldap/controls/sss.py	9 Oct 2017 15:09:28 -0000	1.5

- +++ Lib/ldap/controls/sss.py	7 Nov 2017 13:40:32 -0000

- @@ -121,7 +121,9 @@

-          assert not rest, 'all data could not be decoded'

-          self.result = int(p.getComponentByName('sortResult'))

-          self.result_code = p.getComponentByName('sortResult').prettyOut(self.result)

- -        self.attribute_type_error = p.getComponentByName('attributeType')

- +        attribute_type_error = p.getComponentByName('attributeType')

- +        if attribute_type_error is not None and attribute_type_error.hasValue():

- +            self.attribute_type_error = attribute_type_error

-  

-  

-  KNOWN_RESPONSE_CONTROLS[SSSRequestControl.controlType] = SSSRequestControl

- Index: Lib/ldap/controls/vlv.py

- ===================================================================

- RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/controls/vlv.py,v

- retrieving revision 1.5

- diff -u -r1.5 vlv.py

- --- Lib/ldap/controls/vlv.py	9 Oct 2017 15:09:28 -0000	1.5

- +++ Lib/ldap/controls/vlv.py	7 Nov 2017 13:40:32 -0000

- @@ -130,8 +130,9 @@

-          self.result = int(p.getComponentByName('virtualListViewResult'))

-          self.result_code = p.getComponentByName('virtualListViewResult') \

-                  .prettyOut(self.result)

- -        self.context_id = p.getComponentByName('contextID')

- -        if self.context_id:

- -            self.context_id = str(self.context_id)

- +        context_id = p.getComponentByName('contextID')

- +        if context_id is not None and context_id.hasValue():

- +            self.context_id = str(context_id)

- +

-  

-  KNOWN_RESPONSE_CONTROLS[VLVResponseControl.controlType] = VLVResponseControl

@@ -1,16 +0,0 @@ 

- diff --git a/setup.cfg b/setup.cfg

- index aafa110..4dcf73a 100644

- --- a/setup.cfg

- +++ b/setup.cfg

- @@ -1,8 +1,8 @@

-  [_ldap]

- -library_dirs = /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64

- -include_dirs = /usr/include /usr/include/sasl /usr/local/include /usr/local/include/sasl

- +library_dirs = /usr/lib /usr/lib64

- +include_dirs = /usr/include/sasl /usr/include

-  defines = HAVE_SASL HAVE_TLS HAVE_LIBLDAP_R

- -extra_compile_args = 

- +extra_compile_args = -g

-  extra_objects = 

-  libs = ldap_r

-  

file modified
+132 -36
@@ -1,36 +1,47 @@ 

  ### Abstract ###

+ %global prerelease b4

+ 

+ # Fix for https://bugzilla.redhat.com/show_bug.cgi?id=1520990

+ # openldap does not re-register nss shutdown callbacks after nss_Shutdown is

+ # called.

+ %if 0%{?fedora} <= 26

+ %global openldap_version 2.4.45-2

+ %else  # F27+

+ %global openldap_version 2.4.45-4

+ %endif

  

  Name: python-ldap

- Version: 2.4.25

- Release: 9%{?dist}

- Epoch: 0

+ Version: 3.0.0

+ Release: 0.4.%{?prerelease}%{?dist}

  License: Python

  Group: System Environment/Libraries

  Summary: An object-oriented API to access LDAP directory servers

- URL: http://python-ldap.sourceforge.net/

- Source0: http://pypi.python.org/packages/source/p/python-ldap/python-ldap-%{version}.tar.gz

- 

- ### Patches ###

- # Fedora specific patch

- Patch0: python-ldap-2.4.16-dirs.patch

- # Fix for pyasn1 >= 0.3

- # https://github.com/pyldap/pyldap/pull/126

- Patch1: accommodate-changed-pyasn1-behaviour.patch

+ URL: http://python-ldap.org/

+ Source0: https://files.pythonhosted.org/packages/source/p/%{name}/%{name}-%{version}%{?prerelease}.tar.gz

  

- ### Dependencies ###

- # LDAP controls, extop, syncrepl require pyasn1

+ # Workaround for https://github.com/python-ldap/python-ldap/issues/160

+ Patch0: 0001-Ignore-SASL-methods-in-DSE-test.patch

+ # https://github.com/python-ldap/python-ldap/issues/161

+ Patch1: 0001-Use-correct-types-for-BER-en-decode.patch

  

  ### Build Dependencies ###

- BuildRequires: openldap-devel

+ BuildRequires: openldap-devel >= %{openldap_version}

  BuildRequires: openssl-devel

- BuildRequires: python2-devel 

  BuildRequires: cyrus-sasl-devel

- 

- # we don't want to provide private python extension libs

- %{?filter_setup:

- %filter_provides_in %{python_sitearch}/.*\.so$

- %filter_setup

- }

+ BuildRequires: python2-devel

+ BuildRequires: python2-setuptools

+ BuildRequires: python3-devel

+ BuildRequires: python3-setuptools

+ # Test dependencies

+ BuildRequires: /usr/bin/tox

+ BuildRequires: openldap-servers >= %{openldap_version}

+ BuildRequires: openldap-clients >= %{openldap_version}

+ BuildRequires: python2-coverage

+ BuildRequires: python2-pyasn1 >= 0.3.7

+ BuildRequires: python2-pyasn1-modules >= 0.1.5

+ BuildRequires: python3-coverage

+ BuildRequires: python3-pyasn1 >= 0.3.7

+ BuildRequires: python3-pyasn1-modules >= 0.1.5

  

  %global _description\

  python-ldap provides an object-oriented API for working with LDAP within\
@@ -40,44 +51,129 @@ 

  

  %description %_description

  

+ 

  %package -n python2-ldap

  Summary: %summary

- Requires: openldap

- Requires: python-pyasn1, python-pyasn1-modules

+ 

+ Requires: openldap >= %{openldap_version}

+ Requires: python2-pyasn1 >= 0.3.7

+ Requires: python2-pyasn1-modules >= 0.1.5

+ Requires: python2-setuptools

+ 

+ Provides: python2-ldap%{?_isa} = %{version}-%{release}

  %{?python_provide:%python_provide python2-ldap}

  

  %description -n python2-ldap %_description

  

+ 

+ %package -n     python3-ldap

+ Summary:        %{summary}

+ 

+ Requires:  openldap >= %{openldap_version}

+ Requires:  python3-pyasn1 >= 0.3.7

+ Requires:  python3-pyasn1-modules >= 0.1.5

+ Requires:  python3-setuptools

+ %{?python_provide:%python_provide python3-ldap}

+ Obsoletes: python3-pyldap < 3

+ Provides:  python3-pyldap = %{version}-%{release}

+ Provides:  python3-pyldap%{?_isa} = %{version}-%{release}

+ 

+ %description -n python3-ldap %_description

+ 

+ 

  %prep

- %setup -q -n python-ldap-%{version}

- %patch0 -p1 -b .dirs

- %patch1 -p0 -b accommodate-changed-pyasn1-behaviour.patch

+ %setup -qc

+ pushd %{name}-%{version}%{?prerelease}

+ %patch0 -p1

+ %patch1 -p1

+ popd

  

- # clean up cvs hidden files

- rm -rf Demo/Lib/ldap/.cvsignore Demo/.cvsignore Demo/Lib/ldif/.cvsignore Demo/Lib/ldap/async/.cvsignore \

-        Demo/Lib/.cvsignore Demo/Lib/ldapurl/.cvsignore

+ mv %{name}-%{version}%{?prerelease} python3

+ cp -a python{3,2}

  

  # Fix interpreter

- sed -i 's|#! python|#!/usr/bin/python|g' Demo/simplebrowse.py

+ find python2 -name '*.py' | xargs sed -i '1s|^#!/usr/bin/env python|#!%{__python2}|'

+ find python3 -name '*.py' | xargs sed -i '1s|^#!/usr/bin/env python|#!%{__python3}|'

+ 

+ # Disable warnings in test to work around "'U' mode is deprecated"

+ # https://github.com/python-ldap/python-ldap/issues/96

+ sed -i 's,-Werror,-Wignore,g' python3/tox.ini

+ 

  

  %build

- %{__python} setup.py build

+ pushd python2

+ %py2_build

+ popd

+ pushd python3

+ %py3_build

+ popd

+ 

+ 

+ %check

+ # don't download packages

+ export PIP_INDEX_URL=http://host.invalid./

+ export PIP_NO_DEPS=yes

+ 

+ pushd python2

+ LANG=C.UTF-8 TOXENV=py27 LOGLEVEL=10 tox --sitepackages

+ popd

+ 

+ pushd python3

+ LANG=C.UTF-8 TOXENV=py%{python3_version_nodots} LOGLEVEL=10 tox --sitepackages

+ popd

+ 

  

  %install

- %{__python} setup.py install --skip-build --root $RPM_BUILD_ROOT

+ pushd python2

+ %py2_install

+ popd

+ 

+ pushd python3

+ %py3_install

+ popd

  

  

  %files -n python2-ldap

  %defattr(-,root,root,-)

- %doc LICENCE CHANGES README TODO Demo

+ %license python2/LICENCE

+ %doc python2/CHANGES python2/README python2/TODO python2/Demo

  %{python_sitearch}/_ldap.so

- %{python_sitearch}/dsml.py*

  %{python_sitearch}/ldapurl.py*

  %{python_sitearch}/ldif.py*

+ %{python_sitearch}/slapdtest/

  %{python_sitearch}/ldap/

- %{python_sitearch}/python_ldap-%{version}-*.egg-info

+ %{python_sitearch}/python_ldap-%{version}%{?prerelease}-py2.7.egg-info

+ 

+ %files -n python3-ldap

+ %defattr(-,root,root,-)

+ %license python3/LICENCE

+ %doc python3/CHANGES python3/README python3/TODO python3/Demo

+ %{python3_sitearch}/_ldap.cpython-*.so

+ %{python3_sitearch}/ldapurl.py*

+ %{python3_sitearch}/ldif.py*

+ %{python3_sitearch}/__pycache__/*

+ %{python3_sitearch}/slapdtest/

+ %{python3_sitearch}/ldap/

+ %{python3_sitearch}/python_ldap-%{version}%{?prerelease}-py%{python3_version}.egg-info

  

  %changelog

+ * Wed Jan 10 2018 Christian Heimes <cheimes@redhat.com> - 3.0.0-0.4.b4

+ - New upstream release 3.0.0b4 (RHBZ #1496470)

+ 

+ * Wed Dec 20 2017 Christian Heimes <cheimes@redhat.com> - 3.0.0-0.3.b3

+ - New upstream release 3.0.0b3 (RHBZ #1496470)

+ 

+ * Mon Dec 11 2017 Christian Heimes <cheimes@redhat.com> - 3.0.0-0.2.b2

+ - New upstream release 3.0.0b2 (RHBZ #1496470)

+ - Require OpenLDAP with fix for NSS issue (see #1520990)

+ 

+ * Mon Dec 04 2017 Christian Heimes <cheimes@redhat.com> - 0:3.0.0-0.1.b1

+ - New upstream release 3.0.0b1 (RHBZ #1496470)

+ - Resolves RHBZ #1489184

+ - Enable unittests

+ - Remove dsml module

+ - Package python3-ldap, which obsoletes python3-pyldap

+ 

  * Wed Nov 08 2017 Christian Heimes <cheimes@redhat.com> - 0:2.4.25-9

  - Fix issue in pyasn1 patch

  

file modified
+1 -1
@@ -1,1 +1,1 @@ 

- 21523bf21dbe566e0259030f66f7a487  python-ldap-2.4.25.tar.gz

+ SHA512 (python-ldap-3.0.0b4.tar.gz) = 11432638a16b6e7180ed2f8f4d9a5ec65e892e2f0b9fcd0a61ace066372a15ac113c943e3f21f371ea53592f20cec0c91d42370754cba48f16cc5f970e1768f6

  • update to upstream release 3.0.0b4
  • package python3-ldap
  • obsoletes python3-pyldap
  • enable unittest

rebased onto 7f48439

4 years ago

rebased onto ee32bcd

4 years ago

rebased onto 8c3fd25

4 years ago

rebased onto 6838ae0

4 years ago

rebased onto 72fb110

4 years ago

rebased onto 8682fab

4 years ago

rebased onto 92c2998

4 years ago

2 new commits added

  • Package 3.0.0b3
  • Package 3.0.0b2
4 years ago

3 new commits added

  • Package 3.0.0b3
  • Package 3.0.0b2
  • Package 3.0.0b1
4 years ago

1 new commit added

  • Package 3.0.0b4
4 years ago

if you use ?prerelease her, you can keep it once not a prerelease.

You should put < 3 or something like that.

4 new commits added

  • Package 3.0.0b4
  • Package 3.0.0b3
  • Package 3.0.0b2
  • Package 3.0.0b1
4 years ago

4 new commits added

  • Package 3.0.0b4
  • Package 3.0.0b3
  • Package 3.0.0b2
  • Package 3.0.0b1
4 years ago

9 administrators ignored this for a month, I've reviewed it and will merge after a scretchbuild.

Pull-Request has been merged by churchyard

4 years ago