Hello community,

here is the log from the commit of package python-dns-lexicon for 
openSUSE:Factory checked in at 2019-01-03 18:06:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-dns-lexicon (Old)
 and      /work/SRC/openSUSE:Factory/.python-dns-lexicon.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-dns-lexicon"

Thu Jan  3 18:06:42 2019 rev:2 rq:661962 version:3.0.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-dns-lexicon/python-dns-lexicon.changes    
2018-04-24 15:33:43.916914178 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-dns-lexicon.new.28833/python-dns-lexicon.changes
 2019-01-03 18:06:44.760134071 +0100
@@ -1,0 +2,31 @@
+Sat Dec 29 11:51:25 UTC 2018 - Matej Cepl <[email protected]>
+
+- Remove fix_regexps.patch and replace it with
+  multiple-fixes-to-test_hetzner.patch, which fixes the same rpmlint
+  issue and fixes test-hetzner above (gh#AnalogJ/lexicon#333)
+
+-------------------------------------------------------------------
+Mon Dec 24 09:58:32 CET 2018 - [email protected]
+
+- Requires localzone -> python-localzone
+
+-------------------------------------------------------------------
+Wed Dec 19 13:31:07 UTC 2018 - Matej Cepl <[email protected]>
+
+- Update to version 3.0.7
+- Fix tests (the only excluded tests are test_hetzner because of
+  gh#AnalogJ/lexicon#333)
+- Add fix_regexps.patch to fix gh#AnalogJ/lexicon#332
+
+-------------------------------------------------------------------
+Tue Nov 20 12:09:12 UTC 2018 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 3.0.2
+- Update BuildRequries and Requires from setup.py
+  and test-requirements.txt
+- Re-enable tests/providers/test_namecheap.py as the necessary
+  namecheap libraries have been packaged now
+- Disable tests/providers/test_localzone.py as this test
+  requires an internet connection
+
+-------------------------------------------------------------------

Old:
----
  v2.2.1.tar.gz

New:
----
  lexicon-3.0.7.tar.gz
  multiple-fixes-to-test_hetzner.patch

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

Other differences:
------------------
++++++ python-dns-lexicon.spec ++++++
--- /var/tmp/diff_new_pack.fciMNg/_old  2019-01-03 18:06:45.244133641 +0100
+++ /var/tmp/diff_new_pack.fciMNg/_new  2019-01-03 18:06:45.244133641 +0100
@@ -12,39 +12,60 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 # See also http://en.opensuse.org/openSUSE:Specfile_guidelines
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-dns-lexicon
-Version:        2.2.1
+Version:        3.0.7
 Release:        0
 Summary:        DNS record manipulation utility
 License:        MIT
 Group:          Productivity/Networking/DNS/Utilities
 URL:            https://github.com/AnalogJ/lexicon
-Source0:        https://github.com/AnalogJ/lexicon/archive/v%{version}.tar.gz
+Source0:        
https://github.com/AnalogJ/lexicon/archive/v%{version}.tar.gz#/lexicon-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM Collected from upstream to master as of 66daddf
+# Fixes for upstream bugs gh#AnalogJ/lexicon#332 and gh#AnalogJ/lexicon#333
+Patch0:         multiple-fixes-to-test_hetzner.patch
+BuildRequires:  %{python_module PyNamecheap}
+BuildRequires:  %{python_module PyYAML}
+BuildRequires:  %{python_module beautifulsoup4}
 BuildRequires:  %{python_module boto3}
+BuildRequires:  %{python_module cryptography}
 BuildRequires:  %{python_module future}
-BuildRequires:  %{python_module pytest}
+BuildRequires:  %{python_module localzone}
+BuildRequires:  %{python_module mock >= 2.0.0}
+BuildRequires:  %{python_module pytest >= 3.8.0}
+BuildRequires:  %{python_module pytest-cov >= 2.6.0}
+BuildRequires:  %{python_module pytest-xdist >= 1.23.0}
+BuildRequires:  %{python_module python-coveralls >= 2.9.1}
 BuildRequires:  %{python_module requests}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module softlayer}
 BuildRequires:  %{python_module tldextract}
 BuildRequires:  %{python_module transip >= 0.3.0}
-BuildRequires:  %{python_module vcrpy}
+BuildRequires:  %{python_module vcrpy >= 1.13.0}
+BuildRequires:  %{python_module xmltodict}
+BuildRequires:  %{python_module zeep}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
+Requires:       python-PyNamecheap
+Requires:       python-PyYAML
+Requires:       python-beautifulsoup4
 Requires:       python-boto3
+Requires:       python-cryptography
 Requires:       python-future
+Requires:       python-localzone
 Requires:       python-requests
 Requires:       python-setuptools
 Requires:       python-softlayer
 Requires:       python-tldextract
 Requires:       python-transip >= 0.3.0
 Requires:       python-vcrpy
+Requires:       python-xmltodict
+Requires:       python-zeep
 # Completely different pkg but same namespace
 Conflicts:      python-lexicon
 BuildArch:      noarch
@@ -59,8 +80,9 @@
 
 %prep
 %setup -q -n lexicon-%{version}
-# remove namecheap tests/require as we don't have all the support libs
-rm -f tests/providers/test_namecheap.py
+%autopatch -p1
+# remove localzone test as this test requires an internet connection
+rm -f tests/providers/test_localzone.py
 
 # rpmlint
 find . -type f -name ".gitignore" -delete
@@ -77,7 +99,7 @@
 
 %check
 # Python2 incompatible, only py3 syntax in tests
-python3 -m pytest tests
+py.test3 tests
 
 %files %{python_files}
 %{python_sitelib}/lexicon

++++++ multiple-fixes-to-test_hetzner.patch ++++++
>From d6e3c1f4901baaca3b31489298b5bc598dc42bac Mon Sep 17 00:00:00 2001
From: Adrien Ferrand <[email protected]>
Date: Thu, 27 Dec 2018 21:46:00 +0100
Subject: [PATCH] Multiple fixes to test_hetzner

 * Fixes #332 with raw string regex
 * Added fallback handling for resolving DNS when no domain found via
   local nameservers. Solves issue #333
 * Added mock for _get_dns_cname method
 * Removed tldextract package
 * Specified test domains for DNS resolution test
 * In favor for adferrand ;)
