Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-python-jenkins for 
openSUSE:Factory checked in at 2023-04-17 17:41:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-jenkins (Old)
 and      /work/SRC/openSUSE:Factory/.python-python-jenkins.new.2023 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-python-jenkins"

Mon Apr 17 17:41:20 2023 rev:13 rq:1079857 version:1.8.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-python-jenkins/python-python-jenkins.changes  
    2022-05-04 15:11:26.472193464 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-python-jenkins.new.2023/python-python-jenkins.changes
    2023-04-17 17:41:26.986274308 +0200
@@ -1,0 +2,11 @@
+Mon Apr 17 08:05:56 UTC 2023 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Update to 1.8.0:
+  * Add retrieval of stages of artifacts
+  * Switch links to opendev.org
+  * Allow build number to be a string
+  * Use fullname in get_job_info_regex
+- Add patch use-parts-of-legacy-version.patch:
+  * Use underpining parts of LegacyVersion pre-removal.
+
+-------------------------------------------------------------------

Old:
----
  python-jenkins-1.7.0.tar.gz

New:
----
  python-jenkins-1.8.0.tar.gz
  use-parts-of-legacy-version.patch

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

Other differences:
------------------
++++++ python-python-jenkins.spec ++++++
--- /var/tmp/diff_new_pack.FuQzQJ/_old  2023-04-17 17:41:27.522277440 +0200
+++ /var/tmp/diff_new_pack.FuQzQJ/_new  2023-04-17 17:41:27.530277487 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-python-jenkins
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 # Copyright (c) 2014 Thomas Bechtold <thomasbecht...@jpberlin.de>
 #
 # All modifications and additions to the file contributed by third parties
@@ -17,30 +17,34 @@
 #
 
 
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-python-jenkins
-Version:        1.7.0
+Version:        1.8.0
 Release:        0
 Summary:        Python bindings for the remote Jenkins API
 License:        BSD-3-Clause
-Group:          Development/Languages/Python
 URL:            https://opendev.org/jjb/python-jenkins
 Source:         
https://files.pythonhosted.org/packages/source/p/python-jenkins/python-jenkins-%{version}.tar.gz
 # https://bugs.launchpad.net/python-jenkins/+bug/1971524
 Patch0:         python-python-jenkins-no-mock.patch
+# PATCH-FIX-OPENSUSE Upstream are arguing about version parsing, use the
+# underlying parts of LegacyVersion from packaging pre-removal
+Patch1:         use-parts-of-legacy-version.patch
 BuildRequires:  %{python_module cmd2}
 BuildRequires:  %{python_module multi_key_dict}
 BuildRequires:  %{python_module pbr >= 0.8.2}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module requests-mock >= 1.4}
 BuildRequires:  %{python_module requests}
 BuildRequires:  %{python_module testscenarios}
+BuildRequires:  %{python_module wheel}
+BuildRequires:  fdupes
 BuildRequires:  openssl-devel
 BuildRequires:  pkgconfig
 BuildRequires:  python-rpm-macros
 BuildRequires:  pkgconfig(krb5-gssapi)
 Requires:       python-multi_key_dict
+Requires:       python-pbr
 Requires:       python-requests
-Requires:       python-setuptools
 Requires:       python-six >= 1.3.0
 Provides:       python-jenkins = %{version}
 Obsoletes:      python-jenkins < %{version}
@@ -57,18 +61,22 @@
 %prep
 %autosetup -p1 -n python-jenkins-%{version}
 
