Hello community,

here is the log from the commit of package python-jenkinsapi for 
openSUSE:Factory checked in at 2019-05-22 11:13:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jenkinsapi (Old)
 and      /work/SRC/openSUSE:Factory/.python-jenkinsapi.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-jenkinsapi"

Wed May 22 11:13:56 2019 rev:8 rq:703793 version:0.3.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jenkinsapi/python-jenkinsapi.changes      
2019-02-06 14:07:07.846652413 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-jenkinsapi.new.5148/python-jenkinsapi.changes
    2019-05-22 11:13:56.798556836 +0200
@@ -1,0 +2,15 @@
+Fri May 17 20:23:07 UTC 2019 - Hardik Italia <hita...@suse.com>
+
+- update to 3.0.9:
+  * Updated password
+  * url encode folder name, to fix forward slashes (#702)
+  * Add new method to create job and use it to speedup QueueItem (#699)
+  * See if Jenkins is lazy when loading build history (#698)
+  * Removed python 3.4 and added 3.7 (#695)
+  * Proposed CloudBees integration fix to job.invoke. (#693)
+  * Fix pylint errors (#694)
+  * Add authentication system tests (#686)
+  * Use session id cookie to improve performace (#685)
+  * Parameterize war-filename and locally save hpi-files (#684)
+
+-------------------------------------------------------------------

Old:
----
  jenkinsapi-0.3.8.tar.gz

New:
----
  jenkinsapi-0.3.9.tar.gz

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

Other differences:
------------------
++++++ python-jenkinsapi.spec ++++++
--- /var/tmp/diff_new_pack.QCAkhS/_old  2019-05-22 11:13:57.246556753 +0200
+++ /var/tmp/diff_new_pack.QCAkhS/_new  2019-05-22 11:13:57.250556752 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-jenkinsapi
-Version:        0.3.8
+Version:        0.3.9
 Release:        0
 Summary:        A Python API for accessing resources on a Jenkins continuous 
integration server
 License:        MIT

++++++ jenkinsapi-0.3.8.tar.gz -> jenkinsapi-0.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/.travis.yml 
new/jenkinsapi-0.3.9/.travis.yml
--- old/jenkinsapi-0.3.8/.travis.yml    2018-11-26 16:08:36.000000000 +0100
+++ new/jenkinsapi-0.3.9/.travis.yml    2019-04-12 17:07:05.000000000 +0200
@@ -1,17 +1,17 @@
-dist: trusty
+dist: xenial
 group: edge
 sudo: required
 language: python
+jdk:
+- oraclejdk8
 python:
 - '2.7'
-- '3.4'
 - '3.5'
 - '3.6'
+- '3.7'
 env:
 - JENKINS_VERSION=stable
 - JENKINS_VERSION=latest
-before_install:
-- jdk_switcher use oraclejdk8
 install:
 - pip install tox-travis
 - python setup.py -q sdist bdist_wheel
@@ -26,10 +26,10 @@
     deploy:
       user: lechat
       password:
-        secure: 
Sx99ZHXkGAxWYn2mDz3U9RQg6Yjta22Tu/9ndXxKIAbyGaFn9jPmpYNB2oNu7/6djlfmNsN9cvGze3FghyToW7YHwRC7pSCVxVlqJb+fFOLbhxJeh2RgmUQRqlhWSs/xjGypNdMkNosuAv08UZr1HX1wgYF3rWnAZFDlDsQeayU=
+        secure: 
Dn0M+smML+SzgHSVz8w05mkwkg1Eojp7WKvq8NiWSmqH7BlvTNjBszaYCEqIAdXY5vO9p9yx9mupoeLxXJLJlLer61OwHErrXKzUofLfgMJT/mF9WlUfJZgonJcyl5By/MU9vXIlFMAZNae393GJYhj4zQx8xoZXk8HWMMqNXLA=
       on:
         repo: pycontribs/jenkinsapi
         tags: true
       provider: pypi
-      distributions: "sdist bdist_wheel"
+      distributions: sdist bdist_wheel
       skip_cleanup: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/AUTHORS new/jenkinsapi-0.3.9/AUTHORS
--- old/jenkinsapi-0.3.8/AUTHORS        2018-12-27 23:08:08.000000000 +0100
+++ new/jenkinsapi-0.3.9/AUTHORS        2019-04-13 02:46:41.000000000 +0200
@@ -34,6 +34,8 @@
 Frantisek Reznicek <frantisek.rezni...@centrum.cz>
 Giovanni Berlanda-Scorza 
<38668349+giovanni-superpedestr...@users.noreply.github.com>
 Hugh Brown <hbr...@amplify.com>
+Ikuze <37222566+ik...@users.noreply.github.com>
+JO2M <37215959+j...@users.noreply.github.com>
 Jake Ruth <jake2r...@gmail.com>
 James Whitworth <james.whitwo...@vicon.com>
 James Whitworth <fun4ji...@gmail.com>
@@ -122,6 +124,7 @@
 lechat <ctpek...@gmail.com>
 lphoward <larry.how...@vanderbilt.edu>
 luciali <luci...@twitter.com>
+mdear <md...@cisco.com>
 mthak <manoj.thak...@gmail.com>
 mthakkar <mthak...@cloudera.com>
 mvr <matthewvonrocketstein@gmail-dot-com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/ChangeLog 
new/jenkinsapi-0.3.9/ChangeLog
--- old/jenkinsapi-0.3.8/ChangeLog      2018-12-27 23:08:07.000000000 +0100
+++ new/jenkinsapi-0.3.9/ChangeLog      2019-04-13 02:46:41.000000000 +0200
@@ -1,6 +1,20 @@
 CHANGES
 =======
 
+0.3.9
+-----
+
+* Updated password
+* url encode folder name, to fix forward slashes (#702)
+* Add new method to create job and use it to speedup QueueItem (#699)
+* See if Jenkins is lazy when loading build history (#698)
+* Removed python 3.4 and added 3.7 (#695)
+* Proposed CloudBees integration fix to job.invoke. (#693)
+* Fix pylint errors (#694)
+* Add authentication system tests (#686)
+* Use session id cookie to improve performace (#685)
+* Parameterize war-filename and locally save hpi-files (#684)
+
 0.3.8
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/PKG-INFO 
new/jenkinsapi-0.3.9/PKG-INFO
--- old/jenkinsapi-0.3.8/PKG-INFO       2018-12-27 23:08:09.000000000 +0100
+++ new/jenkinsapi-0.3.9/PKG-INFO       2019-04-13 02:46:42.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: jenkinsapi
-Version: 0.3.8
+Version: 0.3.9
 Summary: A Python API for accessing resources on a Jenkins 
continuous-integration server.
 Home-page: UNKNOWN
 Author: Salim Fadhley, Aleksey Maksimov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/jenkins.py 
new/jenkinsapi-0.3.9/jenkinsapi/jenkins.py
--- old/jenkinsapi-0.3.8/jenkinsapi/jenkins.py  2018-11-26 14:23:11.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/jenkins.py  2019-04-12 15:45:38.000000000 
+0200
@@ -6,6 +6,7 @@
 import warnings
 import six.moves.urllib.parse as urlparse
 
+from six.moves.urllib.request import Request, HTTPRedirectHandler, build_opener
 from six.moves.urllib.parse import quote as urlquote
 from six.moves.urllib.parse import urlencode
 from requests import HTTPError, ConnectionError
@@ -15,6 +16,7 @@
 from jenkinsapi.credentials import CredentialsById
 from jenkinsapi.executors import Executors
 from jenkinsapi.jobs import Jobs
+from jenkinsapi.job import Job
 from jenkinsapi.view import View
 from jenkinsapi.label import Label
 from jenkinsapi.nodes import Nodes
@@ -141,6 +143,15 @@
         """
         return self.jobs[jobname]
 
+    def get_job_by_url(self, url, job_name):
+        """
+        Get a job by url
+        :param url: jobs' url
+        :param jobname: name of the job, str
+        :return: Job obj
+        """
+        return Job(url, job_name, self)
+
     def has_job(self, jobname):
         """
         Does a job by the name specified exist
@@ -543,3 +554,43 @@
             raise JenkinsAPIException('Unexpected response %d.' % 
response.status_code)
 
         return response.text
+
+    def use_auth_cookie(self):
+        assert (self.username and
+                self.baseurl), 'Please provide jenkins url, username '\
+                               'and password to get the session ID cookie.'
+
+        login_url = 'j_acegi_security_check'
+        jenkins_url = '{0}/{1}'.format(self.baseurl, login_url)
+        data = urlencode({'j_username': self.username,
+                          'j_password': self.password}).encode("utf-8")
+
+        class SmartRedirectHandler(HTTPRedirectHandler):
+
+            def extract_cookie(self, setcookie):
+                # Extracts the last cookie.
+                # Example of set-cookie value for python2
+                # ('set-cookie', 'JSESSIONID.30blah=blahblahblah;Path=/;
+                #   HttpOnly, JSESSIONID.30ablah=blahblah;Path=/;HttpOnly'),
+                return setcookie.split(',')[-1].split(';')[0].strip('\n\r ')
+
+            def http_error_302(self, req, fp, code, msg, headers):
+                # Jenkins can send several Set-Cookie values sometimes
+                #  The valid one is the last one
+                for header, value in headers.items():
+                    if header.lower() == 'set-cookie':
+                        cookie = self.extract_cookie(value)
+
+                req.headers['Cookie'] = cookie
+                result = HTTPRedirectHandler.http_error_302(self, req, fp,
+                                                            code, msg,
+                                                            headers)
+                result.orig_status = code
+                result.orig_headers = headers
+                result.cookie = cookie
+                return result
+
+        request = Request(jenkins_url, data)
+        opener = build_opener(SmartRedirectHandler())
+        res = opener.open(request)
+        Requester.AUTH_COOKIE = res.cookie
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/jenkinsbase.py 
new/jenkinsapi-0.3.9/jenkinsapi/jenkinsbase.py
--- old/jenkinsapi-0.3.8/jenkinsapi/jenkinsbase.py      2018-11-13 
01:11:17.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/jenkinsbase.py      2019-04-12 
16:44:27.000000000 +0200
@@ -5,6 +5,7 @@
 import ast
 import pprint
 import logging
+from six.moves.urllib.parse import quote as urlquote
 from jenkinsapi import config
 from jenkinsapi.custom_exceptions import JenkinsAPIException
 
@@ -100,7 +101,7 @@
         return jobs
 
     def process_job_folder(self, folder, folder_path):
-        folder_path += '/job/%s' % folder['name']
+        folder_path += '/job/%s' % urlquote(folder['name'])
         data = self.get_data(self.python_api_url(folder_path),
                              tree='jobs[name,color]')
         result = []
@@ -109,7 +110,7 @@
             if 'color' not in job.keys():
                 result += self.process_job_folder(job, folder_path)
             else:
-                job['url'] = '%s/job/%s' % (folder_path, job['name'])
+                job['url'] = '%s/job/%s' % (folder_path, urlquote(job['name']))
                 result.append(job)
 
         return result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/job.py 
new/jenkinsapi-0.3.9/jenkinsapi/job.py
--- old/jenkinsapi-0.3.8/jenkinsapi/job.py      2018-11-13 01:11:17.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/job.py      2019-04-12 15:45:38.000000000 
+0200
@@ -90,7 +90,7 @@
 
     def poll(self, tree=None):
         data = super(Job, self).poll(tree=tree)
-        if not tree:
+        if not tree and not self.jenkins.lazy:
             self._data = self._add_missing_builds(self._data)
 
         return data
@@ -211,7 +211,26 @@
 
         redirect_url = response.headers['location']
 
-        if not redirect_url.startswith("%s/queue/item" % self.jenkins.baseurl):
+        #
+        # Enterprise Jenkins implementations such as CloudBees locate their
+        # queue REST API base https://server.domain.com/jenkins/queue/api/
+        # above the team-specific REST API base
+        # https://server.domain.com/jenkins/job/my_team/api/
+        #
+        queue_baseurl_candidates = [self.jenkins.baseurl]
+        scheme, netloc, path, _, query, frag = \
+            urlparse.urlparse(self.jenkins.baseurl)
+        while path:
+            path = '/'.join(path.rstrip('/').split('/')[:-1])
+            queue_baseurl_candidates.append(
+                urlparse.urlunsplit([scheme, netloc, path, query, frag]))
+        redirect_url_valid = False
+        for queue_baseurl_candidate in queue_baseurl_candidates:
+            redirect_url_valid = redirect_url.startswith(
+                "%s/queue/item" % queue_baseurl_candidate)
+            if redirect_url_valid:
+                break
+        if not redirect_url_valid:
             raise ValueError("Not a Queue URL: %s" % redirect_url)
 
         qi = QueueItem(redirect_url, self.jenkins)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/node.py 
new/jenkinsapi-0.3.9/jenkinsapi/node.py
--- old/jenkinsapi-0.3.8/jenkinsapi/node.py     2018-11-13 01:11:17.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/node.py     2019-04-12 15:45:38.000000000 
+0200
@@ -220,7 +220,8 @@
                                  "temporarilyOffline = %s" %
                                  (self._data['offline'],
                                   self._data['temporarilyOffline']))
-        elif self._data['offline'] and self._data['temporarilyOffline']:
+
+        if self._data['offline'] and self._data['temporarilyOffline']:
             self.toggle_temporarily_offline()
             if self._data['offline']:
                 raise AssertionError("The node state is still offline, "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/nodes.py 
new/jenkinsapi-0.3.9/jenkinsapi/nodes.py
--- old/jenkinsapi-0.3.8/jenkinsapi/nodes.py    2018-11-13 01:11:17.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/nodes.py    2019-04-12 15:45:38.000000000 
+0200
@@ -123,8 +123,8 @@
         else:
             if item != 'master':
                 raise UnknownNode('Node %s does not exist' % item)
-            else:
-                log.info('Requests to remove master node ignored')
+
+            log.info('Requests to remove master node ignored')
 
     def __setitem__(self, name, node_dict):
         if not isinstance(node_dict, dict):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/plugin.py 
new/jenkinsapi-0.3.9/jenkinsapi/plugin.py
--- old/jenkinsapi-0.3.8/jenkinsapi/plugin.py   2017-12-14 14:59:25.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/plugin.py   2019-04-12 15:45:38.000000000 
+0200
@@ -22,9 +22,9 @@
                          '"plugin-name@version", not "{0}"')
             usage_err = usage_err.format(plugin_string)
             raise ValueError(usage_err)
-        else:
-            shortName, version = plugin_string.split('@')
-            return {'shortName': shortName, 'version': version}
+
+        shortName, version = plugin_string.split('@')
+        return {'shortName': shortName, 'version': version}
 
     def __eq__(self, other):
         return self.__dict__ == other.__dict__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/plugins.py 
new/jenkinsapi-0.3.9/jenkinsapi/plugins.py
--- old/jenkinsapi-0.3.8/jenkinsapi/plugins.py  2018-11-26 14:23:11.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/plugins.py  2019-04-12 15:45:38.000000000 
+0200
@@ -275,13 +275,14 @@
             if plugin.shortName in self:
                 return True  # for Jenkins 1.X
             time.sleep(interval)
+
         if self.jenkins_obj.version.startswith('2'):
             raise JenkinsAPIException(
                 "Problem installing plugin '%s'." % plugin.shortName)
-        else:
-            log.warning("Plugin '%s' not found in loaded plugins."
-                        "You may need to restart Jenkins.", plugin.shortName)
-            return False
+
+        log.warning("Plugin '%s' not found in loaded plugins."
+                    "You may need to restart Jenkins.", plugin.shortName)
+        return False
 
     def __contains__(self, plugin_name):
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/queue.py 
new/jenkinsapi-0.3.9/jenkinsapi/queue.py
--- old/jenkinsapi-0.3.8/jenkinsapi/queue.py    2018-11-13 01:11:17.000000000 
+0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/queue.py    2019-04-12 15:45:38.000000000 
+0200
@@ -1,11 +1,11 @@
 """
 Queue module for jenkinsapi
 """
+import logging
+import time
 from requests import HTTPError
 from jenkinsapi.jenkinsbase import JenkinsBase
 from jenkinsapi.custom_exceptions import UnknownQueueItem, NotBuiltYet
-import logging
-import time
 
 log = logging.getLogger(__name__)
 
@@ -110,7 +110,10 @@
         """
         Return the job associated with this queue item
         """
-        return self.jenkins[self._data['task']['name']]
+        return self.jenkins.get_job_by_url(
+            self._data['task']['url'],
+            self._data['task']['name'],
+        )
 
     def get_parameters(self):
         """returns parameters of queue item"""
@@ -131,8 +134,8 @@
 
     def get_build(self):
         build_number = self.get_build_number()
-        job_name = self.get_job_name()
-        return self.jenkins[job_name][build_number]
+        job = self.get_job()
+        return job[build_number]
 
     def block_until_complete(self, delay=5):
         build = self.block_until_building(delay)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi/utils/requester.py 
new/jenkinsapi-0.3.9/jenkinsapi/utils/requester.py
--- old/jenkinsapi-0.3.8/jenkinsapi/utils/requester.py  2018-12-27 
23:00:41.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi/utils/requester.py  2019-04-12 
15:45:38.000000000 +0200
@@ -37,6 +37,7 @@
     """
 
     VALID_STATUS_CODES = [200, ]
+    AUTH_COOKIE = None
 
     def __init__(self, *args, **kwargs):
 
@@ -94,6 +95,11 @@
                 'headers must be a dict, got %s' % repr(headers)
             requestKwargs['headers'] = headers
 
+        if self.AUTH_COOKIE:
+            currentheaders = requestKwargs.get('headers', {})
+            currentheaders.update({'Cookie': self.AUTH_COOKIE})
+            requestKwargs['headers'] = currentheaders
+
         requestKwargs['verify'] = self.ssl_verify
         requestKwargs['cert'] = self.cert
 
@@ -186,12 +192,12 @@
         if response.status_code not in valid:
             if response.status_code == 405:         # POST required
                 raise PostRequired('POST required for url {0}'.format(url))
-            else:
-                raise JenkinsAPIException(
-                    'Operation failed. url={0}, headers={1}, status={2}, '
-                    'text={3}'.format(
-                        response.url, headers, response.status_code,
-                        response.text.encode('UTF-8')
-                    )
+
+            raise JenkinsAPIException(
+                'Operation failed. url={0}, headers={1}, status={2}, '
+                'text={3}'.format(
+                    response.url, headers, response.status_code,
+                    response.text.encode('UTF-8')
                 )
+            )
         return response
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi.egg-info/PKG-INFO 
new/jenkinsapi-0.3.9/jenkinsapi.egg-info/PKG-INFO
--- old/jenkinsapi-0.3.8/jenkinsapi.egg-info/PKG-INFO   2018-12-27 
23:08:08.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi.egg-info/PKG-INFO   2019-04-13 
02:46:41.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: jenkinsapi
-Version: 0.3.8
+Version: 0.3.9
 Summary: A Python API for accessing resources on a Jenkins 
continuous-integration server.
 Home-page: UNKNOWN
 Author: Salim Fadhley, Aleksey Maksimov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi.egg-info/SOURCES.txt 
new/jenkinsapi-0.3.9/jenkinsapi.egg-info/SOURCES.txt
--- old/jenkinsapi-0.3.8/jenkinsapi.egg-info/SOURCES.txt        2018-12-27 
23:08:08.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi.egg-info/SOURCES.txt        2019-04-13 
02:46:41.000000000 +0200
@@ -104,6 +104,7 @@
 jenkinsapi_tests/systests/get-jenkins-war.sh
 jenkinsapi_tests/systests/jenkins_home.tar.gz
 jenkinsapi_tests/systests/job_configs.py
+jenkinsapi_tests/systests/test_authentication.py
 jenkinsapi_tests/systests/test_credentials.py
 jenkinsapi_tests/systests/test_crumbs_requester.py
 jenkinsapi_tests/systests/test_downstream_upstream.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/jenkinsapi.egg-info/pbr.json 
new/jenkinsapi-0.3.9/jenkinsapi.egg-info/pbr.json
--- old/jenkinsapi-0.3.8/jenkinsapi.egg-info/pbr.json   2018-12-27 
23:08:08.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi.egg-info/pbr.json   2019-04-13 
02:46:41.000000000 +0200
@@ -1 +1 @@
-{"git_version": "3c18310", "is_release": true}
\ No newline at end of file
+{"git_version": "b4d62f1", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/conftest.py 
new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/conftest.py
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/conftest.py  2018-11-25 
03:54:32.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/conftest.py  2019-04-12 
15:45:38.000000000 +0200
@@ -7,6 +7,10 @@
 log = logging.getLogger(__name__)
 state = {}
 
+# User/password for authentication testcases
+ADMIN_USER = 'admin'
+ADMIN_PASSWORD = 'admin'
+
 # Extra plugins required by the systests
 PLUGIN_DEPENDENCIES = [
     "http://updates.jenkins-ci.org/latest/";
@@ -54,12 +58,56 @@
         del jenkins.credentials[name]
 
 
+def _create_admin_user(launched_jenkins):
+    # Groovy script that creates a user "admin/admin" in jenkins
+    # and enable security. "admin" user will be the only user and
+    # have admin permissions. Anonymous cannot read anything.
+    create_admin_groovy = """
+import jenkins.model.*
+import hudson.security.*
+
+def instance = Jenkins.getInstance()
+
+def hudsonRealm = new HudsonPrivateSecurityRealm(false)
+hudsonRealm.createAccount('{0}','{1}')
+instance.setSecurityRealm(hudsonRealm)
+
+def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
+strategy.setAllowAnonymousRead(false)
+instance.setAuthorizationStrategy(strategy)
+    """.format(ADMIN_USER, ADMIN_PASSWORD)
+
+    url = launched_jenkins.jenkins_url
+    jenkins_instance = Jenkins(url)
+    jenkins_instance.run_groovy_script(create_admin_groovy)
+
+
+def _disable_security(launched_jenkins):
+    # Groovy script that disables security in jenkins,
+    # reverting the changes made in "_create_admin_user" function.
+    disable_security_groovy = """
+import jenkins.model.*
+import hudson.security.*
+
+def instance = Jenkins.getInstance()
+instance.disableSecurity()
+instance.save()
+    """
+
+    url = launched_jenkins.jenkins_url
+    jenkins_instance = Jenkins(url, ADMIN_USER, ADMIN_PASSWORD)
+    jenkins_instance.run_groovy_script(disable_security_groovy)
+
+
 @pytest.fixture(scope='session')
 def launched_jenkins():
     systests_dir, _ = os.path.split(__file__)
-    war_path = os.path.join(systests_dir, 'jenkins.war')
+    local_orig_dir = os.path.join(systests_dir, 'localinstance_files')
+    if not os.path.exists(local_orig_dir):
+        os.mkdir(local_orig_dir)
+    war_name = 'jenkins.war'
     launcher = JenkinsLancher(
-        war_path, PLUGIN_DEPENDENCIES,
+        local_orig_dir, systests_dir, war_name, PLUGIN_DEPENDENCIES,
         jenkins_url=os.getenv('JENKINS_URL', None)
     )
     launcher.start()
@@ -81,3 +129,31 @@
     _delete_all_credentials(jenkins_instance)
 
     return jenkins_instance
+
+
+@pytest.fixture(scope='function')
+def lazy_jenkins(launched_jenkins):
+    url = launched_jenkins.jenkins_url
+
+    jenkins_instance = Jenkins(url, lazy=True)
+
+    _delete_all_jobs(jenkins_instance)
+    _delete_all_views(jenkins_instance)
+    _delete_all_credentials(jenkins_instance)
+
+    return jenkins_instance
+
+
+@pytest.fixture(scope='function')
+def jenkins_admin_admin(launched_jenkins, jenkins):  # pylint: 
disable=unused-argument
+    # Using "jenkins" fixture makes sure that jobs/views/credentials are
+    # cleaned before security is enabled.
+    url = launched_jenkins.jenkins_url
+
+    _create_admin_user(launched_jenkins)
+    jenkins_admin_instance = Jenkins(url, ADMIN_USER, ADMIN_PASSWORD)
+
+    yield jenkins_admin_instance
+
+    jenkins_admin_instance.requester.__class__.AUTH_COOKIE = None
+    _disable_security(launched_jenkins)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/get-jenkins-war.sh 
new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/get-jenkins-war.sh
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/get-jenkins-war.sh   
2017-12-14 14:59:25.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/get-jenkins-war.sh   
2019-04-12 15:45:38.000000000 +0200
@@ -1,16 +1,17 @@
 #!/bin/bash
 #JENKINS_WAR_URL="http://mirrors.jenkins-ci.org/war/latest/jenkins.war";
 
-if [[ "$#" -ne 2 ]]; then
-    echo "Usage: $0 jenkins_url path_to_store_jenkins"
+if [[ "$#" -ne 3 ]]; then
+    echo "Usage: $0 jenkins_url path_to_store_jenkins war_filename"
     exit 1
 fi
 
 readonly JENKINS_WAR_URL=$1
 readonly JENKINS_PATH=$2
+readonly WAR_FILENAME=$3
 
-if   [[ $(type -t wget) ]]; then wget -O ${JENKINS_PATH}/jenkins.war 
$JENKINS_WAR_URL
-elif [[ $(type -t curl) ]]; then curl -sSL -o ${JENKINS_PATH}/jenkins.war 
$JENKINS_WAR_URL
+if   [[ $(type -t wget) ]]; then wget -O ${JENKINS_PATH}/${WAR_FILENAME} 
$JENKINS_WAR_URL
+elif [[ $(type -t curl) ]]; then curl -sSL -o ${JENKINS_PATH}/${WAR_FILENAME} 
$JENKINS_WAR_URL
 else
     echo "Could not find wget or curl"
     exit 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/test_authentication.py 
new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_authentication.py
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/systests/test_authentication.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_authentication.py       
2019-04-12 15:45:38.000000000 +0200
@@ -0,0 +1,80 @@
+'''
+System tests for authentication functionality
+'''
+
+import pytest
+from jenkinsapi.utils.requester import Requester
+from six.moves.urllib.error import HTTPError
+from requests import HTTPError as REQHTTPError
+from jenkinsapi.jenkins import Jenkins
+
+
+def test_normal_uthentication(jenkins_admin_admin):
+    # No problem with the righ user/pass
+    jenkins_user = Jenkins(jenkins_admin_admin.baseurl,
+                           jenkins_admin_admin.username,
+                           jenkins_admin_admin.password)
+
+    assert jenkins_user is not None
+
+    # We cannot connect if no user/pass
+    with pytest.raises(REQHTTPError) as http_excep:
+        Jenkins(jenkins_admin_admin.baseurl)
+
+    assert Requester.AUTH_COOKIE is None
+    assert http_excep.value.response.status_code == 403
+
+
+def test_auth_cookie(jenkins_admin_admin):
+    initial_cookie_value = None
+    final_cookie_value = "JSESSIONID"
+    assert initial_cookie_value == Requester.AUTH_COOKIE
+
+    jenkins_admin_admin.use_auth_cookie()
+    result = Requester.AUTH_COOKIE
+    assert result is not None
+    assert final_cookie_value in result
+
+
+def test_wrongauth_cookie(jenkins_admin_admin):
+    initial_cookie_value = None
+    assert initial_cookie_value == Requester.AUTH_COOKIE
+
+    jenkins_admin_admin.username = "fakeuser"
+    jenkins_admin_admin.password = "fakepass"
+
+    with pytest.raises(HTTPError) as http_excep:
+        jenkins_admin_admin.use_auth_cookie()
+
+    assert Requester.AUTH_COOKIE is None
+    assert http_excep.value.code == 401
+
+
+def test_verify_cookie_isworking(jenkins_admin_admin):
+    initial_cookie_value = None
+    final_cookie_value = "JSESSIONID"
+    assert initial_cookie_value == Requester.AUTH_COOKIE
+
+    # Remove requester user/pass
+    jenkins_admin_admin.requester.username = None
+    jenkins_admin_admin.requester.password = None
+
+    # Verify that we cannot connect
+    with pytest.raises(REQHTTPError) as http_excep:
+        jenkins_admin_admin.poll()
+
+    assert Requester.AUTH_COOKIE is None
+    assert http_excep.value.response.status_code == 403
+
+    # Retrieve the auth cookie, we can because we
+    # have right values for jenkins_admin_admin.username
+    # and jenkins_admin_admin.password
+    jenkins_admin_admin.use_auth_cookie()
+
+    result = Requester.AUTH_COOKIE
+    assert result is not None
+    assert final_cookie_value in result
+
+    # Verify that we can connect even with no requester user/pass
+    # If we have the cookie the requester user/pass is not needed
+    jenkins_admin_admin.poll()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_jenkins.py 
new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_jenkins.py
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_jenkins.py     
2017-12-14 14:59:25.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_jenkins.py     
2019-04-12 15:45:38.000000000 +0200
@@ -1,5 +1,6 @@
 import pytest
 
+import jenkinsapi
 from jenkinsapi.plugins import Plugins
 from jenkinsapi.utils.requester import Requester
 from jenkinsapi.jenkins import Jenkins
@@ -266,3 +267,28 @@
     jenkins = Jenkins('http://localhost:8080/',
                       username='foouser', password='foopassword')
     assert jenkins.has_plugin('subversion') is True
+
+
+def test_get_use_auth_cookie(mocker, monkeypatch):
+    COOKIE_VALUE = 'FAKE_COOKIE'
+
+    def fake_opener(redirect_handler):  # pylint: disable=unused-argument
+        mock_response = mocker.MagicMock()
+        mock_response.cookie = COOKIE_VALUE
+
+        mock_opener = mocker.MagicMock()
+        mock_opener.open.return_value = mock_response
+        return mock_opener
+
+    def fake_poll(cls, tree=None):  # pylint: disable=unused-argument
+        return {}
+
+    monkeypatch.setattr(Jenkins, '_poll', fake_poll)
+    monkeypatch.setattr(Requester, 'AUTH_COOKIE', None)
+    monkeypatch.setattr(jenkinsapi.jenkins, 'build_opener', fake_opener)
+
+    jenkins = Jenkins('http://localhost:8080',
+                      username='foouser', password='foopassword')
+
+    jenkins.use_auth_cookie()
+    assert Requester.AUTH_COOKIE == COOKIE_VALUE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_job_get_all_builds.py 
new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_job_get_all_builds.py
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_job_get_all_builds.py  
2018-11-13 01:11:17.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_job_get_all_builds.py  
2019-04-12 15:45:38.000000000 +0200
@@ -195,10 +195,22 @@
         # remaining jobs will be fetched automatically, and to have two calls
         # to the Jenkins API
         TestJobGetAllBuilds.__get_data_call_count = 0
+        self.J.lazy = False
         self.j = Job('http://halob:8080/job/foo/', 'foo', self.J)
         self.assertEqual(TestJobGetAllBuilds.__get_data_call_count, 2)
 
     @mock.patch.object(JenkinsBase, 'get_data', fakeGetDataTree)
+    def test_lazy_builds_list_will_not_call_jenkins_twice(self):
+        # The job data contains only one build, so we expect that the
+        # remaining jobs will be fetched automatically, and to have two calls
+        # to the Jenkins API
+        TestJobGetAllBuilds.__get_data_call_count = 0
+        self.J.lazy = True
+        self.j = Job('http://halob:8080/job/foo/', 'foo', self.J)
+        self.assertEqual(TestJobGetAllBuilds.__get_data_call_count, 1)
+        self.J.lazy = False
+
+    @mock.patch.object(JenkinsBase, 'get_data', fakeGetDataTree)
     def test_complete_builds_list_will_call_jenkins_once(self):
         # The job data contains all builds, so we will not gather remaining
         # builds
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_requester.py 
new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_requester.py
--- old/jenkinsapi-0.3.8/jenkinsapi_tests/unittests/test_requester.py   
2018-12-27 23:00:41.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_requester.py   
2019-04-12 15:45:38.000000000 +0200
@@ -3,6 +3,7 @@
 import requests
 from jenkinsapi.jenkins import Requester
 from jenkinsapi.custom_exceptions import JenkinsAPIException
+from mock import patch
 
 
 def test_no_parameters_uses_default_values():
@@ -127,6 +128,50 @@
     assert req_return['auth'] == ('foo', 'bar')
 
 
+@patch('jenkinsapi.jenkins.Requester.AUTH_COOKIE', 'FAKE')
+def test_get_request_dict_cookie():
+    req = Requester('foo', 'bar')
+
+    req_return = req.get_request_dict(
+        params={},
+        data=None,
+        headers=None
+    )
+    assert isinstance(req_return, dict)
+    assert req_return.get('headers')
+    assert req_return.get('headers').get('Cookie')
+    assert req_return.get('headers').get('Cookie') == 'FAKE'
+
+
+@patch('jenkinsapi.jenkins.Requester.AUTH_COOKIE', 'FAKE')
+def test_get_request_dict_updatecookie():
+    req = Requester('foo', 'bar')
+
+    req_return = req.get_request_dict(
+        params={},
+        data=None,
+        headers={'key': 'value'}
+    )
+    assert isinstance(req_return, dict)
+    assert req_return.get('headers')
+    assert req_return.get('headers').get('key')
+    assert req_return.get('headers').get('key') == 'value'
+    assert req_return.get('headers').get('Cookie')
+    assert req_return.get('headers').get('Cookie') == 'FAKE'
+
+
+def test_get_request_dict_nocookie():
+    req = Requester('foo', 'bar')
+
+    req_return = req.get_request_dict(
+        params={},
+        data=None,
+        headers=None
+    )
+    assert isinstance(req_return, dict)
+    assert not req_return.get('headers')
+
+
 def test_get_request_dict_wrong_params():
     req = Requester('foo', 'bar')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/jenkinsapi-0.3.8/jenkinsapi_utils/jenkins_launcher.py 
new/jenkinsapi-0.3.9/jenkinsapi_utils/jenkins_launcher.py
--- old/jenkinsapi-0.3.8/jenkinsapi_utils/jenkins_launcher.py   2018-11-13 
01:11:17.000000000 +0100
+++ new/jenkinsapi-0.3.9/jenkinsapi_utils/jenkins_launcher.py   2019-04-12 
15:45:38.000000000 +0200
@@ -64,9 +64,15 @@
     """
     Launch jenkins
     """
-    JENKINS_WAR_URL = "http://mirrors.jenkins-ci.org/war/latest/jenkins.war";
+    JENKINS_WEEKLY_WAR_URL = (
+        "http://mirrors.jenkins-ci.org/war/latest/jenkins.war";
+    )
+    JENKINS_LTS_WAR_URL = (
+        "http://mirrors.jenkins-ci.org/war-stable/latest/jenkins.war";
+    )
 
-    def __init__(self, war_path, plugin_urls=None, jenkins_url=None):
+    def __init__(self, local_orig_dir, systests_dir, war_name, 
plugin_urls=None,
+                 jenkins_url=None):
         if jenkins_url is not None:
             self.jenkins_url = jenkins_url
             self.http_port = urlparse(jenkins_url).port
@@ -83,8 +89,10 @@
             self.start_new_instance = True
 
         self.threads = []
-        self.war_path = war_path
-        self.war_directory, self.war_filename = os.path.split(self.war_path)
+        self.war_path = os.path.join(local_orig_dir, war_name)
+        self.local_orig_dir = local_orig_dir
+        self.systests_dir = systests_dir
+        self.war_filename = war_name
 
         if 'JENKINS_HOME' not in os.environ:
             self.jenkins_home = tempfile.mkdtemp(prefix='jenkins-home-')
@@ -96,20 +104,22 @@
         self.queue = queue.Queue()
         self.plugin_urls = plugin_urls or []
         if os.environ.get('JENKINS_VERSION', 'stable') == 'stable':
-            self.JENKINS_WAR_URL = (
-                'http://mirrors.jenkins-ci.org/war-stable/latest/jenkins.war'
-            )
+            self.JENKINS_WAR_URL = self.JENKINS_LTS_WAR_URL
+        else:
+            self.JENKINS_WAR_URL = self.JENKINS_WEEKLY_WAR_URL
 
     def update_war(self):
-        os.chdir(self.war_directory)
+        os.chdir(self.systests_dir)
         if os.path.exists(self.war_path):
-            log.info("We already have the War file...")
+            log.info("War file already present, delete it to redownload and"
+                     " update jenkins")
         else:
-            log.info("Redownloading Jenkins")
-            script_dir = os.path.join(self.war_directory,
+            log.info("Downloading Jenkins War")
+            script_dir = os.path.join(self.systests_dir,
                                       'get-jenkins-war.sh')
             subprocess.check_call([script_dir,
-                                   self.JENKINS_WAR_URL, self.war_directory])
+                                   self.JENKINS_WAR_URL, self.local_orig_dir,
+                                   self.war_filename])
 
     def update_config(self):
         tarball = TarFile.open(fileobj=resource_stream(
@@ -117,27 +127,37 @@
         tarball.extractall(path=self.jenkins_home)
 
     def install_plugins(self):
-        plugin_dir = os.path.join(self.jenkins_home, 'plugins')
-        log.info("Plugins will be installed in '%s'", plugin_dir)
+        plugin_dest_dir = os.path.join(self.jenkins_home, 'plugins')
+        log.info("Plugins will be installed in '%s'", plugin_dest_dir)
 
-        if not os.path.exists(plugin_dir):
-            os.mkdir(plugin_dir)
+        if not os.path.exists(plugin_dest_dir):
+            os.mkdir(plugin_dest_dir)
 
         for url in self.plugin_urls:
-            self.install_plugin(url, plugin_dir)
+            self.install_plugin(url, plugin_dest_dir)
 
-    def install_plugin(self, hpi_url, plugin_dir):
-        log.info("Downloading %s", hpi_url)
+    def install_plugin(self, hpi_url, plugin_dest_dir):
         path = urlparse(hpi_url).path
         filename = posixpath.basename(path)
-        plugin_path = os.path.join(plugin_dir, filename)
-        with open(plugin_path, 'wb') as hpi:
-            request = requests.get(hpi_url)
-            hpi.write(request.content)
+        plugin_orig_dir = os.path.join(self.local_orig_dir, 'plugins')
+        if not os.path.exists(plugin_orig_dir):
+            os.mkdir(plugin_orig_dir)
+        plugin_orig_path = os.path.join(plugin_orig_dir, filename)
+        plugin_dest_path = os.path.join(plugin_dest_dir, filename)
+        if os.path.exists(plugin_orig_path):
+            log.info("%s already locally present, delete the file to 
redownload"
+                     " and update", filename)
+        else:
+            log.info("Downloading %s from %s", filename, hpi_url)
+            with open(plugin_orig_path, 'wb') as hpi:
+                request = requests.get(hpi_url)
+                hpi.write(request.content)
+        log.info("Installing %s", filename)
+        shutil.copy(plugin_orig_path, plugin_dest_path)
         # Create an empty .pinned file, so that the downloaded plugin
         # will be used, instead of the version bundled in jenkins.war
         # See https://wiki.jenkins-ci.org/display/JENKINS/Pinned+Plugins
-        open(plugin_path + ".pinned", 'a').close()
+        open(plugin_dest_path + ".pinned", 'a').close()
 
     def stop(self):
         if self.start_new_instance:
@@ -176,7 +196,7 @@
             self.update_config()
             self.install_plugins()
 
-            os.chdir(self.war_directory)
+            os.chdir(self.local_orig_dir)
 
             jenkins_command = ['java',
                                '-Djenkins.install.runSetupWizard=false',
@@ -236,7 +256,8 @@
 
     jl = JenkinsLancher(
         '/home/sal/workspace/jenkinsapi/src/'
-        'jenkinsapi_tests/systests/jenkins.war'
+        'jenkinsapi_tests/systests/',
+        'jenkins.war'
     )
     jl.start()
     log.info("Jenkins was launched...")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jenkinsapi-0.3.8/tox.ini new/jenkinsapi-0.3.9/tox.ini
--- old/jenkinsapi-0.3.8/tox.ini        2018-11-13 01:11:17.000000000 +0100
+++ new/jenkinsapi-0.3.9/tox.ini        2019-04-12 15:45:38.000000000 +0200
@@ -12,7 +12,7 @@
 #     $ tox         # lint/tests for both
 #
 [tox]
-envlist = py27,py34,py35,py36
+envlist = py27,py35,py36,py37
 
 [testenv]
 deps=-rtest-requirements.txt


Reply via email to