---
 lexicon/providers/gehirn.py     | 14 +++----
 lexicon/providers/hetzner.py    | 15 ++++---
 tests/providers/test_hetzner.py | 74 +++++++++++++++++++++++++--------
 tests/pylint_quality_gate.py    | 73 +++++---------------------------
 tox.ini                         |  1 +
 5 files changed, 84 insertions(+), 93 deletions(-)

diff --git a/lexicon/providers/gehirn.py b/lexicon/providers/gehirn.py
index a8e42e9..46b99a0 100644
--- a/lexicon/providers/gehirn.py
+++ b/lexicon/providers/gehirn.py
@@ -33,13 +33,13 @@ BUILD_FORMATS = {
 }
 
 FORMAT_RE = {
-    "A": re.compile("(?P<address>.+)"),
-    "AAAA": re.compile("(?P<address>.+)"),
-    "CNAME": re.compile("(?P<cname>.+)"),
-    "TXT": re.compile("(?P<data>.+)"),
-    "NS": re.compile("(?P<nsdname>.+)"),
-    "MX": re.compile("(?P<prio>\d+)\s+(?P<exchange>.+)"),
-    "SRV": 
re.compile("(?P<prio>\d+)\s+(?P<weight>\d+)\s+(?P<port>\d+)\s+(?P<target>.+)"),
+    "A": re.compile(r"(?P<address>.+)"),
+    "AAAA": re.compile(r"(?P<address>.+)"),
+    "CNAME": re.compile(r"(?P<cname>.+)"),
+    "TXT": re.compile(r"(?P<data>.+)"),
+    "NS": re.compile(r"(?P<nsdname>.+)"),
+    "MX": re.compile(r"(?P<prio>\d+)\s+(?P<exchange>.+)"),
+    "SRV": 
re.compile(r"(?P<prio>\d+)\s+(?P<weight>\d+)\s+(?P<port>\d+)\s+(?P<target>.+)"),
 }
 
 
diff --git a/lexicon/providers/hetzner.py b/lexicon/providers/hetzner.py
index 6d3ea58..d92b990 100644
--- a/lexicon/providers/hetzner.py
+++ b/lexicon/providers/hetzner.py
@@ -421,6 +421,7 @@ class Provider(BaseProvider):
         rrset = dns.rrset.from_text(name, 0, 1, rdtype)
         try:
             resolver = dns.resolver.Resolver()
