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 <[email protected]>
+
+- 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 <[email protected]>
Giovanni Berlanda-Scorza
<[email protected]>
Hugh Brown <[email protected]>
+Ikuze <[email protected]>
+JO2M <[email protected]>
Jake Ruth <[email protected]>
James Whitworth <[email protected]>
James Whitworth <[email protected]>
@@ -122,6 +124,7 @@
lechat <[email protected]>
lphoward <[email protected]>
luciali <[email protected]>
+mdear <[email protected]>
mthak <[email protected]>
mthakkar <[email protected]>
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
+
+
[email protected](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
+
+
[email protected](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