+sed -i '1{\@^#!%{_bindir}/env python@d}' jenkins/__init__.py
+
 %build
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%pyunittest tests/*.py
+%pyunittest discover -v tests
 
 %files %{python_files}
 %license COPYING
 %doc README.rst
-%{python_sitelib}/*
+%{python_sitelib}/jenkins
+%{python_sitelib}/python_jenkins-%{version}*-info
 
 %changelog

++++++ python-jenkins-1.7.0.tar.gz -> python-jenkins-1.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/.zuul.yaml 
new/python-jenkins-1.8.0/.zuul.yaml
--- old/python-jenkins-1.7.0/.zuul.yaml 2020-03-04 04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/.zuul.yaml 2023-03-24 15:50:48.000000000 +0100
@@ -18,8 +18,6 @@
       jobs:
         - openstack-tox-linters
         - openstack-tox-py27
-        - openstack-tox-pypy:
-            nodeset: ubuntu-bionic
         - jjb-tox-cross-jenkins-job-builder
     gate:
       jobs:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/AUTHORS 
new/python-jenkins-1.8.0/AUTHORS
--- old/python-jenkins-1.7.0/AUTHORS    2020-03-04 04:07:27.000000000 +0100
+++ new/python-jenkins-1.8.0/AUTHORS    2023-03-24 15:51:12.000000000 +0100
@@ -26,6 +26,7 @@
 Emilien Macchi <emil...@redhat.com>
 Frank Lichtenheld <frank.lichtenh...@sophos.com>
 Guido Günther <a...@sigxcpu.org>
+Guillaume DeMengin <gdemen...@gmail.com>
 JP Sullivan <jonps...@cisco.com>
 James E. Blair <cor...@gnu.org>
 James E. Blair <jebl...@hp.com>
@@ -38,8 +39,10 @@
 Jeremy Stanley <fu...@yuggoth.org>
 Jerome Hourquebie <jhour...@cisco.com>
 Jerry Zhao <xyzje...@gmail.com>
+Jim Wisniewski <wis...@gmail.com>
 Jonathan Perret <jonat...@ut7.fr>
 K Jonathan Harker <jhar...@suse.com>
+Kazuhiro Suzuki <ksauzz...@gmail.com>
 Ken Conley k...@willowgarage.com <>
 Ken Dreyer <ktdre...@ktdreyer.com>
 Ken Rumer <kenru...@gmail.com>
@@ -49,7 +52,9 @@
 Lukas Vacek <lucas.va...@gmail.com>
 Marc Abramowitz <m...@marc-abramowitz.com>
 Marc Abramowitz <ma...@surveymonkey.com>
+Marcin Cieślak <sa...@saper.info>
 Marcos Diez <mar...@unitron.com.br>
+Michael Still <mi...@stillhq.com>
 Monty Taylor <mord...@inaugust.com>
 Nickolas Pohilets <pohil...@gmail.com>
 Ondřej Nový <ondrej.n...@firma.seznam.cz>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/ChangeLog 
new/python-jenkins-1.8.0/ChangeLog
--- old/python-jenkins-1.7.0/ChangeLog  2020-03-04 04:07:27.000000000 +0100
+++ new/python-jenkins-1.8.0/ChangeLog  2023-03-24 15:51:12.000000000 +0100
@@ -1,6 +1,21 @@
 CHANGES
 =======
 
+1.8.0
+-----
+
+* Fix CI tests
+* Handle new master naming in Jenkins post v2.307
+* Use fullname in get\_job\_info\_regex
+
+1.8.0.0a0
+---------
+
+* Allow build number to be a string
+* Switch links for contributors to opendev.org or launchpad
+* Add retrieval of stages and artifacts
+* Blacklist stestr 3.0.0 and drop pypy
+
 1.7.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/PKG-INFO 
new/python-jenkins-1.8.0/PKG-INFO
--- old/python-jenkins-1.7.0/PKG-INFO   2020-03-04 04:07:28.000000000 +0100
+++ new/python-jenkins-1.8.0/PKG-INFO   2023-03-24 15:51:12.177868000 +0100
@@ -1,13 +1,14 @@
 Metadata-Version: 1.2
 Name: python-jenkins
-Version: 1.7.0
+Version: 1.8.0
 Summary: Python bindings for the remote Jenkins API
-Home-page: http://git.openstack.org/cgit/openstack/python-jenkins
+Home-page: https://opendev.org/jjb/python-jenkins
 Author: Ken Conley
 Author-email: k...@willowgarage.com
-Maintainer: OpenStack Infrastructure Team
-Maintainer-email: openst...@lists.launchpad.net
+Maintainer: Python-Jenkins Developers
+Maintainer-email: python-jenkins-develop...@lists.launchpad.net
 License: BSD
+Project-URL: Documentation, https://python-jenkins.readthedocs.io/
 Description: README
         ======
         
@@ -56,15 +57,15 @@
         
         Repository:
         
-        * https://git.openstack.org/cgit/openstack/python-jenkins
+        * https://opendev.org/jjb/python-jenkins
         
         Cloning:
         
-        * git clone https://git.openstack.org/openstack/python-jenkins
+        * git clone https://opendev.org/jjb/python-jenkins
         
         Patches are submitted via Gerrit at:
         
-        * https://review.openstack.org/
+        * https://review.opendev.org/#/q/project:jjb/python-jenkins
         
         Please do not submit GitHub pull requests, they will be automatically 
closed.
         
@@ -73,7 +74,7 @@
         
         More details on how you can contribute is available on our wiki at:
         
-        * http://docs.openstack.org/infra/manual/developers.html
+        * https://docs.opendev.org/opendev/infra-manual/latest/developers.html
         
         Writing a patch
         ---------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/README.rst 
new/python-jenkins-1.8.0/README.rst
--- old/python-jenkins-1.7.0/README.rst 2020-03-04 04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/README.rst 2023-03-24 15:50:48.000000000 +0100
@@ -46,15 +46,15 @@
 
 Repository:
 
-* https://git.openstack.org/cgit/openstack/python-jenkins
+* https://opendev.org/jjb/python-jenkins
 
 Cloning:
 
-* git clone https://git.openstack.org/openstack/python-jenkins
+* git clone https://opendev.org/jjb/python-jenkins
 
 Patches are submitted via Gerrit at:
 
-* https://review.openstack.org/
+* https://review.opendev.org/#/q/project:jjb/python-jenkins
 
 Please do not submit GitHub pull requests, they will be automatically closed.
 
@@ -63,7 +63,7 @@
 
 More details on how you can contribute is available on our wiki at:
 
-* http://docs.openstack.org/infra/manual/developers.html
+* https://docs.opendev.org/opendev/infra-manual/latest/developers.html
 
 Writing a patch
 ---------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/bindep.txt 
new/python-jenkins-1.8.0/bindep.txt
--- old/python-jenkins-1.7.0/bindep.txt 2020-03-04 04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/bindep.txt 2023-03-24 15:50:48.000000000 +0100
@@ -4,7 +4,6 @@
 gcc [platform:rpm]
 pypy [test]
 pypy-dev [test]
-python-dev [platform:dpkg]
 python-devel [platform:rpm]
 python3-dev [platform:dpkg]
 python3-devel [platform:fedora]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/jenkins/__init__.py 
new/python-jenkins-1.8.0/jenkins/__init__.py
--- old/python-jenkins-1.7.0/jenkins/__init__.py        2020-03-04 
04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/jenkins/__init__.py        2023-03-24 
15:50:48.000000000 +0100
@@ -117,12 +117,14 @@
 BUILD_JOB = '%(folder_url)sjob/%(short_name)s/build'
 STOP_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/stop'
 BUILD_WITH_PARAMS_JOB = '%(folder_url)sjob/%(short_name)s/buildWithParameters'
-BUILD_INFO = 
'%(folder_url)sjob/%(short_name)s/%(number)d/api/json?depth=%(depth)s'
-BUILD_CONSOLE_OUTPUT = 
'%(folder_url)sjob/%(short_name)s/%(number)d/consoleText'
-BUILD_ENV_VARS = 
'%(folder_url)sjob/%(short_name)s/%(number)d/injectedEnvVars/api/json' + \
+BUILD_INFO = 
'%(folder_url)sjob/%(short_name)s/%(number)s/api/json?depth=%(depth)s'
+BUILD_CONSOLE_OUTPUT = 
'%(folder_url)sjob/%(short_name)s/%(number)s/consoleText'
+BUILD_ENV_VARS = 
'%(folder_url)sjob/%(short_name)s/%(number)s/injectedEnvVars/api/json' + \
     '?depth=%(depth)s'
-BUILD_TEST_REPORT = 
'%(folder_url)sjob/%(short_name)s/%(number)d/testReport/api/json' + \
+BUILD_TEST_REPORT = 
'%(folder_url)sjob/%(short_name)s/%(number)s/testReport/api/json' + \
     '?depth=%(depth)s'
+BUILD_ARTIFACT = 
'%(folder_url)sjob/%(short_name)s/%(number)s/artifact/%(artifact)s'
+BUILD_STAGES = '%(folder_url)sjob/%(short_name)s/%(number)s/wfapi/describe/'
 DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete'
 WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace'
 NODE_LIST = 'computer/api/json?depth=%(depth)s'
@@ -350,7 +352,8 @@
     def _get_encoded_params(self, params):
         for k, v in params.items():
             if k in ["name", "msg", "short_name", "from_short_name",
-                     "to_short_name", "folder_url", "from_folder_url", 
"to_folder_url"]:
+                     "to_short_name", "folder_url", "from_folder_url", 
"to_folder_url",
+                     "artifact"]:
                 params[k] = quote(v.encode('utf8'))
         return params
 
@@ -495,7 +498,7 @@
                                  
folder_depth_per_request=folder_depth_per_request)
         for job in jobs:
             if re.search(pattern, job['name']):
-                result.append(self.get_job_info(job['name'], depth=depth))
+                result.append(self.get_job_info(job['fullname'], depth=depth))
 
         return result
 
@@ -630,7 +633,7 @@
         '''Get build information dictionary.
 
         :param name: Job name, ``str``
-        :param number: Build number, ``int``
+        :param number: Build number, ``str`` (also accepts ``int``)
         :param depth: JSON depth, ``int``
         :returns: dictionary of build information, ``dict``
 
@@ -651,22 +654,20 @@
             if response:
                 return json.loads(response)
             else:
-                raise JenkinsException('job[%s] number[%d] does not exist'
+                raise JenkinsException('job[%s] number[%s] does not exist'
                                        % (name, number))
         except (req_exc.HTTPError, NotFoundException):
-            raise JenkinsException('job[%s] number[%d] does not exist'
+            raise JenkinsException('job[%s] number[%s] does not exist'
                                    % (name, number))
         except ValueError:
-            raise JenkinsException(
-                'Could not parse JSON info for job[%s] number[%d]'
-                % (name, number)
-            )
+            raise JenkinsException('Could not parse JSON info for job[%s] 
number[%s]'
+                                   % (name, number))
 
     def get_build_env_vars(self, name, number, depth=0):
         '''Get build environment variables.
 
         :param name: Job name, ``str``
-        :param number: Build number, ``int``
+        :param number: Build number, ``str`` (also accepts ``int``)
         :param depth: JSON depth, ``int``
         :returns: dictionary of build env vars, ``dict`` or None for workflow 
jobs,
             or if InjectEnvVars plugin not installed
@@ -678,12 +679,12 @@
             if response:
                 return json.loads(response)
             else:
-                raise JenkinsException('job[%s] number[%d] does not exist' % 
(name, number))
+                raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
         except req_exc.HTTPError:
-            raise JenkinsException('job[%s] number[%d] does not exist' % 
(name, number))
+            raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
         except ValueError:
             raise JenkinsException(
-                'Could not parse JSON info for job[%s] number[%d]' % (name, 
number))
+                'Could not parse JSON info for job[%s] number[%s]' % (name, 
number))
         except NotFoundException:
             # This can happen on workflow jobs, or if InjectEnvVars plugin not 
installed
             return None
@@ -692,7 +693,7 @@
         '''Get test results report.
 
         :param name: Job name, ``str``
-        :param number: Build number, ``int``
+        :param number: Build number, ``str`` (also accepts ``int``)
         :returns: dictionary of test report results, ``dict`` or None if there 
is no Test Report
         '''
         folder_url, short_name = self._get_job_folder(name)
@@ -702,16 +703,69 @@
             if response:
                 return json.loads(response)
             else:
-                raise JenkinsException('job[%s] number[%d] does not exist' % 
(name, number))
+                raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
         except req_exc.HTTPError:
-            raise JenkinsException('job[%s] number[%d] does not exist' % 
(name, number))
+            raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
         except ValueError:
             raise JenkinsException(
-                'Could not parse JSON info for job[%s] number[%d]' % (name, 
number))
+                'Could not parse JSON info for job[%s] number[%s]' % (name, 
number))
         except NotFoundException:
             # This can happen if the test report wasn't generated for any 
reason
             return None
 
+    def get_build_artifact(self, name, number, artifact):
+        """Get artifacts from job
+
+        :param name: Job name, ``str``
+        :param number: Build number, ``str`` (also accepts ``int``)
+        :param artifact: Artifact relative path, ``str``
+        :returns: artifact to download, ``dict``
+        """
+        folder_url, short_name = self._get_job_folder(name)
+
+        try:
+            response = self.jenkins_open(requests.Request(
+                    'GET', self._build_url(BUILD_ARTIFACT, locals())))
+
+            if response:
+                return json.loads(response)
+            else:
+                raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
+        except requests.exceptions.HTTPError:
+            raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
+        except ValueError:
+            raise JenkinsException(
+                'Could not parse JSON info for job[%s] number[%s]' % (name, 
number))
+        except NotFoundException:
+            # This can happen if the artifact is not found
+            return None
+
+    def get_build_stages(self, name, number):
+        """Get stages info from job
+
+        :param name: Job name, ``str``
+        :param number: Build number, ``str`` (also accepts ``int``)
+        :returns: dictionary of stages in the job, ``dict``
+        """
+        folder_url, short_name = self._get_job_folder(name)
+
+        try:
+            response = self.jenkins_open(requests.Request(
+                    'GET', self._build_url(BUILD_STAGES, locals())))
+
+            if response:
+                return json.loads(response)
+            else:
+                raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
+        except requests.exceptions.HTTPError:
+            raise JenkinsException('job[%s] number[%s] does not exist' % 
(name, number))
+        except ValueError:
+            raise JenkinsException(
+                'Could not parse JSON info for job[%s] number[%s]' % (name, 
number))
+        except NotFoundException:
+            # This can happen if this isn't a stages/pipeline job
+            return None
+
     def get_queue_info(self):
         ''':returns: list of job dictionaries, ``[dict]``
 
@@ -1445,7 +1499,7 @@
         for node in nodes:
             # the name returned is not the name to lookup when
             # dealing with master :/
-            if node['name'] == 'master':
+            if node['name'] in ['master', 'Built-In Node']:
                 node_name = '(master)'
             else:
                 node_name = node['name']
@@ -1500,6 +1554,9 @@
         :param depth: JSON depth, ``int``
         :returns: Dictionary of node info, ``dict``
         '''
+        if name == 'Built-In Node':
+            name = '(master)'
+
         try:
             response = self.jenkins_open(requests.Request(
                 'GET', self._build_url(NODE_INFO, locals())
@@ -1651,7 +1708,7 @@
         '''Get build console text.
 
         :param name: Job name, ``str``
-        :param number: Build number, ``int``
+        :param number: Build number, ``str`` (also accepts ``int``)
         :returns: Build console output,  ``str``
         '''
         folder_url, short_name = self._get_job_folder(name)
@@ -1662,10 +1719,10 @@
             if response:
                 return response
             else:
-                raise JenkinsException('job[%s] number[%d] does not exist'
+                raise JenkinsException('job[%s] number[%s] does not exist'
                                        % (name, number))
         except (req_exc.HTTPError, NotFoundException):
-            raise JenkinsException('job[%s] number[%d] does not exist'
+            raise JenkinsException('job[%s] number[%s] does not exist'
                                    % (name, number))
 
     def _get_job_folder(self, name):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-jenkins-1.7.0/python_jenkins.egg-info/PKG-INFO 
new/python-jenkins-1.8.0/python_jenkins.egg-info/PKG-INFO
--- old/python-jenkins-1.7.0/python_jenkins.egg-info/PKG-INFO   2020-03-04 
04:07:27.000000000 +0100
+++ new/python-jenkins-1.8.0/python_jenkins.egg-info/PKG-INFO   2023-03-24 
15:51:12.000000000 +0100
@@ -1,13 +1,14 @@
 Metadata-Version: 1.2
 Name: python-jenkins
-Version: 1.7.0
+Version: 1.8.0
 Summary: Python bindings for the remote Jenkins API
-Home-page: http://git.openstack.org/cgit/openstack/python-jenkins
+Home-page: https://opendev.org/jjb/python-jenkins
 Author: Ken Conley
 Author-email: k...@willowgarage.com
-Maintainer: OpenStack Infrastructure Team
-Maintainer-email: openst...@lists.launchpad.net
+Maintainer: Python-Jenkins Developers
+Maintainer-email: python-jenkins-develop...@lists.launchpad.net
 License: BSD
+Project-URL: Documentation, https://python-jenkins.readthedocs.io/
 Description: README
         ======
         
@@ -56,15 +57,15 @@
         
         Repository:
         
-        * https://git.openstack.org/cgit/openstack/python-jenkins
+        * https://opendev.org/jjb/python-jenkins
         
         Cloning:
         
-        * git clone https://git.openstack.org/openstack/python-jenkins
+        * git clone https://opendev.org/jjb/python-jenkins
         
         Patches are submitted via Gerrit at:
         
-        * https://review.openstack.org/
+        * https://review.opendev.org/#/q/project:jjb/python-jenkins
         
         Please do not submit GitHub pull requests, they will be automatically 
closed.
         
@@ -73,7 +74,7 @@
         
         More details on how you can contribute is available on our wiki at:
         
-        * http://docs.openstack.org/infra/manual/developers.html
+        * https://docs.opendev.org/opendev/infra-manual/latest/developers.html
         
         Writing a patch
         ---------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-jenkins-1.7.0/python_jenkins.egg-info/pbr.json 
new/python-jenkins-1.8.0/python_jenkins.egg-info/pbr.json
--- old/python-jenkins-1.7.0/python_jenkins.egg-info/pbr.json   2020-03-04 
04:07:27.000000000 +0100
+++ new/python-jenkins-1.8.0/python_jenkins.egg-info/pbr.json   2023-03-24 
15:51:12.000000000 +0100
@@ -1 +1 @@
-{"git_version": "9e66e45", "is_release": true}
\ No newline at end of file
+{"git_version": "70dc3e4", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-jenkins-1.7.0/python_jenkins.egg-info/requires.txt 
new/python-jenkins-1.8.0/python_jenkins.egg-info/requires.txt
--- old/python-jenkins-1.7.0/python_jenkins.egg-info/requires.txt       
2020-03-04 04:07:27.000000000 +0100
+++ new/python-jenkins-1.8.0/python_jenkins.egg-info/requires.txt       
2023-03-24 15:51:12.000000000 +0100
@@ -1,4 +1,5 @@
-six>=1.3.0
-pbr>=0.8.2
 multi_key_dict
+pbr>=0.8.2
 requests
+setuptools<66
+six>=1.3.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/requirements.txt 
new/python-jenkins-1.8.0/requirements.txt
--- old/python-jenkins-1.7.0/requirements.txt   2020-03-04 04:06:09.000000000 
+0100
+++ new/python-jenkins-1.8.0/requirements.txt   2023-03-24 15:50:48.000000000 
+0100
@@ -1,3 +1,5 @@
+# Setuptools removed support for PEP 440 non-conforming versions
+setuptools<66
 six>=1.3.0
 pbr>=0.8.2
 multi_key_dict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/setup.cfg 
new/python-jenkins-1.8.0/setup.cfg
--- old/python-jenkins-1.7.0/setup.cfg  2020-03-04 04:07:28.000000000 +0100
+++ new/python-jenkins-1.8.0/setup.cfg  2023-03-24 15:51:12.177868000 +0100
@@ -3,11 +3,13 @@
 author = Ken Conley
 author_email = k...@willowgarage.com
 summary = Python bindings for the remote Jenkins API
-maintainer = OpenStack Infrastructure Team
-maintainer_email = openst...@lists.launchpad.net
+maintainer = Python-Jenkins Developers
+maintainer_email = python-jenkins-develop...@lists.launchpad.net
 description-file = README.rst
 license = BSD
-home-page = http://git.openstack.org/cgit/openstack/python-jenkins
+home-page = https://opendev.org/jjb/python-jenkins
+project-urls = 
+       Documentation = https://python-jenkins.readthedocs.io/
 classifier = 
        Topic :: Utilities
        Intended Audience :: Developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/test-requirements.txt 
new/python-jenkins-1.8.0/test-requirements.txt
--- old/python-jenkins-1.7.0/test-requirements.txt      2020-03-04 
04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/test-requirements.txt      2023-03-24 
15:50:48.000000000 +0100
@@ -5,10 +5,11 @@
 unittest2
 python-subunit
 requests-mock>=1.4.0
-requests-kerberos
+requests-kerberos<=0.12.0;python_version<'3.6'
+requests-kerberos;python_version>='3.6'
 sphinx>=1.6.0,<2.0.0;python_version=='2.7'  # BSD
 sphinx>=1.6.0;python_version>='3.4'  # BSD
-stestr>=2.0.0
+stestr>=2.0.0,!=3.0.0
 testscenarios
 testtools
 pre-commit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/tests/jobs/test_info.py 
new/python-jenkins-1.8.0/tests/jobs/test_info.py
--- old/python-jenkins-1.7.0/tests/jobs/test_info.py    2020-03-04 
04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/tests/jobs/test_info.py    2023-03-24 
15:50:48.000000000 +0100
@@ -110,22 +110,36 @@
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_regex(self, jenkins_mock):
+        parent_job = {
+            u'name': u'nested-parent-job',
+            u'jobs': [{u'name': u'nested-child-job'}],
+        }
         jobs = [
             {u'name': u'my-job-1'},
             {u'name': u'my-job-2'},
             {u'name': u'your-job-1'},
             {u'name': u'Your-Job-1'},
             {u'name': u'my-project-1'},
+            parent_job,
         ]
         job_info_to_return = {u'jobs': jobs}
-        jenkins_mock.return_value = json.dumps(job_info_to_return)
+
+        def mock_jenkins_open(req, **kwargs):
+            return json.dumps(parent_job if parent_job['name'] in req.url else 
job_info_to_return)
+        jenkins_mock.side_effect = mock_jenkins_open
 
         self.assertEqual(len(self.j.get_job_info_regex('her-job')), 0)
         self.assertEqual(len(self.j.get_job_info_regex('my-job-1')), 1)
         self.assertEqual(len(self.j.get_job_info_regex('my-job')), 2)
-        self.assertEqual(len(self.j.get_job_info_regex('job')), 3)
+        self.assertEqual(len(self.j.get_job_info_regex('job')), 4)
+        self.assertEqual(len(self.j.get_job_info_regex('job', 
folder_depth=1)), 5)
         self.assertEqual(len(self.j.get_job_info_regex('project')), 1)
         self.assertEqual(len(self.j.get_job_info_regex('[Yy]our-[Jj]ob-1')), 2)
+        self.assertEqual(len(self.j.get_job_info_regex('nested-.*-job')), 1)
+        self.assertEqual(len(self.j.get_job_info_regex('nested-.*-job', 
folder_depth=1)), 2)
+        self.assertEqual(len(self.j.get_job_info_regex('parent')), 1)
+        self.assertEqual(len(self.j.get_job_info_regex('child')), 0)
+        self.assertEqual(len(self.j.get_job_info_regex('child', 
folder_depth=1)), 1)
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/tests/test_build.py 
new/python-jenkins-1.8.0/tests/test_build.py
--- old/python-jenkins-1.7.0/tests/test_build.py        2020-03-04 
04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/tests/test_build.py        2023-03-24 
15:50:48.000000000 +0100
@@ -14,7 +14,7 @@
     def test_simple(self, jenkins_mock):
         jenkins_mock.return_value = "build console output..."
 
-        build_info = self.j.get_build_console_output(u'Test Job', number=52)
+        build_info = self.j.get_build_console_output(u'Test Job', number='52')
 
         self.assertEqual(build_info, jenkins_mock.return_value)
         self.assertEqual(
@@ -26,7 +26,7 @@
     def test_in_folder(self, jenkins_mock):
         jenkins_mock.return_value = "build console output..."
 
-        build_info = self.j.get_build_console_output(u'a Folder/Test Job', 
number=52)
+        build_info = self.j.get_build_console_output(u'a Folder/Test Job', 
number='52')
 
         self.assertEqual(build_info, jenkins_mock.return_value)
         self.assertEqual(
@@ -35,10 +35,23 @@
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        jenkins_mock.return_value = "build console output..."
+
+        build_info = self.j.get_build_console_output(u'a Folder/Test Job', 
number='52/label=matrix')
+
+        self.assertEqual(build_info, jenkins_mock.return_value)
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            
self.make_url('job/a%20Folder/job/Test%20Job/52/label=matrix/consoleText'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_return_none(self, jenkins_mock):
         jenkins_mock.return_value = None
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
             self.j.get_build_console_output(u'TestJob', number=52)
         self.assertEqual(
             str(context_manager.exception),
@@ -50,17 +63,28 @@
         jenkins_mock.return_value = None
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_console_output(u'A Folder/TestJob', number=52)
+            self.j.get_build_console_output(u'A Folder/TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[A Folder/TestJob] number[52] does not exist')
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix_return_none(self, jenkins_mock):
+        jenkins_mock.return_value = None
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_console_output(u'A Folder/TestJob', 
number='52/label=matrix')
+        self.assertEqual(
+            str(context_manager.exception),
+            'job[A Folder/TestJob] number[52/label=matrix] does not exist')
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_return_invalid_json(self, jenkins_mock):
         jenkins_mock.return_value = 'Invalid JSON'
 
-        console_output = self.j.get_build_console_output(u'TestJob', number=52)
+        console_output = self.j.get_build_console_output(u'TestJob', 
number='52')
         self.assertEqual(console_output, jenkins_mock.return_value)
 
     @patch('jenkins.requests.Session.send')
@@ -71,7 +95,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_console_output(u'TestJob', number=52)
+            self.j.get_build_console_output(u'TestJob', number='52')
         self.assertEqual(
             session_send_mock.call_args_list[1][0][0].url,
             self.make_url('job/TestJob/52/consoleText'))
@@ -87,6 +111,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
             self.j.get_build_console_output(u'a Folder/TestJob', number=52)
         self.assertEqual(
             session_send_mock.call_args_list[1][0][0].url,
@@ -108,7 +133,7 @@
         }
         jenkins_mock.return_value = json.dumps(build_info_to_return)
 
-        build_info = self.j.get_build_info(u'Test Job', number=52)
+        build_info = self.j.get_build_info(u'Test Job', number='52')
 
         self.assertEqual(build_info, build_info_to_return)
         self.assertEqual(
@@ -126,7 +151,7 @@
         }
         jenkins_mock.return_value = json.dumps(build_info_to_return)
 
-        build_info = self.j.get_build_info(u'a Folder/Test Job', number=52)
+        build_info = self.j.get_build_info(u'a Folder/Test Job', number='52')
 
         self.assertEqual(build_info, build_info_to_return)
         self.assertEqual(
@@ -135,11 +160,29 @@
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        build_info_to_return = {
+            u'building': False,
+            u'msg': u'test',
+            u'revision': 66,
+            u'user': u'unknown'
+        }
+        jenkins_mock.return_value = json.dumps(build_info_to_return)
+
+        build_info = self.j.get_build_info(u'a Folder/Test Job', 
number='52/label=matrix')
+
+        self.assertEqual(build_info, build_info_to_return)
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            
self.make_url('job/a%20Folder/job/Test%20Job/52/label=matrix/api/json?depth=0'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_return_none(self, jenkins_mock):
         jenkins_mock.return_value = None
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_info(u'TestJob', number=52)
+            self.j.get_build_info(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] number[52] does not exist')
@@ -150,6 +193,7 @@
         jenkins_mock.return_value = 'Invalid JSON'
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
             self.j.get_build_info(u'TestJob', number=52)
         self.assertEqual(
             str(context_manager.exception),
@@ -164,7 +208,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_info(u'TestJob', number=52)
+            self.j.get_build_info(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] number[52] does not exist')
@@ -177,7 +221,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_info(u'a Folder/TestJob', number=52)
+            self.j.get_build_info(u'a Folder/TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[a Folder/TestJob] number[52] does not exist')
@@ -187,7 +231,7 @@
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_simple(self, jenkins_mock):
-        self.j.stop_build(u'Test Job', number=52)
+        self.j.stop_build(u'Test Job', number='52')
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -197,7 +241,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder(self, jenkins_mock):
 
-        self.j.stop_build(u'a Folder/Test Job', number=52)
+        self.j.stop_build(u'a Folder/Test Job', number='52')
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -209,7 +253,7 @@
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_simple(self, jenkins_mock):
-        self.j.delete_build(u'Test Job', number=52)
+        self.j.delete_build(u'Test Job', number='52')
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -219,7 +263,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder(self, jenkins_mock):
 
-        self.j.delete_build(u'a Folder/Test Job', number=52)
+        self.j.delete_build(u'a Folder/Test Job', number='52')
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -496,7 +540,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_simple(self, jenkins_mock):
         jenkins_mock.return_value = '{}'
-        ret = self.j.get_build_env_vars(u'Test Job', number=52, depth=1)
+        ret = self.j.get_build_env_vars(u'Test Job', number='52', depth=1)
         self.assertEqual(ret, json.loads(jenkins_mock.return_value))
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -506,6 +550,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder(self, jenkins_mock):
         jenkins_mock.return_value = '{}'
+        # Test with a number to ensure it works as well as string
         ret = self.j.get_build_env_vars(u'a Folder/Test Job', number=52, 
depth=1)
         self.assertEqual(ret, json.loads(jenkins_mock.return_value))
         self.assertEqual(
@@ -513,13 +558,24 @@
             
self.make_url('job/a%20Folder/job/Test%20Job/52/injectedEnvVars/api/json?depth=1'))
         self._check_requests(jenkins_mock.call_args_list)
 
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_env_vars(u'a Folder/Test Job', 
number='52/index=matrix', depth=1)
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            self.make_url(
+                
'job/a%20Folder/job/Test%20Job/52/index=matrix/injectedEnvVars/api/json?depth=1'))
+        self._check_requests(jenkins_mock.call_args_list)
+
     @patch('jenkins.requests.Session.send', autospec=True)
     def test_return_none(self, session_send_mock):
         session_send_mock.side_effect = iter([
             build_response_mock(404, reason="Not Found"),  # crumb
             build_response_mock(404, reason="Not Found"),  # request
         ])
-        ret = self.j.get_build_env_vars(u'TestJob', number=52)
+        ret = self.j.get_build_env_vars(u'TestJob', number='52')
         self.assertIsNone(ret)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -527,7 +583,7 @@
         jenkins_mock.return_value = None
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_env_vars(u'TestJob', number=52)
+            self.j.get_build_env_vars(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] number[52] does not exist')
@@ -538,7 +594,7 @@
         jenkins_mock.return_value = 'Invalid JSON'
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_env_vars(u'TestJob', number=52)
+            self.j.get_build_env_vars(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'Could not parse JSON info for job[TestJob] number[52]')
@@ -552,6 +608,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
             self.j.get_build_env_vars(u'TestJob', number=52)
         self.assertEqual(
             str(context_manager.exception),
@@ -565,7 +622,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_env_vars(u'a Folder/TestJob', number=52)
+            self.j.get_build_env_vars(u'a Folder/TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'Error in request. Possibly authentication failed [401]: Not 
Authorised')
@@ -576,7 +633,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_simple(self, jenkins_mock):
         jenkins_mock.return_value = '{}'
-        ret = self.j.get_build_test_report(u'Test Job', number=52, depth=1)
+        ret = self.j.get_build_test_report(u'Test Job', number='52', depth=1)
         self.assertEqual(ret, json.loads(jenkins_mock.return_value))
         self.assertEqual(
             jenkins_mock.call_args[0][0].url,
@@ -586,6 +643,7 @@
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder(self, jenkins_mock):
         jenkins_mock.return_value = '{}'
+        # Test with a number to ensure it works as well as string
         ret = self.j.get_build_test_report(u'a Folder/Test Job', number=52, 
depth=1)
         self.assertEqual(ret, json.loads(jenkins_mock.return_value))
         self.assertEqual(
@@ -593,13 +651,24 @@
             
self.make_url('job/a%20Folder/job/Test%20Job/52/testReport/api/json?depth=1'))
         self._check_requests(jenkins_mock.call_args_list)
 
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_test_report(u'a Folder/Test Job', 
number='52/index=matrix', depth=1)
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            self.make_url(
+                
'job/a%20Folder/job/Test%20Job/52/index=matrix/testReport/api/json?depth=1'))
+        self._check_requests(jenkins_mock.call_args_list)
+
     @patch('jenkins.requests.Session.send', autospec=True)
     def test_return_none(self, session_send_mock):
         session_send_mock.side_effect = iter([
             build_response_mock(404, reason="Not Found"),  # crumb
             build_response_mock(404, reason="Not Found"),  # request
         ])
-        ret = self.j.get_build_test_report(u'TestJob', number=52)
+        ret = self.j.get_build_test_report(u'TestJob', number='52')
         self.assertIsNone(ret)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -607,7 +676,7 @@
         jenkins_mock.return_value = None
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_test_report(u'TestJob', number=52)
+            self.j.get_build_test_report(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] number[52] does not exist')
@@ -618,7 +687,7 @@
         jenkins_mock.return_value = 'Invalid JSON'
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_test_report(u'TestJob', number=52)
+            self.j.get_build_test_report(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'Could not parse JSON info for job[TestJob] number[52]')
@@ -632,7 +701,7 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
-            self.j.get_build_test_report(u'TestJob', number=52)
+            self.j.get_build_test_report(u'TestJob', number='52')
         self.assertEqual(
             str(context_manager.exception),
             'Error in request. Possibly authentication failed [401]: Not 
Authorised')
@@ -645,7 +714,190 @@
         ])
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
             self.j.get_build_test_report(u'a Folder/TestJob', number=52)
         self.assertEqual(
             str(context_manager.exception),
             'Error in request. Possibly authentication failed [401]: Not 
Authorised')
+
+
+class JenkinsBuildArtifactUrlTest(JenkinsTestBase):
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_simple(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_artifact(u'Test Job', number='52', 
artifact="filename")
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            self.make_url('job/Test%20Job/52/artifact/filename'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_in_folder(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_artifact(u'a Folder/Test Job', number='52', 
artifact="file name")
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            
self.make_url('job/a%20Folder/job/Test%20Job/52/artifact/file%20name'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_artifact(u'a Folder/Test Job', 
number='52/index=matrix',
+                                        artifact="file name")
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            
self.make_url('job/a%20Folder/job/Test%20Job/52/index=matrix/artifact/file%20name'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_return_none(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(404, reason="Not Found"),  # crumb
+            build_response_mock(404, reason="Not Found"),  # request
+        ])
+        ret = self.j.get_build_artifact(u'TestJob', number='52', 
artifact="filename")
+        self.assertIsNone(ret)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_open_return_none(self, jenkins_mock):
+        jenkins_mock.return_value = None
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_artifact(u'TestJob', number='52', 
artifact="filename")
+        self.assertEqual(
+            str(context_manager.exception),
+            'job[TestJob] number[52] does not exist')
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_return_invalid_json(self, jenkins_mock):
+        jenkins_mock.return_value = 'Invalid JSON'
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_artifact(u'TestJob', number='52', 
artifact="filename")
+        self.assertEqual(
+            str(context_manager.exception),
+            'Could not parse JSON info for job[TestJob] number[52]')
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_raise_HTTPError(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(401, reason="Not Authorised"),  # crumb
+            build_response_mock(401, reason="Not Authorised"),  # request
+        ])
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_artifact(u'TestJob', number='52', 
artifact="filename")
+        self.assertEqual(
+            str(context_manager.exception),
+            'Error in request. Possibly authentication failed [401]: Not 
Authorised')
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_in_folder_raise_HTTPError(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(401, reason="Not Authorised"),  # crumb
+            build_response_mock(401, reason="Not Authorised"),  # request
+        ])
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_artifact(u'a Folder/TestJob', number='52', 
artifact="filename")
+        self.assertEqual(
+            str(context_manager.exception),
+            'Error in request. Possibly authentication failed [401]: Not 
Authorised')
+
+
+class JenkinsBuildStagesUrlTest(JenkinsTestBase):
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_simple(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_stages(u'Test Job', number='52')
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            self.make_url('job/Test%20Job/52/wfapi/describe/'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_matrix(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_stages(u'a Folder/Test Job', 
number='52/index=matrix')
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            
self.make_url('job/a%20Folder/job/Test%20Job/52/index=matrix/wfapi/describe/'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_in_folder(self, jenkins_mock):
+        jenkins_mock.return_value = '{}'
+        ret = self.j.get_build_stages(u'a Folder/Test Job', number='52')
+        self.assertEqual(ret, json.loads(jenkins_mock.return_value))
+        self.assertEqual(
+            jenkins_mock.call_args[0][0].url,
+            self.make_url('job/a%20Folder/job/Test%20Job/52/wfapi/describe/'))
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_return_none(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(404, reason="Not Found"),  # crumb
+            build_response_mock(404, reason="Not Found"),  # request
+        ])
+        ret = self.j.get_build_stages(u'TestJob', number='52')
+        self.assertIsNone(ret)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_open_return_none(self, jenkins_mock):
+        jenkins_mock.return_value = None
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            # Test with a number for a printing case, to ensure it works
+            self.j.get_build_stages(u'TestJob', number=52)
+        self.assertEqual(
+            str(context_manager.exception),
+            'job[TestJob] number[52] does not exist')
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_return_invalid_json(self, jenkins_mock):
+        jenkins_mock.return_value = 'Invalid JSON'
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_stages(u'TestJob', number='52')
+        self.assertEqual(
+            str(context_manager.exception),
+            'Could not parse JSON info for job[TestJob] number[52]')
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_raise_HTTPError(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(401, reason="Not Authorised"),  # crumb
+            build_response_mock(401, reason="Not Authorised"),  # request
+        ])
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_stages(u'TestJob', number='52')
+        self.assertEqual(
+            str(context_manager.exception),
+            'Error in request. Possibly authentication failed [401]: Not 
Authorised')
+
+    @patch('jenkins.requests.Session.send', autospec=True)
+    def test_in_folder_raise_HTTPError(self, session_send_mock):
+        session_send_mock.side_effect = iter([
+            build_response_mock(401, reason="Not Authorised"),  # crumb
+            build_response_mock(401, reason="Not Authorised"),  # request
+        ])
+
+        with self.assertRaises(jenkins.JenkinsException) as context_manager:
+            self.j.get_build_stages(u'a Folder/TestJob', number='52')
+        self.assertEqual(
+            str(context_manager.exception),
+            'Error in request. Possibly authentication failed [401]: Not 
Authorised')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-jenkins-1.7.0/tox.ini 
new/python-jenkins-1.8.0/tox.ini
--- old/python-jenkins-1.7.0/tox.ini    2020-03-04 04:06:09.000000000 +0100
+++ new/python-jenkins-1.8.0/tox.ini    2023-03-24 15:50:48.000000000 +0100
@@ -1,7 +1,7 @@
 [tox]
 minversion = 2.0
 skipsdist = True
-envlist = py{34,27,35,36}, linters, pypy
+envlist = py{34,27,35,36}, linters
 
 [testenv]
 setenv =
@@ -9,12 +9,13 @@
          VIRTUAL_ENV={envdir}
 usedevelop = True
 install_command = pip install {opts} {packages}
-deps = -r{toxinidir}/test-requirements.txt
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
 commands =
     - find . -type f -name "*.pyc" -delete
     - find . -type d -name "__pycache__" -delete
     stestr run --slowest {posargs}
-whitelist_externals =
+allowlist_externals =
     bash
     find
 
@@ -25,7 +26,7 @@
 commands =
     bash -c "if [ -d {toxinidir}/../jenkins-job-builder ]; then \
     pip install -q -U -e 
'git+file://{toxinidir}/../jenkins-job-builder#egg=jenkins-job-builder' ; else \
-    pip install -q -U -e 
'git+https://git.openstack.org/openstack-infra/jenkins-job-builder@master#egg=jenkins-job-builder'
 ; fi "
+    pip install -q -U -e 
'https://opendev.org/jjb/python-jenkins@master#egg=jenkins-job-builder' ; fi "
     stestr run --slowest {posargs}
 
 [testenv:cover]

++++++ python-python-jenkins-no-mock.patch ++++++
--- /var/tmp/diff_new_pack.FuQzQJ/_old  2023-04-17 17:41:27.686278399 +0200
+++ /var/tmp/diff_new_pack.FuQzQJ/_new  2023-04-17 17:41:27.690278422 +0200
@@ -1,17 +1,79 @@
-diff -upr python-jenkins-1.7.0.orig/tests/base.py 
python-jenkins-1.7.0/tests/base.py
---- python-jenkins-1.7.0.orig/tests/base.py    2022-05-03 14:48:58.234141501 
+0200
-+++ python-jenkins-1.7.0/tests/base.py 2022-05-03 14:48:58.242141551 +0200
-@@ -1,6 +1,6 @@
+---
+ test-requirements.txt                    |    2 --
+ tests/base.py                            |    7 ++-----
+ tests/helper.py                          |    2 +-
+ tests/jobs/test_assert.py                |    2 +-
+ tests/jobs/test_build.py                 |    2 +-
+ tests/jobs/test_config.py                |    2 +-
+ tests/jobs/test_copy.py                  |    2 +-
+ tests/jobs/test_count.py                 |    2 +-
+ tests/jobs/test_create.py                |    2 +-
+ tests/jobs/test_debug.py                 |    2 +-
+ tests/jobs/test_delete.py                |    2 +-
+ tests/jobs/test_disable.py               |    2 +-
+ tests/jobs/test_enable.py                |    2 +-
+ tests/jobs/test_get.py                   |    2 +-
+ tests/jobs/test_getall.py                |    2 +-
+ tests/jobs/test_info.py                  |    2 +-
+ tests/jobs/test_name.py                  |    2 +-
+ tests/jobs/test_reconfig.py              |    2 +-
+ tests/jobs/test_rename.py                |    2 +-
+ tests/jobs/test_set_next_build_number.py |    2 +-
+ tests/test_build.py                      |    2 +-
+ tests/test_check_jenkinsfile_syntax.py   |    2 +-
+ tests/test_credential.py                 |    2 +-
+ tests/test_info.py                       |    2 +-
+ tests/test_jenkins.py                    |    2 +-
+ tests/test_job_folder.py                 |    2 +-
+ tests/test_node.py                       |    2 +-
+ tests/test_plugins.py                    |    2 +-
+ tests/test_promotion.py                  |    2 +-
+ tests/test_queue.py                      |    2 +-
+ tests/test_quiet_down.py                 |    2 +-
+ tests/test_script.py                     |    2 +-
+ tests/test_version.py                    |    2 +-
+ tests/test_view.py                       |    2 +-
+ tests/test_whoami.py                     |    2 +-
+ 35 files changed, 35 insertions(+), 40 deletions(-)
+
+Index: python-jenkins-1.8.0/test-requirements.txt
+===================================================================
+--- python-jenkins-1.8.0.orig/test-requirements.txt
++++ python-jenkins-1.8.0/test-requirements.txt
+@@ -1,8 +1,6 @@
+ cmd2!=0.8.3,<0.9.0;python_version<'3.0'  # MIT
+ cmd2!=0.8.3;python_version>='3.0'  # MIT
+ coverage>=3.6
+-mock
+-unittest2
+ python-subunit
+ requests-mock>=1.4.0
+ requests-kerberos<=0.12.0;python_version<'3.6'
+Index: python-jenkins-1.8.0/tests/base.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/base.py
++++ python-jenkins-1.8.0/tests/base.py
+@@ -1,14 +1,11 @@
  import sys
  
 -import mock
 +from unittest import mock
++import unittest
  from testscenarios import TestWithScenarios
  
  import jenkins
-diff -upr python-jenkins-1.7.0.orig/tests/helper.py 
python-jenkins-1.7.0/tests/helper.py
---- python-jenkins-1.7.0.orig/tests/helper.py  2022-05-03 14:48:58.234141501 
+0200
-+++ python-jenkins-1.7.0/tests/helper.py       2022-05-03 14:48:58.242141551 
+0200
+ 
+-if sys.version_info < (2, 7):
+-    import unittest2 as unittest
+-else:
+-    import unittest
+ 
+ 
+ class JenkinsTestBase(TestWithScenarios, unittest.TestCase):
+Index: python-jenkins-1.8.0/tests/helper.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/helper.py
++++ python-jenkins-1.8.0/tests/helper.py
 @@ -4,7 +4,7 @@ from multiprocessing import Process
  from multiprocessing import Queue
  import traceback
@@ -21,9 +83,10 @@
  import requests
  from six.moves import socketserver
  
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_assert.py 
python-jenkins-1.7.0/tests/jobs/test_assert.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_assert.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_assert.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_assert.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_assert.py
++++ python-jenkins-1.8.0/tests/jobs/test_assert.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -31,9 +94,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_build.py 
python-jenkins-1.7.0/tests/jobs/test_build.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_build.py 2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_build.py      2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_build.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_build.py
++++ python-jenkins-1.8.0/tests/jobs/test_build.py
 @@ -1,5 +1,5 @@
  # -*- coding: utf-8 -*-
 -from mock import patch
@@ -41,18 +105,20 @@
  
  import jenkins
  from six.moves.urllib.parse import quote
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_config.py 
python-jenkins-1.7.0/tests/jobs/test_config.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_config.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_config.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_config.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_config.py
++++ python-jenkins-1.8.0/tests/jobs/test_config.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_copy.py 
python-jenkins-1.7.0/tests/jobs/test_copy.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_copy.py  2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_copy.py       2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_copy.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_copy.py
++++ python-jenkins-1.8.0/tests/jobs/test_copy.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -60,9 +126,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_count.py 
python-jenkins-1.7.0/tests/jobs/test_count.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_count.py 2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_count.py      2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_count.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_count.py
++++ python-jenkins-1.8.0/tests/jobs/test_count.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -70,9 +137,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_create.py 
python-jenkins-1.7.0/tests/jobs/test_create.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_create.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_create.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_create.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_create.py
++++ python-jenkins-1.8.0/tests/jobs/test_create.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -80,9 +148,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_debug.py 
python-jenkins-1.7.0/tests/jobs/test_debug.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_debug.py 2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_debug.py      2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_debug.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_debug.py
++++ python-jenkins-1.8.0/tests/jobs/test_debug.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -90,9 +159,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_delete.py 
python-jenkins-1.7.0/tests/jobs/test_delete.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_delete.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_delete.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_delete.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_delete.py
++++ python-jenkins-1.8.0/tests/jobs/test_delete.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -100,9 +170,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_disable.py 
python-jenkins-1.7.0/tests/jobs/test_disable.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_disable.py       2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_disable.py    2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_disable.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_disable.py
++++ python-jenkins-1.8.0/tests/jobs/test_disable.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -110,9 +181,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_enable.py 
python-jenkins-1.7.0/tests/jobs/test_enable.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_enable.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_enable.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_enable.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_enable.py
++++ python-jenkins-1.8.0/tests/jobs/test_enable.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -120,29 +192,32 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_getall.py 
python-jenkins-1.7.0/tests/jobs/test_getall.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_getall.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_getall.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_get.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_get.py
++++ python-jenkins-1.8.0/tests/jobs/test_get.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
- from tests.jobs.base import JenkinsGetJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_get.py 
python-jenkins-1.7.0/tests/jobs/test_get.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_get.py   2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_get.py        2022-05-03 
14:48:58.246141576 +0200
+ from tests.helper import build_response_mock
+Index: python-jenkins-1.8.0/tests/jobs/test_getall.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_getall.py
++++ python-jenkins-1.8.0/tests/jobs/test_getall.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
- from tests.helper import build_response_mock
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_info.py 
python-jenkins-1.7.0/tests/jobs/test_info.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_info.py  2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_info.py       2022-05-03 
14:48:58.246141576 +0200
+ from tests.jobs.base import JenkinsGetJobsTestBase
+Index: python-jenkins-1.8.0/tests/jobs/test_info.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_info.py
++++ python-jenkins-1.8.0/tests/jobs/test_info.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -150,9 +225,10 @@
  
  import jenkins
  from tests.helper import build_response_mock
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_name.py 
python-jenkins-1.7.0/tests/jobs/test_name.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_name.py  2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_name.py       2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_name.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_name.py
++++ python-jenkins-1.8.0/tests/jobs/test_name.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -160,9 +236,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_reconfig.py 
python-jenkins-1.7.0/tests/jobs/test_reconfig.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_reconfig.py      2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_reconfig.py   2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_reconfig.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_reconfig.py
++++ python-jenkins-1.8.0/tests/jobs/test_reconfig.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -170,9 +247,10 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_rename.py 
python-jenkins-1.7.0/tests/jobs/test_rename.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_rename.py        2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_rename.py     2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_rename.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_rename.py
++++ python-jenkins-1.8.0/tests/jobs/test_rename.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -180,18 +258,20 @@
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/jobs/test_set_next_build_number.py 
python-jenkins-1.7.0/tests/jobs/test_set_next_build_number.py
---- python-jenkins-1.7.0.orig/tests/jobs/test_set_next_build_number.py 
2022-05-03 14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/jobs/test_set_next_build_number.py      
2022-05-03 14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/jobs/test_set_next_build_number.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/jobs/test_set_next_build_number.py
++++ python-jenkins-1.8.0/tests/jobs/test_set_next_build_number.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
  from tests.jobs.base import JenkinsJobsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_build.py 
python-jenkins-1.7.0/tests/test_build.py
---- python-jenkins-1.7.0.orig/tests/test_build.py      2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_build.py   2022-05-03 14:48:58.242141551 
+0200
+Index: python-jenkins-1.8.0/tests/test_build.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_build.py
++++ python-jenkins-1.8.0/tests/test_build.py
 @@ -1,7 +1,7 @@
  import json
  
@@ -201,18 +281,20 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_check_jenkinsfile_syntax.py 
python-jenkins-1.7.0/tests/test_check_jenkinsfile_syntax.py
---- python-jenkins-1.7.0.orig/tests/test_check_jenkinsfile_syntax.py   
2022-05-03 14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_check_jenkinsfile_syntax.py        
2022-05-03 14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/test_check_jenkinsfile_syntax.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_check_jenkinsfile_syntax.py
++++ python-jenkins-1.8.0/tests/test_check_jenkinsfile_syntax.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  from tests.base import JenkinsTestBase
  from tests.helper import build_response_mock
-diff -upr python-jenkins-1.7.0.orig/tests/test_credential.py 
python-jenkins-1.7.0/tests/test_credential.py
---- python-jenkins-1.7.0.orig/tests/test_credential.py 2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_credential.py      2022-05-03 
14:48:58.242141551 +0200
+Index: python-jenkins-1.8.0/tests/test_credential.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_credential.py
++++ python-jenkins-1.8.0/tests/test_credential.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -220,9 +302,10 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_info.py 
python-jenkins-1.7.0/tests/test_info.py
---- python-jenkins-1.7.0.orig/tests/test_info.py       2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/test_info.py    2022-05-03 14:48:58.246141576 
+0200
+Index: python-jenkins-1.8.0/tests/test_info.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_info.py
++++ python-jenkins-1.8.0/tests/test_info.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -230,9 +313,10 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_jenkins.py 
python-jenkins-1.7.0/tests/test_jenkins.py
---- python-jenkins-1.7.0.orig/tests/test_jenkins.py    2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_jenkins.py 2022-05-03 14:48:58.246141576 
+0200
+Index: python-jenkins-1.8.0/tests/test_jenkins.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_jenkins.py
++++ python-jenkins-1.8.0/tests/test_jenkins.py
 @@ -1,7 +1,7 @@
  import json
  import socket
@@ -242,18 +326,20 @@
  import six
  
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_job_folder.py 
python-jenkins-1.7.0/tests/test_job_folder.py
---- python-jenkins-1.7.0.orig/tests/test_job_folder.py 2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_job_folder.py      2022-05-03 
14:48:58.242141551 +0200
+Index: python-jenkins-1.8.0/tests/test_job_folder.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_job_folder.py
++++ python-jenkins-1.8.0/tests/test_job_folder.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_node.py 
python-jenkins-1.7.0/tests/test_node.py
---- python-jenkins-1.7.0.orig/tests/test_node.py       2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_node.py    2022-05-03 14:48:58.242141551 
+0200
+Index: python-jenkins-1.8.0/tests/test_node.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_node.py
++++ python-jenkins-1.8.0/tests/test_node.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -261,9 +347,10 @@
  
  import jenkins
  import requests_mock
-diff -upr python-jenkins-1.7.0.orig/tests/test_plugins.py 
python-jenkins-1.7.0/tests/test_plugins.py
---- python-jenkins-1.7.0.orig/tests/test_plugins.py    2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_plugins.py 2022-05-03 14:48:58.242141551 
+0200
+Index: python-jenkins-1.8.0/tests/test_plugins.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_plugins.py
++++ python-jenkins-1.8.0/tests/test_plugins.py
 @@ -32,7 +32,7 @@
  
  
@@ -273,9 +360,10 @@
  from testscenarios.scenarios import multiply_scenarios
  
  import jenkins
-diff -upr python-jenkins-1.7.0.orig/tests/test_promotion.py 
python-jenkins-1.7.0/tests/test_promotion.py
---- python-jenkins-1.7.0.orig/tests/test_promotion.py  2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_promotion.py       2022-05-03 
14:48:58.242141551 +0200
+Index: python-jenkins-1.8.0/tests/test_promotion.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_promotion.py
++++ python-jenkins-1.8.0/tests/test_promotion.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -283,9 +371,10 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_queue.py 
python-jenkins-1.7.0/tests/test_queue.py
---- python-jenkins-1.7.0.orig/tests/test_queue.py      2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_queue.py   2022-05-03 14:48:58.246141576 
+0200
+Index: python-jenkins-1.8.0/tests/test_queue.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_queue.py
++++ python-jenkins-1.8.0/tests/test_queue.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -293,9 +382,10 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_quiet_down.py 
python-jenkins-1.7.0/tests/test_quiet_down.py
---- python-jenkins-1.7.0.orig/tests/test_quiet_down.py 2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/test_quiet_down.py      2022-05-03 
14:48:58.246141576 +0200
+Index: python-jenkins-1.8.0/tests/test_quiet_down.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_quiet_down.py
++++ python-jenkins-1.8.0/tests/test_quiet_down.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -303,27 +393,30 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_script.py 
python-jenkins-1.7.0/tests/test_script.py
---- python-jenkins-1.7.0.orig/tests/test_script.py     2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_script.py  2022-05-03 14:48:58.242141551 
+0200
+Index: python-jenkins-1.8.0/tests/test_script.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_script.py
++++ python-jenkins-1.8.0/tests/test_script.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_version.py 
python-jenkins-1.7.0/tests/test_version.py
---- python-jenkins-1.7.0.orig/tests/test_version.py    2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_version.py 2022-05-03 14:48:58.246141576 
+0200
+Index: python-jenkins-1.8.0/tests/test_version.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_version.py
++++ python-jenkins-1.8.0/tests/test_version.py
 @@ -1,4 +1,4 @@
 -from mock import patch
 +from unittest.mock import patch
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_view.py 
python-jenkins-1.7.0/tests/test_view.py
---- python-jenkins-1.7.0.orig/tests/test_view.py       2022-05-03 
14:48:58.238141526 +0200
-+++ python-jenkins-1.7.0/tests/test_view.py    2022-05-03 14:48:58.246141576 
+0200
+Index: python-jenkins-1.8.0/tests/test_view.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_view.py
++++ python-jenkins-1.8.0/tests/test_view.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch
@@ -331,9 +424,10 @@
  
  import jenkins
  from tests.base import JenkinsTestBase
-diff -upr python-jenkins-1.7.0.orig/tests/test_whoami.py 
python-jenkins-1.7.0/tests/test_whoami.py
---- python-jenkins-1.7.0.orig/tests/test_whoami.py     2022-05-03 
14:48:58.234141501 +0200
-+++ python-jenkins-1.7.0/tests/test_whoami.py  2022-05-03 14:48:58.242141551 
+0200
+Index: python-jenkins-1.8.0/tests/test_whoami.py
+===================================================================
+--- python-jenkins-1.8.0.orig/tests/test_whoami.py
++++ python-jenkins-1.8.0/tests/test_whoami.py
 @@ -1,5 +1,5 @@
  import json
 -from mock import patch

++++++ use-parts-of-legacy-version.patch ++++++
Index: python-jenkins-1.8.0/jenkins/plugins.py
===================================================================
--- python-jenkins-1.8.0.orig/jenkins/plugins.py
+++ python-jenkins-1.8.0/jenkins/plugins.py
@@ -41,8 +41,7 @@
 
 import operator
 import re
-
-import pkg_resources
+from typing import Iterator, Tuple
 
 
 class Plugin(dict):
@@ -67,6 +66,63 @@ class Plugin(dict):
         super(Plugin, self).__setitem__(key, value)
 
 
+# Portion of code from packaging module, dual licensed under the terms of
+# the Apache License, Version 2.0, and the BSD License.
+_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", 
re.VERBOSE)
+
+_legacy_version_replacement_map = {
+    "pre": "c",
+    "preview": "c",
+    "-": "final-",
+    "rc": "c",
+    "dev": "@",
+}
+
+
+def _parse_version_parts(s: str) -> Iterator[str]:
+    for part in _legacy_version_component_re.split(s):
+        part = _legacy_version_replacement_map.get(part, part)
+
+        if not part or part == ".":
+            continue
+
+        if part[:1] in "0123456789":
+            # pad for numeric comparison
+            yield part.zfill(8)
+        else:
+            yield "*" + part
+
+    # ensure that alpha/beta/candidate are before final
+    yield "*final"
+
+
+def _legacy_cmpkey(version: str) -> Tuple[int, Tuple[str, ...]]:
+
+    # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
+    # greater than or equal to 0. This will effectively put the LegacyVersion,
+    # which uses the defacto standard originally implemented by setuptools,
+    # as before all PEP 440 versions.
+    epoch = -1
+
+    # This scheme is taken from pkg_resources.parse_version setuptools prior to
+    # it's adoption of the packaging library.
+    parts: List[str] = []
+    for part in _parse_version_parts(version.lower()):
+        if part.startswith("*"):
+            # remove "-" before a prerelease tag
+            if part < "*final":
+                while parts and parts[-1] == "*final-":
+                    parts.pop()
+
+            # remove trailing zeros from each series of numeric parts
+            while parts and parts[-1] == "00000000":
+                parts.pop()
+
+        parts.append(part)
+
+    return epoch, tuple(parts)
+
+
 class PluginVersion(str):
     '''Class providing comparison capabilities for plugin versions.'''
 
@@ -76,15 +132,14 @@ class PluginVersion(str):
         '''Parse plugin version and store it for comparison.'''
 
         self._version = version
-        self.parsed_version = pkg_resources.parse_version(
-            self.__convert_version(version))
+        self.parsed_version = _legacy_cmpkey(self.__convert_version(version))
 
     def __convert_version(self, version):
         return self._VERSION_RE.sub(r'\g<1>.preview', str(version))
 
     def __compare(self, op, version):
-        return op(self.parsed_version, pkg_resources.parse_version(
-            self.__convert_version(version)))
+        return op(self.parsed_version,
+                  _legacy_cmpkey(self.__convert_version(version)))
 
     def __le__(self, version):
         return self.__compare(operator.le, version)
Index: python-jenkins-1.8.0/requirements.txt
===================================================================
--- python-jenkins-1.8.0.orig/requirements.txt
+++ python-jenkins-1.8.0/requirements.txt
@@ -1,5 +1,3 @@
-# Setuptools removed support for PEP 440 non-conforming versions
-setuptools<66
 six>=1.3.0
 pbr>=0.8.2
 multi_key_dict

Reply via email to