+            resolver.lifetime = 1
             if nameservers:
                 resolver.nameservers = nameservers
             rrset = resolver.query(name, rdtype)
@@ -459,7 +460,9 @@ class Provider(BaseProvider):
         more linked record name was found for the given fully qualified record 
name or
         the CNAME lookup was disabled, and then returns the parameters as a 
tuple.
         """
-        domain = dns.resolver.zone_for_name(name).to_text(True)
+        resolver = dns.resolver.Resolver()
+        resolver.lifetime = 1
+        domain = dns.resolver.zone_for_name(name, 
resolver=resolver).to_text(True)
         nameservers = Provider._get_nameservers(domain)
         cname = None
         links, max_links = 0, 5
@@ -474,9 +477,9 @@ class Provider(BaseProvider):
             if rrset:
                 links += 1
                 cname = rrset[0].to_text()
-                qdomain = dns.resolver.zone_for_name(cname)
-                if domain != qdomain.to_text(True):
-                    domain = qdomain.to_text(True)
+                qdomain = dns.resolver.zone_for_name(cname, 
resolver=resolver).to_text(True)
+                if domain != qdomain:
+                    domain = qdomain
                     nameservers = Provider._get_nameservers(qdomain)
             else:
                 link = False
@@ -504,10 +507,10 @@ class Provider(BaseProvider):
             if action != 'update' or name == qname or not qname:
                 LOGGER.info('Hetzner => Enable CNAME lookup '
                             '(see --linked parameter)')
-                return qname, True
+                return name, True
         LOGGER.info('Hetzner => Disable CNAME lookup '
                     '(see --linked parameter)')
-        return qname, False
+        return name, False
 
     def _propagated_record(self, rdtype, name, content, nameservers=None):
         """
diff --git a/tests/providers/test_hetzner.py b/tests/providers/test_hetzner.py
index a7fdd6c..d0a7baa 100644
--- a/tests/providers/test_hetzner.py
+++ b/tests/providers/test_hetzner.py
@@ -1,16 +1,50 @@
-# Test for one implementation of the interface
+from unittest import TestCase
+import os
+import mock
+import pytest
+from bs4 import BeautifulSoup
+import dns.resolver
 from lexicon.providers.hetzner import Provider
 from integration_tests import IntegrationTests
-from unittest import TestCase
-import pytest
 
-import os
-from bs4 import BeautifulSoup
+def _no_dns_lookup():
+    _domains = ['rimek.info', 'bettilaila.com']
+    _resolver = dns.resolver.Resolver()
+    _resolver.lifetime = 1
+    try:
+        for _domain in _domains:
+            _ = dns.resolver.zone_for_name(_domain, resolver=_resolver)
+        return False
+    except dns.exception.DNSException:
+        pass
+    return True
 
-# Hook into testing framework by inheriting unittest.TestCase and reuse
-# the tests which *each and every* implementation of the interface must
-# pass, by inheritance from integration_tests.IntegrationTests
-class HetznerRobotProviderTests(TestCase, IntegrationTests):
+class HetznerIntegrationTests(IntegrationTests):
+
+    @pytest.fixture(autouse=True)
+    def dns_cname_mock(self, request):
+        _ignore_mock = request.node.get_marker('ignore_dns_cname_mock')
+        _domain_mock = self.domain
+        if request.node.name == 
'test_Provider_authenticate_with_unmanaged_domain_should_fail':
+            _domain_mock = 'thisisadomainidonotown.com'
+        if _ignore_mock:
+            yield
+        else:
+            with 
mock.patch('lexicon.providers.hetzner.Provider._get_dns_cname',
+                            return_value=(_domain_mock, [], None)) as fixture:
+                yield fixture
+
+    @pytest.mark.skipif(_no_dns_lookup(), reason='No DNS resolution possible.')
+    @pytest.mark.ignore_dns_cname_mock
+    def test_get_dns_cname(self):
+        """Ensure that zone for name can be resolved through dns.resolver 
call."""
+        _domain, _nameservers, _cname = 
Provider._get_dns_cname(('_acme-challenge.fqdn.{}.'
+                                                                 
.format(self.domain)), False)
+        assert _domain == self.domain
+        assert _nameservers
+        assert not _cname
+
+class HetznerRobotProviderTests(TestCase, HetznerIntegrationTests):
 
     Provider = Provider
     provider_name = 'hetzner'
