commit python-jenkinsapi for openSUSE:Factory
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 <hitalia@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.reznicek@centrum.cz> Giovanni Berlanda-Scorza <38668349+giovanni-superpedestrian@users.noreply.github.com> Hugh Brown <hbrown@amplify.com> +Ikuze <37222566+Ikuze@users.noreply.github.com> +JO2M <37215959+J02M@users.noreply.github.com> Jake Ruth <jake2ruth@gmail.com> James Whitworth <James.Whitworth@vicon.com> James Whitworth <fun4jimmy@gmail.com> @@ -122,6 +124,7 @@ lechat <ctpeko3a@gmail.com> lphoward <larry.howard@vanderbilt.edu> luciali <luciali@twitter.com> +mdear <mdear@cisco.com> mthak <manoj.thakkar@gmail.com> mthakkar <mthakkar@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
participants (1)
-
root