@@ -18,7 +52,7 @@ class HetznerRobotProviderTests(TestCase, IntegrationTests):
     domain = 'rimek.info'
 
     def _filter_post_data_parameters(self):
-        return ['_username','_password', '_csrf_token']
+        return ['_username', '_password', '_csrf_token']
 
     def _filter_headers(self):
         return ['Cookie']
@@ -28,9 +62,11 @@ class HetznerRobotProviderTests(TestCase, IntegrationTests):
             if cookie in response['headers']:
                 del response['headers'][cookie]
         if os.environ.get('LEXICON_LIVE_TESTS', 'false') == 'true':
-            filter_body = BeautifulSoup(response['body']['string'], 
'html.parser').find(id='center_col')
+            filter_body = (BeautifulSoup(response['body']['string'], 
'html.parser')
+                           .find(id='center_col'))
             if not filter_body:
-                filter_body = BeautifulSoup(response['body']['string'], 
'html.parser').find(id='login-form')
+                filter_body = (BeautifulSoup(response['body']['string'], 
'html.parser')
+                               .find(id='login-form'))
             response['body']['string'] = str(filter_body).encode('UTF-8')
         return response
 
@@ -41,7 +77,7 @@ class HetznerRobotProviderTests(TestCase, IntegrationTests):
                    'latency': 1}
         return options
 
-class HetznerKonsoleHProviderTests(TestCase, IntegrationTests):
+class HetznerKonsoleHProviderTests(TestCase, HetznerIntegrationTests):
 
     Provider = Provider
     provider_name = 'hetzner'
@@ -49,7 +85,7 @@ class HetznerKonsoleHProviderTests(TestCase, 
IntegrationTests):
     domain = 'bettilaila.com'
 
     def _filter_post_data_parameters(self):
-        return ['login_user_inputbox','login_pass_inputbox', '_csrf_name', 
'_csrf_token']
+        return ['login_user_inputbox', 'login_pass_inputbox', '_csrf_name', 
'_csrf_token']
 
     def _filter_headers(self):
         return ['Cookie']
@@ -59,15 +95,17 @@ class HetznerKonsoleHProviderTests(TestCase, 
IntegrationTests):
             if cookie in response['headers']:
                 del response['headers'][cookie]
         if os.environ.get('LEXICON_LIVE_TESTS', 'false') == 'true':
-            filter_body = BeautifulSoup(response['body']['string'], 
'html.parser').find(id='content')
+            filter_body = (BeautifulSoup(response['body']['string'], 
'html.parser')
+                           .find(id='content'))
             if not filter_body:
-                filter_body = BeautifulSoup(response['body']['string'], 
'html.parser').find(id='loginform')
+                filter_body = (BeautifulSoup(response['body']['string'], 
'html.parser')
+                               .find(id='loginform'))
             response['body']['string'] = str(filter_body).encode('UTF-8')
         return response
 
     def _test_parameters_overrides(self):
-        env_username = os.environ.get('LEXICON_HETZNER_KONSOLEH_USERNAME')
-        env_password = os.environ.get('LEXICON_HETZNER_KONSOLEH_PASSWORD')
+        env_username = os.environ.get('LEXICON_HETZNER_KONSOLEH_USERNAME', 
'placeholder_username')
+        env_password = os.environ.get('LEXICON_HETZNER_KONSOLEH_PASSWORD', 
'placeholder_password')
         options = {'auth_account': 'konsoleh',
                    'auth_username': env_username,
                    'auth_password': env_password,
diff --git a/tests/pylint_quality_gate.py b/tests/pylint_quality_gate.py
index ddc5bef..085263b 100644
--- a/tests/pylint_quality_gate.py
+++ b/tests/pylint_quality_gate.py
@@ -1,64 +1,16 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 import os
-import shutil
-import tempfile
-import contextlib
-import stat
 import sys
-import subprocess
-from io import StringIO
 
 from pylint import lint
 
 
 REPO_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+GLOBAL_NOTE_THRESHOLD = 8.12
 
 
[email protected]
-def capture():
-    oldout, olderr = sys.stdout, sys.stderr
-    try:
-        out = [StringIO(), StringIO()]
-        sys.stdout, sys.stderr = out
-        yield out
-    finally:
-        sys.stdout, sys.stderr = oldout, olderr
-        out[0] = out[0].getvalue()
-        out[1] = out[1].getvalue()
-
-
-def get_pylint_upstream_master_note():
-    """
-    Get the pylint global note of lexicon on upstream master branch
-    """
-    sys.stdout.write(
-        '===> Preparing a temporary local repository for upstream ... <===\n')
-    worktree_dir = tempfile.mkdtemp()
-
-    try:
-        sys.stdout.write('===> Executing pylint on upstream master '
-                         'to calculate pylint global note diff ... <===\n')
-
-        subprocess.check_output([
-            'git', 'clone', '--depth=1', 
'https://github.com/AnalogJ/lexicon.git',
-            worktree_dir], stderr=subprocess.STDOUT)
-        subprocess.check_output(['pip', 'install', '-e', worktree_dir], 
stderr=subprocess.STDOUT)
-        with capture():
-            results = lint.Run([
-                os.path.join(worktree_dir, 'lexicon'), 
os.path.join(worktree_dir, 'tests'),
-                os.path.join(worktree_dir, 'tests', 'providers'), 
'--persistent=n'],
-                do_exit=False)
-
-        return results.linter.stats['global_note']
-    finally:
-        def del_rw(_, name, __):
-            os.chmod(name, stat.S_IWRITE)
-            os.remove(name)
-        shutil.rmtree(worktree_dir, onerror=del_rw)
-
-
-def quality_gate(stats, upstream_master_note):
+def quality_gate(stats):
     """
     Trigger various performance metrics on code quality.
     Raise if these metrics do not match expectations.
@@ -83,34 +35,31 @@ def quality_gate(stats, upstream_master_note):
     else:
         sys.stdout.write('2) OK. No "error" issues have been found.\n')
 
-    if stats['global_note'] < upstream_master_note:
-        sys.stderr.write('3) Failure: pylint global note is '
-                         'decreasing compared to master: {0} => {1}\n'
-                         .format(upstream_master_note, stats['global_note']))
+    if stats['global_note'] < GLOBAL_NOTE_THRESHOLD:
+        sys.stderr.write('3) Failure: pylint global note is below threshold: 
{0} < {1}\n'
+                         .format(stats['global_note'], GLOBAL_NOTE_THRESHOLD))
         quality_errors = True
     else:
-        sys.stdout.write('3) OK: pylint global is increasing or stable 
compared to master: '
-                         '{0} => {1}\n'.format(upstream_master_note, 
stats['global_note']))
+        sys.stdout.write('3) OK: pylint global note is beyond threshold: {0} 
>= {1}\n'
+                         .format(stats['global_note'], GLOBAL_NOTE_THRESHOLD))
 
     return 0 if not quality_errors else 1
 
 
 def main():
     """Main process"""
-    upstream_master_note = get_pylint_upstream_master_note()
-
     # Script is located two levels deep in the repository root 
(./tests/pylint_quality_gate.py)
     repo_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
-    sys.stdout.write('===> Executing pylint on current branch ... <===\n')
-    subprocess.check_output(['pip', 'install', '-e', repo_dir], 
stderr=subprocess.STDOUT)
+    sys.stdout.write('===> Executing pylint ... <===\n')
     results = lint.Run([
-        os.path.join(repo_dir, 'lexicon'), os.path.join(repo_dir, 'tests'),
+        os.path.join(repo_dir, 'lexicon'),
+        os.path.join(repo_dir, 'tests'),
         os.path.join(repo_dir, 'tests', 'providers'), '--persistent=n'],
         do_exit=False)
 
     stats = results.linter.stats
-    sys.exit(quality_gate(stats, upstream_master_note))
+    sys.exit(quality_gate(stats))
 
 
 if __name__ == '__main__':
diff --git a/tox.ini b/tox.ini
index 44a4b1d..191717d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -33,6 +33,7 @@ deps =
 commands =
     python tests/pylint_quality_gate.py
 deps =
+    -r requirements.txt
     -r test-requirements.txt
     -r optional-requirements.txt
     pylint==2.1.1
-- 
2.20.1


Reply via email to