Hello community,
here is the log from the commit of package python-jenkinsapi for
openSUSE:Factory checked in at 2020-04-16 23:07:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jenkinsapi (Old)
and /work/SRC/openSUSE:Factory/.python-jenkinsapi.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jenkinsapi"
Thu Apr 16 23:07:04 2020 rev:9 rq:794645 version:0.3.11
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jenkinsapi/python-jenkinsapi.changes
2019-05-22 11:13:56.798556836 +0200
+++
/work/SRC/openSUSE:Factory/.python-jenkinsapi.new.2738/python-jenkinsapi.changes
2020-04-16 23:07:06.515880708 +0200
@@ -1,0 +2,30 @@
+Thu Apr 16 12:13:33 UTC 2020 - [email protected]
+
+- version update to 0.3.11
+ 0.3.11
+ ------
+ * jobs.py: don't yield jobs twice (#740)
+ * Add debug log message in JenkinsBase.process\_job\_folder to follow
execution progress (#738)
+ * don't faile when node\_descriprion is missing (#737)
+ * Fix safe exit test (#736)
+ * don't stale feature requests or "help wanted"
+ * change label for stale issues
+ * Fixed idle state not being refreshed (#575)
+ * Simple plugins (#735)
+ 0.3.10
+ ------
+ * Add method for streaming build logs (#722)
+ * add instructions for Stale bot
+ * Fixed problems with changeSets (#717)
+ * Create Node by providing predetermined configuration (#730)
+ * Fix plugin versions (#734)
+ * Updates Requester to use a Session, maintaining cookies (#727)
+ * Feature/multibranch pipeline job (#715)
+ * Fix failures caused by plugins (#718)
+ * Fix for build.get\_artifacts() (#712)
+ * Add safe exit (#700)
+ * simplify crumb usage (#704)
+ * generate new api token for logged in user (#706)
+ * ignore dot files (#705)
+
+-------------------------------------------------------------------
Old:
----
jenkinsapi-0.3.9.tar.gz
New:
----
jenkinsapi-0.3.11.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jenkinsapi.spec ++++++
--- /var/tmp/diff_new_pack.EOjwMw/_old 2020-04-16 23:07:07.975882008 +0200
+++ /var/tmp/diff_new_pack.EOjwMw/_new 2020-04-16 23:07:07.975882008 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-jenkinsapi
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,13 +18,13 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-jenkinsapi
-Version: 0.3.9
+Version: 0.3.11
Release: 0
Summary: A Python API for accessing resources on a Jenkins continuous
integration server
License: MIT
Group: Development/Languages/Python
-Url: https://github.com/salimfadhley/jenkinsapi
-Source:
https://pypi.io/packages/source/j/jenkinsapi/jenkinsapi-%{version}.tar.gz
+URL: https://github.com/salimfadhley/jenkinsapi
+Source:
https://files.pythonhosted.org/packages/source/j/jenkinsapi/jenkinsapi-%{version}.tar.gz
BuildRequires: %{python_module pbr}
BuildRequires: %{python_module pytz}
BuildRequires: %{python_module requests}
@@ -33,7 +33,15 @@
BuildRequires: python-rpm-macros
Requires: python-pytz >= 2014.4
Requires: python-requests >= 2.3.0
+Requires: python-six >= 1.10.0
BuildArch: noarch
+# SECTION test requirements
+BuildRequires: %{python_module astroid >= 1.4.8}
+BuildRequires: %{python_module mock}
+BuildRequires: %{python_module pytest-mock}
+BuildRequires: %{python_module pytest}
+BuildRequires: %{python_module requests-kerberos}
+# /SECTION
%python_subpackages
%description
@@ -78,8 +86,14 @@
%postun
%python_uninstall_alternative jenkins_invoke
+%check
+# E fixture '_view_poll' not found
+rm jenkinsapi_tests/unittests/test_view.py
+# E ConnectionError: HTTPSConnectionPool(host='updates.jenkins.io...
+rm jenkinsapi_tests/unittests/test_plugins.py
+%pytest jenkinsapi_tests/unittests jenkinsapi_tests/test_utils
+
%files %{python_files}
-%defattr(-,root,root,-)
%doc README.rst
%license license.txt
%python_alternative %{_bindir}/jenkins_invoke
++++++ jenkinsapi-0.3.9.tar.gz -> jenkinsapi-0.3.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/.github/stale.yml
new/jenkinsapi-0.3.11/.github/stale.yml
--- old/jenkinsapi-0.3.9/.github/stale.yml 1970-01-01 01:00:00.000000000
+0100
+++ new/jenkinsapi-0.3.11/.github/stale.yml 2019-10-21 13:43:49.000000000
+0200
@@ -0,0 +1,64 @@
+# Configuration for probot-stale - https://github.com/probot/stale
+
+# Number of days of inactivity before an Issue or Pull Request becomes stale
+daysUntilStale: 60
+
+# Number of days of inactivity before an Issue or Pull Request with the stale
label is closed.
+# Set to false to disable. If disabled, issues still need to be closed
manually, but will remain marked as stale.
+daysUntilClose: 7
+
+# Only issues or pull requests with all of these labels are check if stale.
Defaults to `[]` (disabled)
+onlyLabels: []
+
+# Issues or Pull Requests with these labels will never be considered stale.
Set to `[]` to disable
+exemptLabels:
+ - pinned
+ - security
+ - "[Status] Maybe Later"
+ - "feature request"
+ - "help wanted"
+ - "improvement request"
+
+# Set to true to ignore issues in a project (defaults to false)
+exemptProjects: false
+
+# Set to true to ignore issues in a milestone (defaults to false)
+exemptMilestones: false
+
+# Set to true to ignore issues with an assignee (defaults to false)
+exemptAssignees: false
+
+# Label to use when marking as stale
+staleLabel: stale
+
+# Comment to post when marking as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+
+# Comment to post when removing the stale label.
+# unmarkComment: >
+# Your comment here.
+
+# Comment to post when closing a stale Issue or Pull Request.
+closeComment: >
+ Closed due to inactivity
+
+# Limit the number of actions per hour, from 1-30. Default is 30
+limitPerRun: 30
+
+# Limit to only `issues` or `pulls`
+# only: issues
+
+# Optionally, specify configuration settings that are specific to just
'issues' or 'pulls':
+# pulls:
+# daysUntilStale: 30
+# markComment: >
+# This pull request has been automatically marked as stale because it has
not had
+# recent activity. It will be closed if no further activity occurs. Thank
you
+# for your contributions.
+
+# issues:
+# exemptLabels:
+# - confirmed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/AUTHORS
new/jenkinsapi-0.3.11/AUTHORS
--- old/jenkinsapi-0.3.9/AUTHORS 2019-04-13 02:46:41.000000000 +0200
+++ new/jenkinsapi-0.3.11/AUTHORS 2019-10-31 13:00:21.000000000 +0100
@@ -16,6 +16,7 @@
Bradley Harris <[email protected]>
Brian Weber <[email protected]>
Chris Gavin <[email protected]>
+Chris Maes <[email protected]>
Christophe Bliard <[email protected]>
Christophe de Vienne <[email protected]>
Cleber J Santos <[email protected]>
@@ -42,6 +43,7 @@
Jason Swager <[email protected]>
Jeremy Kao <[email protected]>
Jingjing Duan <[email protected]>
+Jiri Polansky <[email protected]>
Joao Vale <[email protected]>
John Zeller <[email protected]>
Jon Passki <[email protected]>
@@ -61,6 +63,7 @@
Lars Hupfeldt <[email protected]>
Lars Wirzenius <[email protected]>
Leshist <[email protected]>
+Lucas Cimon <[email protected]>
Marius van den Beek <[email protected]>
Matt Hootman <[email protected]>
Mickaël Schoentgen <[email protected]>
@@ -72,6 +75,7 @@
Pablo Fabregat <[email protected]>
Paul Belanger <[email protected]>
Petr Kocandrle <[email protected]>
+Przemysław Pietras <[email protected]>
Rafael Eyng <[email protected]>
Ramon van Alteren <[email protected]>
Robert Collins <[email protected]>
@@ -90,6 +94,7 @@
Sorin Sbarnea <[email protected]>
Sorin Sbarnea <[email protected]>
Stephen Chu <[email protected]>
+Steve Bussetti <[email protected]>
Steve Lounsbury <[email protected]>
Sudharshan S <[email protected]>
Sudharshan S <[email protected]>
@@ -110,6 +115,7 @@
andrewgy8 <[email protected]>
bbgobie <[email protected]>
benjaminkemper <[email protected]>
+chrismaes87 <[email protected]>
ddavydov <[email protected]>
elhostis <[email protected]>
hokadiri <[email protected]>
@@ -119,11 +125,14 @@
jpiron <[email protected]>
jwhitworth <[email protected]>
kavehv <[email protected]>
+kennedy <[email protected]>
kworr <[email protected]>
lechat <[email protected]>
lechat <[email protected]>
+leon-gh <[email protected]>
lphoward <[email protected]>
luciali <[email protected]>
+maxime-viargues-serato <[email protected]>
mdear <[email protected]>
mthak <[email protected]>
mthakkar <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/ChangeLog
new/jenkinsapi-0.3.11/ChangeLog
--- old/jenkinsapi-0.3.9/ChangeLog 2019-04-13 02:46:41.000000000 +0200
+++ new/jenkinsapi-0.3.11/ChangeLog 2019-10-31 13:00:21.000000000 +0100
@@ -1,6 +1,35 @@
CHANGES
=======
+0.3.11
+------
+
+* jobs.py: don't yield jobs twice (#740)
+* Add debug log message in JenkinsBase.process\_job\_folder to follow
execution progress (#738)
+* don't faile when node\_descriprion is missing (#737)
+* Fix safe exit test (#736)
+* don't stale feature requests or "help wanted"
+* change label for stale issues
+* Fixed idle state not being refreshed (#575)
+* Simple plugins (#735)
+
+0.3.10
+------
+
+* Add method for streaming build logs (#722)
+* add instructions for Stale bot
+* Fixed problems with changeSets (#717)
+* Create Node by providing predetermined configuration (#730)
+* Fix plugin versions (#734)
+* Updates Requester to use a Session, maintaining cookies (#727)
+* Feature/multibranch pipeline job (#715)
+* Fix failures caused by plugins (#718)
+* Fix for build.get\_artifacts() (#712)
+* Add safe exit (#700)
+* simplify crumb usage (#704)
+* generate new api token for logged in user (#706)
+* ignore dot files (#705)
+
0.3.9
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/PKG-INFO
new/jenkinsapi-0.3.11/PKG-INFO
--- old/jenkinsapi-0.3.9/PKG-INFO 2019-04-13 02:46:42.000000000 +0200
+++ new/jenkinsapi-0.3.11/PKG-INFO 2019-10-31 13:00:22.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: jenkinsapi
-Version: 0.3.9
+Version: 0.3.11
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.9/examples/how_to/use_crumbs.py
new/jenkinsapi-0.3.11/examples/how_to/use_crumbs.py
--- old/jenkinsapi-0.3.9/examples/how_to/use_crumbs.py 2018-11-13
01:11:17.000000000 +0100
+++ new/jenkinsapi-0.3.11/examples/how_to/use_crumbs.py 2019-10-18
14:46:09.000000000 +0200
@@ -1,17 +1,9 @@
"""
-Example of using CrumbRequester - when CSRF protection is enable in Jenkins
+Example of using CrumbRequester - when CSRF protection is enabled in Jenkins
"""
from jenkinsapi.jenkins import Jenkins
-from jenkinsapi.utils.crumb_requester import CrumbRequester
-jenkins = Jenkins(
- 'http://localhost:8080', username='admin', password='password',
- requester=CrumbRequester(
- baseurl='http://localhost:8080',
- username='admin',
- password='password'
- )
-)
+jenkins = Jenkins('http://localhost:8080', username='admin',
password='password', useCrumb=True)
for job_name in jenkins.jobs:
- print job_name
+ print(job_name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/build.py
new/jenkinsapi-0.3.11/jenkinsapi/build.py
--- old/jenkinsapi-0.3.9/jenkinsapi/build.py 2018-11-13 01:11:17.000000000
+0100
+++ new/jenkinsapi-0.3.11/jenkinsapi/build.py 2019-10-18 16:28:28.000000000
+0200
@@ -82,16 +82,13 @@
return self._data["builtOn"]
def get_revision(self):
- vcs = self._data['changeSet']['kind'] or 'git'
- return getattr(self, '_get_%s_rev' % vcs, lambda: None)()
+ return getattr(self, '_get_%s_rev' % self._get_vcs(), lambda: None)()
def get_revision_branch(self):
- vcs = self._data['changeSet']['kind'] or 'git'
- return getattr(self, '_get_%s_rev_branch' % vcs, lambda: None)()
+ return getattr(self, '_get_%s_rev_branch' % self._get_vcs(), lambda:
None)()
def get_repo_url(self):
- vcs = self._data['changeSet']['kind'] or 'git'
- return getattr(self, '_get_%s_repo_url' % vcs, lambda: None)()
+ return getattr(self, '_get_%s_repo_url' % self._get_vcs(), lambda:
None)()
def get_params(self):
"""
@@ -147,6 +144,18 @@
return self._data['changeSets']['items']
return []
+ def _get_vcs(self):
+ """
+ Returns a string VCS.
+ By default, 'git' will be used.
+ """
+ vcs = 'git'
+ if 'changeSet' in self._data and 'kind' in self._data['changeSet']:
+ vcs = self._data['changeSet']['kind'] or 'git'
+ elif 'changeSets' in self._data and 'kind' in self._data['changeSets']:
+ vcs = self._data['changeSets']['kind'] or 'git'
+ return vcs
+
def _get_svn_rev(self):
warnings.warn(
"This untested function may soon be removed from Jenkinsapi "
@@ -222,7 +231,7 @@
def get_artifact_dict(self):
return dict(
- (af.filename, af) for af in self.get_artifacts()
+ (af.relative_path, af) for af in self.get_artifacts()
)
def get_upstream_job_name(self):
@@ -494,6 +503,27 @@
else:
raise JenkinsAPIException('Unknown content type for console')
+ def stream_logs(self, interval=0):
+ """
+ Return generator which streams parts of text console.
+ """
+ url = "%s/logText/progressiveText" % self.baseurl
+ size = 0
+ more_data = True
+ while more_data:
+ resp = self.job.jenkins.requester.get_url(url, params={'start':
size})
+ content = resp.content
+ if content:
+ if isinstance(content, str):
+ yield content
+ elif isinstance(content, bytes):
+ yield content.decode('ISO-8859-1')
+ else:
+ raise JenkinsAPIException('Unknown content type for
console')
+ size = resp.headers['X-Text-Size']
+ more_data = resp.headers.get('X-More-Data')
+ sleep(interval)
+
def get_estimated_duration(self):
"""
Return the estimated build duration (in seconds) or none.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/jenkins.py
new/jenkinsapi-0.3.11/jenkinsapi/jenkins.py
--- old/jenkinsapi-0.3.9/jenkinsapi/jenkins.py 2019-04-12 15:45:38.000000000
+0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/jenkins.py 2019-10-21 15:49:10.000000000
+0200
@@ -22,12 +22,14 @@
from jenkinsapi.nodes import Nodes
from jenkinsapi.plugins import Plugins
from jenkinsapi.plugin import Plugin
+from jenkinsapi.utils.requester import Requester
from jenkinsapi.views import Views
from jenkinsapi.queue import Queue
from jenkinsapi.fingerprint import Fingerprint
from jenkinsapi.jenkinsbase import JenkinsBase
-from jenkinsapi.utils.requester import Requester
from jenkinsapi.custom_exceptions import JenkinsAPIException
+from jenkinsapi.utils.crumb_requester import CrumbRequester
+
log = logging.getLogger(__name__)
@@ -42,7 +44,8 @@
self, baseurl,
username=None, password=None,
requester=None, lazy=False,
- ssl_verify=True, cert=None, timeout=10):
+ ssl_verify=True, cert=None,
+ timeout=10, useCrumb=False):
"""
:param baseurl: baseurl for jenkins instance including port, str
:param username: username for jenkins auth, str
@@ -51,14 +54,23 @@
"""
self.username = username
self.password = password
- self.requester = requester or Requester(
- username,
- password,
- baseurl=baseurl,
- ssl_verify=ssl_verify,
- cert=cert,
- timeout=timeout
- )
+ if requester is None:
+ if useCrumb:
+ requester = CrumbRequester
+ else:
+ requester = Requester
+
+ self.requester = requester(
+ username,
+ password,
+ baseurl=baseurl,
+ ssl_verify=ssl_verify,
+ cert=cert,
+ timeout=timeout
+ )
+ else:
+ self.requester = requester
+
self.requester.timeout = timeout
self.lazy = lazy
self.jobs_container = None
@@ -172,6 +184,12 @@
"""
return self.jobs.create(jobname, xml)
+ def create_multibranch_pipeline_job(self, jobname, xml, block=True,
delay=60):
+ """
+ :return: list of new Job objects
+ """
+ return self.jobs.create_multibranch_pipeline(jobname, xml, block,
delay)
+
def copy_job(self, jobname, newjobname):
return self.jobs.copy(jobname, newjobname)
@@ -335,6 +353,17 @@
}
return self.nodes.create_node(name, node_dict)
+ def create_node_with_config(self, name, config):
+ """
+ Create a new slave node with specific configuration.
+ Config should be resemble the output of node.get_node_attributes()
+ :param str name: name of slave
+ :param dict config: Node attributes for Jenkins API request to create
node
+ (See function output Node.get_node_attributes())
+ :return: node obj
+ """
+ return self.nodes.create_node_with_config(name=name, config=config)
+
def get_plugins_url(self, depth):
# This only ever needs to work on the base object
return '%s/pluginManager/api/python?depth=%i' % (self.baseurl, depth)
@@ -477,6 +506,68 @@
# so Jenkins is likely available
time.sleep(1)
+ def safe_exit(self, wait_for_exit=True, max_wait=360):
+ """ restarts jenkins when no jobs are running, except for pipeline
jobs """
+ # NB: unlike other methods, the value of resp.status_code
+ # here can be 503 even when everything is normal
+ url = '%s/safeExit' % (self.baseurl,)
+ valid = self.requester.VALID_STATUS_CODES + [503, 500]
+ resp = self.requester.post_and_confirm_status(url, data='',
+ valid=valid)
+ if wait_for_exit:
+ self._wait_for_exit(max_wait=max_wait)
+ return resp
+
+ def _wait_for_exit(self, max_wait=360):
+ # We need to make sure all non pipeline jobs have finished,
+ # and that jenkins is unavailable
+ self.__jenkins_is_unresponsive(max_wait=max_wait)
+
+ def __jenkins_is_unresponsive(self, max_wait=360):
+ # Blocks until jenkins returns ConnectionError or JenkinsAPIException
+ # Default wait is one hour
+ is_alive = True
+ wait = 0
+ while is_alive and wait < max_wait:
+ try:
+ self.requester.get_and_confirm_status(
+ self.baseurl, valid=[200])
+ time.sleep(1)
+ wait += 1
+ is_alive = True
+ except (ConnectionError, JenkinsAPIException):
+ # Jenkins is finally down
+ is_alive = False
+ return True
+ except HTTPError:
+ # This is a return code that is not 503,
+ # so Jenkins is likely available, and we need to wait
+ time.sleep(1)
+ wait += 1
+ is_alive = True
+
+ def quiet_down(self):
+ """ Put Jenkins in a Quiet mode, preparation for restart. no new
builds started"""
+ #
https://support.cloudbees.com/hc/en-us/articles/216118748-How-to-Start-Stop-or-Restart-your-Instance-
+ # NB: unlike other methods, the value of resp.status_code
+ # here can be 503 even when everything is normal
+ url = '%s/quietDown' % (self.baseurl,)
+ valid = self.requester.VALID_STATUS_CODES + [503, 500]
+ resp = self.requester.post_and_confirm_status(url, data='',
+ valid=valid)
+ return resp
+
+ def cancel_quiet_down(self):
+ """ Cancel the effect of the quiet-down command """
+ #
https://support.cloudbees.com/hc/en-us/articles/216118748-How-to-Start-Stop-or-Restart-your-Instance-
+ # NB: unlike other methods, the value of resp.status_code
+ # here can be 503 even when everything is normal
+ url = '%s/cancelQuietDown' % (self.baseurl,)
+ valid = self.requester.VALID_STATUS_CODES + [503, 500]
+ resp = self.requester.post_and_confirm_status(url, data='',
+ valid=valid)
+ return resp
+
@property
def plugins(self):
return self.get_plugins()
@@ -528,10 +619,24 @@
def credentials_by_id(self):
return self.get_credentials(CredentialsById)
+ @property
+ def is_quieting_down(self):
+ url = '%s/api/python?tree=quietingDown' % (self.baseurl,)
+ data = self.get_data(url=url)
+ return data.get('quietingDown', False)
+
def shutdown(self):
url = "%s/exit" % self.baseurl
self.requester.post_and_confirm_status(url, data='')
+ def generate_new_api_token(self, new_token_name='Token By jenkinsapi
python'):
+ subUrl =
'/me/descriptorByName/jenkins.security.ApiTokenProperty/generateNewToken'
+ url = '%s%s' % (self.baseurl, subUrl)
+ data = urlencode({'newTokenName': new_token_name})
+ response = self.requester.post_and_confirm_status(url, data=data)
+ token = response.json()['data']['tokenValue']
+ return token
+
def run_groovy_script(self, script):
"""
Runs the requested groovy script on the Jenkins server returning the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/jenkinsbase.py
new/jenkinsapi-0.3.11/jenkinsapi/jenkinsbase.py
--- old/jenkinsapi-0.3.9/jenkinsapi/jenkinsbase.py 2019-04-12
16:44:27.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/jenkinsbase.py 2019-10-31
12:58:24.000000000 +0100
@@ -9,6 +9,8 @@
from jenkinsapi import config
from jenkinsapi.custom_exceptions import JenkinsAPIException
+logger = logging.getLogger(__name__)
+
class JenkinsBase(object):
@@ -77,13 +79,13 @@
response = requester.get_url(url, params)
if response.status_code != 200:
- logging.error('Failed request at %s with params: %s %s',
- url, params, tree if tree else '')
+ logger.error('Failed request at %s with params: %s %s',
+ url, params, tree if tree else '')
response.raise_for_status()
try:
return ast.literal_eval(response.text)
except Exception:
- logging.exception('Inappropriate content found at %s', url)
+ logger.exception('Inappropriate content found at %s', url)
raise JenkinsAPIException('Cannot parse %s' % response.content)
def pprint(self):
@@ -101,6 +103,7 @@
return jobs
def process_job_folder(self, folder, folder_path):
+ logger.debug('Processing folder %s in %s', folder['name'], folder_path)
folder_path += '/job/%s' % urlquote(folder['name'])
data = self.get_data(self.python_api_url(folder_path),
tree='jobs[name,color]')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/jobs.py
new/jenkinsapi-0.3.11/jenkinsapi/jobs.py
--- old/jenkinsapi-0.3.9/jenkinsapi/jobs.py 2018-11-25 03:54:32.000000000
+0100
+++ new/jenkinsapi-0.3.11/jenkinsapi/jobs.py 2019-10-31 12:58:24.000000000
+0100
@@ -3,6 +3,7 @@
interface for all of the jobs defined on a single Jenkins server.
"""
import logging
+import time
from jenkinsapi.job import Job
from jenkinsapi.custom_exceptions import JenkinsAPIException, UnknownJob
@@ -92,9 +93,10 @@
Iterate over the names & objects for all jobs
"""
for job in self.itervalues():
- yield job.name, job
if job.name != job.get_full_name():
yield job.get_full_name(), job
+ else:
+ yield job.name, job
def __contains__(self, job_name):
"""
@@ -109,12 +111,13 @@
if not self._data:
self._data = self.poll().get('jobs', [])
for row in self._data:
- yield row['name']
if row['name'] != \
Job.get_full_name_from_url_and_baseurl(row['url'],
self.jenkins.baseurl):
yield Job.get_full_name_from_url_and_baseurl(
row['url'], self.jenkins.baseurl)
+ else:
+ yield row['name']
def itervalues(self):
"""
@@ -162,6 +165,60 @@
return self[job_name]
+ def create_multibranch_pipeline(self, job_name, config, block=True,
delay=60):
+ """
+ Create a multibranch pipeline job
+
+ :param str jobname: Name of new job
+ :param str config: XML configuration of new job
+ :param block: block until scan is finished?
+ :param delay: max delay to wait for scan to finish (seconds)
+ :returns list of new Jobs after scan
+ """
+ if not config:
+ raise JenkinsAPIException('Job XML config cannot be empty')
+
+ params = {'name': job_name}
+ try:
+ if isinstance(config, unicode): # pylint:
disable=undefined-variable
+ config = str(config)
+ except NameError:
+ # Python2 already a str
+ pass
+ self.jenkins.requester.post_xml_and_confirm_status(
+ self.jenkins.get_create_url(),
+ data=config,
+ params=params
+ )
+ # Reset to get it refreshed from Jenkins
+ self._data = []
+
+ # Launch a first scan / indexing to discover the branches...
+ self.jenkins.requester.post_and_confirm_status(
+ '{}/job/{}/build'.format(self.jenkins.baseurl, job_name),
+ data='',
+ valid=[200, 302], # expect 302 without redirects
+ allow_redirects=False)
+
+ start_time = time.time()
+ # redirect-url does not work with indexing;
+ # so the only workaround found is to parse the console output untill
scan has finished.
+ scan_finished = False
+ while not scan_finished and block and time.time() < start_time + delay:
+ indexing_console_text = self.jenkins.requester.get_url(
+ '{}/job/{}/indexing/consoleText'.format(self.jenkins.baseurl,
job_name))
+ if
indexing_console_text.text.strip().split('\n')[-1].startswith('Finished:'):
+ scan_finished = True
+ time.sleep(1)
+
+ # now search for all jobs created; those who start with job_name + '/'
+ jobs = []
+ for name in self.jenkins.get_jobs_list():
+ if name.startswith(job_name + '/'):
+ jobs.append(self[name])
+
+ return jobs
+
def copy(self, job_name, new_job_name):
"""
Copy a job
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/node.py
new/jenkinsapi-0.3.11/jenkinsapi/node.py
--- old/jenkinsapi-0.3.9/jenkinsapi/node.py 2019-04-12 15:45:38.000000000
+0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/node.py 2019-10-31 12:58:24.000000000
+0100
@@ -6,8 +6,9 @@
import xml.etree.ElementTree as ET
+import time
from jenkinsapi.jenkinsbase import JenkinsBase
-from jenkinsapi.custom_exceptions import PostRequired
+from jenkinsapi.custom_exceptions import PostRequired, TimeOut
from jenkinsapi.custom_exceptions import JenkinsAPIException
from six.moves.urllib.parse import quote as urlquote
@@ -171,7 +172,7 @@
'type': 'hudson.slaves.DumbSlave$DescriptorImpl',
'json': json.dumps({
'name': self.name,
- 'nodeDescription': na['node_description'],
+ 'nodeDescription': na.get('node_description', ''),
'numExecutors': na['num_executors'],
'remoteFS': na['remote_fs'],
'labelString': na['labels'],
@@ -201,7 +202,7 @@
return self._data['jnlpAgent']
def is_idle(self):
- return self._data['idle']
+ return self.poll(tree='idle')['idle']
def set_online(self):
"""
@@ -469,6 +470,27 @@
# no need to poll as the architecture will never change
return self.get_monitor('ArchitectureMonitor', poll_monitor=False)
+ def block_until_idle(self, timeout, poll_time=5):
+ """
+ Blocks until the node become idle.
+ :param timeout: Time in second when the wait is aborted.
+ :param poll_time: Interval in seconds between each check.
+ :@raise TimeOut
+ """
+ start_time = time.time()
+ while not self.is_idle() and (time.time() - start_time) < timeout:
+ log.debug(
+ "Waiting for the node to become idle. Elapsed time: %s",
+ (time.time() - start_time)
+ )
+ time.sleep(poll_time)
+
+ if not self.is_idle():
+ raise TimeOut(
+ "The node has not become idle after {} minutes."
+ .format(timeout/60)
+ )
+
def get_response_time(self):
"""
Returns the node's average response time.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/nodes.py
new/jenkinsapi-0.3.11/jenkinsapi/nodes.py
--- old/jenkinsapi-0.3.9/jenkinsapi/nodes.py 2019-04-12 15:45:38.000000000
+0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/nodes.py 2019-10-18 14:46:09.000000000
+0200
@@ -154,3 +154,25 @@
self.jenkins.requester.post_and_confirm_status(url, data=data)
self.poll()
return self[name]
+
+ def create_node_with_config(self, name, config):
+ """
+ Create a new slave node with specific configuration.
+ Config should be resemble the output of node.get_node_attributes()
+ :param str name: name of slave
+ :param dict config: Node attributes for Jenkins API request to create
node
+ (See function output Node.get_node_attributes())
+ :return: node obj
+ """
+ if name in self:
+ return self[name]
+
+ if not isinstance(config, dict):
+ return None
+ url = ('%s/computer/doCreateItem?%s'
+ % (self.jenkins.baseurl,
+ urlencode(config)))
+ data = {'json': urlencode(config)}
+ self.jenkins.requester.post_and_confirm_status(url, data=data)
+ self.poll()
+ return self[name]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/plugins.py
new/jenkinsapi-0.3.11/jenkinsapi/plugins.py
--- old/jenkinsapi-0.3.9/jenkinsapi/plugins.py 2019-04-12 15:45:38.000000000
+0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/plugins.py 2019-10-21 15:49:10.000000000
+0200
@@ -50,7 +50,7 @@
@property
def update_center_dict(self):
- update_center = 'https://updates.jenkins-ci.org/update-center.json'
+ update_center = 'https://updates.jenkins.io/update-center.json'
jsonp = requests.get(update_center).content.decode('utf-8')
return json.loads(jsonp_to_json(jsonp))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi/utils/requester.py
new/jenkinsapi-0.3.11/jenkinsapi/utils/requester.py
--- old/jenkinsapi-0.3.9/jenkinsapi/utils/requester.py 2019-04-12
15:45:38.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi/utils/requester.py 2019-10-18
14:46:09.000000000 +0200
@@ -77,6 +77,7 @@
self.ssl_verify = kwargs.get('ssl_verify', ssl_verify)
self.cert = kwargs.get('cert', cert)
self.timeout = kwargs.get('timeout', timeout)
+ self.session = requests.Session()
def get_request_dict(
self, params=None, data=None, files=None, headers=None, **kwargs):
@@ -140,7 +141,7 @@
allow_redirects=allow_redirects,
stream=stream
)
- return requests.get(self._update_url_scheme(url), **requestKwargs)
+ return self.session.get(self._update_url_scheme(url), **requestKwargs)
def post_url(self, url, params=None, data=None, files=None,
headers=None, allow_redirects=True, **kwargs):
@@ -151,7 +152,7 @@
headers=headers,
allow_redirects=allow_redirects,
**kwargs)
- return requests.post(self._update_url_scheme(url), **requestKwargs)
+ return self.session.post(self._update_url_scheme(url), **requestKwargs)
def post_xml_and_confirm_status(
self, url, params=None, data=None, valid=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi.egg-info/PKG-INFO
new/jenkinsapi-0.3.11/jenkinsapi.egg-info/PKG-INFO
--- old/jenkinsapi-0.3.9/jenkinsapi.egg-info/PKG-INFO 2019-04-13
02:46:41.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi.egg-info/PKG-INFO 2019-10-31
13:00:21.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: jenkinsapi
-Version: 0.3.9
+Version: 0.3.11
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.9/jenkinsapi.egg-info/SOURCES.txt
new/jenkinsapi-0.3.11/jenkinsapi.egg-info/SOURCES.txt
--- old/jenkinsapi-0.3.9/jenkinsapi.egg-info/SOURCES.txt 2019-04-13
02:46:41.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi.egg-info/SOURCES.txt 2019-10-31
13:00:21.000000000 +0100
@@ -12,6 +12,7 @@
test-requirements.txt
tox.ini
.github/ISSUE_TEMPLATE.md
+.github/stale.yml
bin/pipelint
doc/.gitignore
doc/build.properties
@@ -110,6 +111,7 @@
jenkinsapi_tests/systests/test_downstream_upstream.py
jenkinsapi_tests/systests/test_env_vars.py
jenkinsapi_tests/systests/test_executors.py
+jenkinsapi_tests/systests/test_generate_new_api_token.py
jenkinsapi_tests/systests/test_invocation.py
jenkinsapi_tests/systests/test_jenkins.py
jenkinsapi_tests/systests/test_jenkins_artifacts.py
@@ -118,7 +120,9 @@
jenkinsapi_tests/systests/test_parameterized_builds.py
jenkinsapi_tests/systests/test_plugins.py
jenkinsapi_tests/systests/test_queue.py
+jenkinsapi_tests/systests/test_quiet_down.py
jenkinsapi_tests/systests/test_restart.py
+jenkinsapi_tests/systests/test_safe_exit.py
jenkinsapi_tests/systests/test_scm.py
jenkinsapi_tests/systests/test_views.py
jenkinsapi_tests/systests/view_configs.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/jenkinsapi.egg-info/pbr.json
new/jenkinsapi-0.3.11/jenkinsapi.egg-info/pbr.json
--- old/jenkinsapi-0.3.9/jenkinsapi.egg-info/pbr.json 2019-04-13
02:46:41.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi.egg-info/pbr.json 2019-10-31
13:00:21.000000000 +0100
@@ -1 +1 @@
-{"git_version": "b4d62f1", "is_release": true}
\ No newline at end of file
+{"git_version": "dce4073", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/conftest.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/conftest.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/conftest.py 2019-04-12
15:45:38.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/conftest.py 2019-10-21
13:39:57.000000000 +0200
@@ -13,30 +13,32 @@
# Extra plugins required by the systests
PLUGIN_DEPENDENCIES = [
- "http://updates.jenkins-ci.org/latest/"
+ "http://updates.jenkins.io/latest/"
"apache-httpcomponents-client-4-api.hpi",
- "http://updates.jenkins-ci.org/latest/jsch.hpi",
- "http://updates.jenkins-ci.org/latest/trilead-api.hpi",
- "http://updates.jenkins-ci.org/latest/workflow-api.hpi",
- "http://updates.jenkins-ci.org/latest/display-url-api.hpi",
- "http://updates.jenkins-ci.org/latest/workflow-step-api.hpi",
- "http://updates.jenkins-ci.org/latest/workflow-scm-step.hpi",
- "http://updates.jenkins-ci.org/latest/icon-shim.hpi",
- "http://updates.jenkins-ci.org/latest/junit.hpi",
- "http://updates.jenkins-ci.org/latest/script-security.hpi",
- "http://updates.jenkins-ci.org/latest/matrix-project.hpi",
- "http://updates.jenkins-ci.org/latest/credentials.hpi",
- "http://updates.jenkins-ci.org/latest/ssh-credentials.hpi",
- "http://updates.jenkins-ci.org/latest/scm-api.hpi",
- "http://updates.jenkins-ci.org/latest/mailer.hpi",
- "http://updates.jenkins-ci.org/latest/git.hpi",
- "http://updates.jenkins-ci.org/latest/git-client.hpi",
- "https://updates.jenkins-ci.org/latest/nested-view.hpi",
- "https://updates.jenkins-ci.org/latest/ssh-slaves.hpi",
- "https://updates.jenkins-ci.org/latest/structs.hpi",
- "http://updates.jenkins-ci.org/latest/plain-credentials.hpi",
- "http://updates.jenkins-ci.org/latest/envinject.hpi",
- "http://updates.jenkins-ci.org/latest/envinject-api.hpi"
+ "http://updates.jenkins.io/latest/jsch.hpi",
+ "http://updates.jenkins.io/download/plugins/trilead-api/1.0.5/"
+ "trilead-api.hpi",
+ "http://updates.jenkins.io/latest/workflow-api.hpi",
+ "http://updates.jenkins.io/latest/display-url-api.hpi",
+ "http://updates.jenkins.io/latest/workflow-step-api.hpi",
+ "http://updates.jenkins.io/latest/workflow-scm-step.hpi",
+ "http://updates.jenkins.io/latest/icon-shim.hpi",
+ "http://updates.jenkins.io/download/plugins/junit/1.28/junit.hpi",
+ "http://updates.jenkins.io/latest/script-security.hpi",
+ "http://updates.jenkins.io/latest/matrix-project.hpi",
+ "http://updates.jenkins.io/latest/credentials.hpi",
+ "http://updates.jenkins.io/latest/ssh-credentials.hpi",
+ "http://updates.jenkins.io/latest/scm-api.hpi",
+ "http://updates.jenkins.io/latest/mailer.hpi",
+ "http://updates.jenkins.io/latest/git.hpi",
+ "http://updates.jenkins.io/latest/git-client.hpi",
+ "https://updates.jenkins.io/latest/nested-view.hpi",
+ "https://updates.jenkins.io/latest/ssh-slaves.hpi",
+ "https://updates.jenkins.io/latest/structs.hpi",
+ "http://updates.jenkins.io/latest/plain-credentials.hpi",
+ "http://updates.jenkins.io/latest/envinject.hpi",
+ "http://updates.jenkins.io/latest/envinject-api.hpi",
+ "http://updates.jenkins.io/latest/jdk-tool.hpi"
]
@@ -122,7 +124,7 @@
def jenkins(launched_jenkins):
url = launched_jenkins.jenkins_url
- jenkins_instance = Jenkins(url)
+ jenkins_instance = Jenkins(url, timeout=30)
_delete_all_jobs(jenkins_instance)
_delete_all_views(jenkins_instance)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_generate_new_api_token.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_generate_new_api_token.py
---
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_generate_new_api_token.py
1970-01-01 01:00:00.000000000 +0100
+++
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_generate_new_api_token.py
2019-10-18 14:46:09.000000000 +0200
@@ -0,0 +1,24 @@
+
+"""
+System tests for generation new api token for logged in user
+"""
+import pytest
+import logging
+from jenkinsapi.utils.crumb_requester import CrumbRequester
+
+
+log = logging.getLogger(__name__)
+
+
[email protected]_new_api_token
+def test_generate_new_api_token(jenkins_admin_admin):
+ jenkins_admin_admin.requester = CrumbRequester(
+ baseurl=jenkins_admin_admin.baseurl,
+ username=jenkins_admin_admin.username,
+ password=jenkins_admin_admin.password
+ )
+ jenkins_admin_admin.poll()
+
+ new_token = jenkins_admin_admin.generate_new_api_token() # generate new
token
+ log.info('newly generated token: %s', new_token)
+ assert new_token is not None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_jenkins.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_jenkins.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_jenkins.py
2018-11-26 14:23:11.000000000 +0100
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_jenkins.py
2019-10-18 14:46:09.000000000 +0200
@@ -206,7 +206,7 @@
def test_install_delete_single_plugin_string(jenkins):
- plugin_name = 'antisamy-markup-formatter'
+ plugin_name = 'simple-theme-plugin'
plugin_version = 'latest'
plugin = ('%s@%s') % (plugin_name, plugin_version)
@@ -223,7 +223,7 @@
def test_install_delete_single_plugin_object(jenkins):
- plugin_name = 'antisamy-markup-formatter'
+ plugin_name = 'simple-theme-plugin'
plugin_version = 'latest'
plugin = Plugin(('%s@%s') % (plugin_name, plugin_version))
@@ -240,7 +240,7 @@
def test_install_delete_multiple_plugins_mix_string_object(jenkins):
- plugin_one_name = 'antisamy-markup-formatter'
+ plugin_one_name = 'simple-theme-plugin'
plugin_one_version = 'latest'
plugin_one = ('%s@%s') % (plugin_one_name, plugin_one_version)
plugin_two_name = 'docker-commons'
@@ -264,4 +264,4 @@
def test_run_groovy_script(jenkins):
expected_result = 'Hello world!'
result = jenkins.run_groovy_script('print "%s"' % expected_result)
- assert result == 'Hello world!'
+ assert result.strip() == 'Hello world!'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_plugins.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_plugins.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_plugins.py
2017-12-14 14:59:25.000000000 +0100
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_plugins.py
2019-10-21 13:39:57.000000000 +0200
@@ -9,6 +9,16 @@
log = logging.getLogger(__name__)
+def test_plugin_data(jenkins):
+ # It takes time to get plugins json from remote
+ timeout = jenkins.requester.timeout
+ jenkins.requester.timeout = 60
+ jenkins.plugins.check_updates_server()
+ jenkins.requester.timeout = timeout
+
+ assert 'mailer' in jenkins.plugins
+
+
def test_get_missing_plugin(jenkins):
plugins = jenkins.get_plugins()
with pytest.raises(KeyError):
@@ -27,39 +37,38 @@
plugins = jenkins.get_plugins(depth=2)
_, plugin = next(plugins.iteritems())
+ assert isinstance(plugin, Plugin)
+
def test_delete_inexistant_plugin(jenkins):
with pytest.raises(KeyError):
- plugins = jenkins.plugins
-
- del plugins[random_string()]
+ del jenkins.plugins[random_string()]
def test_install_uninstall_plugin(jenkins):
- plugins = jenkins.plugins
- plugin_name = 'async-http-client'
+ plugin_name = 'suppress-stack-trace'
plugin_dict = {
'shortName': plugin_name,
'version': 'latest',
}
- plugins[plugin_name] = Plugin(plugin_dict)
+ jenkins.plugins[plugin_name] = Plugin(plugin_dict)
- assert plugin_name in plugins
+ assert plugin_name in jenkins.plugins
- plugin = plugins[plugin_name]
+ plugin = jenkins.get_plugins()[plugin_name]
assert isinstance(plugin, Plugin)
assert plugin.shortName == plugin_name
- del plugins[plugin_name]
- assert plugins[plugin_name].deleted
+ del jenkins.plugins[plugin_name]
+ assert jenkins.plugins[plugin_name].deleted
def test_install_multiple_plugins(jenkins):
- plugin_one_name = 'jenkins-cloudformation-plugin'
+ plugin_one_name = 'keyboard-shortcuts-plugin'
plugin_one_version = 'latest'
plugin_one = "@".join((plugin_one_name, plugin_one_version))
- plugin_two = Plugin({'shortName': 'anything-goes-formatter', 'version':
'latest'})
+ plugin_two = Plugin({'shortName': 'emotional-jenkins-plugin', 'version':
'latest'})
assert isinstance(plugin_two, Plugin)
@@ -70,23 +79,28 @@
assert plugin_one_name in jenkins.plugins
assert plugin_two.shortName in jenkins.plugins
+ del jenkins.plugins['keyboard-shortcuts-plugin']
+ del jenkins.plugins['emotional-jenkins-plugin']
+
def test_downgrade_plugin(jenkins):
- plugin_name = 'amazon-ecs'
- plugin_version = '1.5' # This is explicitly not the latest version
+ plugin_name = 'console-badge'
+ plugin_version = 'latest'
plugin = Plugin({'shortName': plugin_name, 'version': plugin_version})
assert isinstance(plugin, Plugin)
# Need to restart when not installing the latest version
- jenkins.install_plugins([plugin], restart=True, wait_for_reboot=True)
+ jenkins.install_plugins([plugin])
installed_plugin = jenkins.plugins[plugin_name]
- assert installed_plugin.version == '1.5'
+ assert installed_plugin.version == '1.1'
- older_plugin = Plugin({'shortName': plugin_name, 'version': '1.4'})
+ older_plugin = Plugin({'shortName': plugin_name, 'version': '1.0'})
jenkins.install_plugins([older_plugin], restart=True, wait_for_reboot=True)
installed_older_plugin = jenkins.plugins[plugin_name]
- assert installed_older_plugin.version == '1.4'
+ assert installed_older_plugin.version == '1.0'
+
+ del jenkins.plugins[plugin_name]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_quiet_down.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_quiet_down.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_quiet_down.py
1970-01-01 01:00:00.000000000 +0100
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_quiet_down.py
2019-10-18 14:46:09.000000000 +0200
@@ -0,0 +1,27 @@
+
+"""
+System tests for setting jenkins in quietDown mode
+"""
+import pytest
+import logging
+
+
+log = logging.getLogger(__name__)
+
+
[email protected]_these_please
+def test_quiet_down_and_cancel_quiet_down(jenkins):
+ jenkins.poll() # jenkins should be alive
+
+ jenkins.quiet_down() # put Jenkins in quietDown mode
+ # is_quieting_down = jenkins.is_quieting_down
+ assert jenkins.is_quieting_down is True
+
+ jenkins.poll() # jenkins should be alive
+
+ jenkins.cancel_quiet_down() # leave quietDown mode
+
+ # is_quieting_down = jenkins_api['quietingDown']
+ assert jenkins.is_quieting_down is False
+
+ jenkins.poll() # jenkins should be alive
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_safe_exit.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_safe_exit.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/systests/test_safe_exit.py
1970-01-01 01:00:00.000000000 +0100
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/systests/test_safe_exit.py
2019-10-21 15:49:10.000000000 +0200
@@ -0,0 +1,44 @@
+"""
+System tests for `jenkinsapi.jenkins` module.
+"""
+import time
+import logging
+import pytest
+from jenkinsapi.build import Build
+from jenkinsapi_tests.test_utils.random_strings import random_string
+from jenkinsapi_tests.systests.job_configs import LONG_RUNNING_JOB
+
+
+log = logging.getLogger(__name__)
+
+
[email protected]_these_please
+def test_safe_exit(jenkins):
+ job_name = 'Bcreate_%s' % random_string()
+ job = jenkins.create_job(job_name, LONG_RUNNING_JOB)
+ qq = job.invoke()
+ time.sleep(3)
+ bn = qq.block_until_building(delay=3).get_number()
+ assert isinstance(bn, int)
+
+ build = qq.get_build()
+ assert isinstance(build, Build)
+ assert build.is_running()
+
+ # A job is now running and safe_exit should await running jobs
+ # Call, but wait only for 5 seconds then cancel exit
+ jenkins.safe_exit(wait_for_exit=False)
+ time.sleep(5)
+
+ jenkins.cancel_quiet_down() # leave quietDown mode
+ assert jenkins.is_quieting_down is False
+
+ build.stop()
+ # if we call next line right away - Jenkins have no time to stop job
+ # so we wait a bit
+ while build.is_running():
+ time.sleep(0.5)
+
+ console = build.get_console()
+ assert isinstance(console, str)
+ assert 'Started by user' in console
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_jenkins.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/unittests/test_jenkins.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_jenkins.py
2019-04-12 15:45:38.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/unittests/test_jenkins.py
2019-10-18 14:46:09.000000000 +0200
@@ -1,4 +1,5 @@
import pytest
+from collections import namedtuple
import jenkinsapi
from jenkinsapi.plugins import Plugins
@@ -19,6 +20,34 @@
'color': 'blue'},
]
}
+MULTIBRANCH_JOBS_DATA = {
+ 'jobs': [
+ {'name': 'multibranch-repo/master',
+ 'url': 'http://localhost:8080/job/multibranch-repo/job/master',
+ 'color': 'blue'},
+ {'name': 'multibranch-repo/develop',
+ 'url': 'http://localhost:8080/job/multibranch-repo/job/develop',
+ 'color': 'blue'},
+ ]
+}
+SCAN_MULTIBRANCH_PIPELINE_LOG = """
+Started by timer
+[Fri Jul 05 06:46:00 CEST 2019] Starting branch indexing...
+Connecting to https://stash.macq.eu using Jenkins/****** (jenkins-ldap)
+Repository type: Git
+Looking up internal/base for branches
+Checking branch master from internal/base
+ 'Jenkinsfile' found
+ Met criteria
+No changes detected: master (still at 26d4d8a673f57a957fd5a23f5adfe0be02089294)
+
+ 1 branches were processed
+Looking up internal/base for pull requests
+
+ 0 pull requests were processed
+[Fri Jul 05 06:46:01 CEST 2019] Finished branch indexing. Indexing took 1.1 sec
+Finished: SUCCESS
+"""
@pytest.fixture(scope='function')
@@ -112,6 +141,45 @@
assert 'Job XML config cannot be empty' in str(ar.value)
+def test_create_multibranch_pipeline_job(mocker, monkeypatch):
+ def fake_jenkins_poll(cls, tree=None): # pylint: disable=unused-argument
+ # return multibranch jobs and other jobs.
+ # create_multibranch_pipeline_job is supposed to filter out the
MULTIBRANCH jobs
+ return {
+ 'jobs': TWO_JOBS_DATA['jobs'] + MULTIBRANCH_JOBS_DATA['jobs']
+ }
+
+ def fake_job_poll(cls, tree=None): # pylint: disable=unused-argument
+ return {}
+
+ monkeypatch.setattr(JenkinsBase, '_poll', fake_jenkins_poll)
+ monkeypatch.setattr(Jenkins, '_poll', fake_jenkins_poll)
+ monkeypatch.setattr(Job, '_poll', fake_job_poll)
+
+ mock_requester = Requester(username='foouser', password='foopassword')
+ mock_requester.post_xml_and_confirm_status = mocker.MagicMock(
+ return_value=''
+ )
+ mock_requester.post_and_confirm_status = mocker.MagicMock(
+ return_value=''
+ )
+ get_response = namedtuple('get_response', 'text')
+ mock_requester.get_url = mocker.MagicMock(
+ return_value=get_response(text=SCAN_MULTIBRANCH_PIPELINE_LOG)
+ )
+ jenkins = Jenkins('http://localhost:8080/',
+ username='foouser', password='foopassword',
+ requester=mock_requester)
+
+ jobs = jenkins.create_multibranch_pipeline_job("multibranch-repo",
"multibranch-xml-content")
+
+ for idx, job_instance in enumerate(jobs):
+ assert job_instance.name == MULTIBRANCH_JOBS_DATA['jobs'][idx]['name']
+
+ # make sure we didn't get more jobs.
+ assert len(MULTIBRANCH_JOBS_DATA['jobs']) == len(jobs)
+
+
def test_get_jenkins_obj_from_url(mocker, monkeypatch):
def fake_jenkins_poll(cls, tree=None): # pylint: disable=unused-argument
return TWO_JOBS_DATA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_requester.py
new/jenkinsapi-0.3.11/jenkinsapi_tests/unittests/test_requester.py
--- old/jenkinsapi-0.3.9/jenkinsapi_tests/unittests/test_requester.py
2019-04-12 15:45:38.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi_tests/unittests/test_requester.py
2019-10-18 14:46:09.000000000 +0200
@@ -255,7 +255,7 @@
def fake_get(*args, **kwargs): # pylint: disable=unused-argument
return 'SUCCESS'
- monkeypatch.setattr(requests, 'get', fake_get)
+ monkeypatch.setattr(requests.Session, 'get', fake_get)
req = Requester('foo', 'bar')
response = req.get_url(
@@ -270,7 +270,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return 'SUCCESS'
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
response = req.post_url(
@@ -285,7 +285,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return 'SUCCESS'
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
with pytest.raises(AssertionError):
@@ -304,7 +304,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return FakeResponse()
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
ret = req.post_xml_and_confirm_status(
@@ -319,7 +319,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return 'SUCCESS'
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
with pytest.raises(AssertionError):
@@ -338,7 +338,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return FakeResponse()
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
ret = req.post_and_confirm_status(
@@ -359,7 +359,7 @@
def fake_post(*args, **kwargs): # pylint: disable=unused-argument
return FakeResponse()
- monkeypatch.setattr(requests, 'post', fake_post)
+ monkeypatch.setattr(requests.Session, 'post', fake_post)
req = Requester('foo', 'bar')
with pytest.raises(JenkinsAPIException):
@@ -378,7 +378,7 @@
def fake_get(*args, **kwargs): # pylint: disable=unused-argument
return FakeResponse()
- monkeypatch.setattr(requests, 'get', fake_get)
+ monkeypatch.setattr(requests.Session, 'get', fake_get)
req = Requester('foo', 'bar')
ret = req.get_and_confirm_status(
@@ -398,7 +398,7 @@
def fake_get(*args, **kwargs): # pylint: disable=unused-argument
return FakeResponse()
- monkeypatch.setattr(requests, 'get', fake_get)
+ monkeypatch.setattr(requests.Session, 'get', fake_get)
req = Requester('foo', 'bar', baseurl='http://dummy')
with pytest.raises(JenkinsAPIException):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jenkinsapi-0.3.9/jenkinsapi_utils/jenkins_launcher.py
new/jenkinsapi-0.3.11/jenkinsapi_utils/jenkins_launcher.py
--- old/jenkinsapi-0.3.9/jenkinsapi_utils/jenkins_launcher.py 2019-04-12
15:45:38.000000000 +0200
+++ new/jenkinsapi-0.3.11/jenkinsapi_utils/jenkins_launcher.py 2019-10-21
15:49:10.000000000 +0200
@@ -65,10 +65,10 @@
Launch jenkins
"""
JENKINS_WEEKLY_WAR_URL = (
- "http://mirrors.jenkins-ci.org/war/latest/jenkins.war"
+ "http://updates.jenkins.io/latest/jenkins.war"
)
JENKINS_LTS_WAR_URL = (
- "http://mirrors.jenkins-ci.org/war-stable/latest/jenkins.war"
+ "https://updates.jenkins.io/stable/latest/jenkins.war"
)
def __init__(self, local_orig_dir, systests_dir, war_name,
plugin_urls=None,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/pylintrc
new/jenkinsapi-0.3.11/pylintrc
--- old/jenkinsapi-0.3.9/pylintrc 2018-11-26 13:33:20.000000000 +0100
+++ new/jenkinsapi-0.3.11/pylintrc 2019-10-18 14:46:09.000000000 +0200
@@ -51,7 +51,7 @@
# E1103: %s %r has no %r member (but some types could not be inferred) - fails
to infer real members of types, e.g. in Celery
# W0231: method from base class is not called - complains about not invoking
empty __init__s in parents, which is annoying
# R0921: abstract class not referenced, when in fact referenced from another
egg
-disable=F0401,E0611,E1101,W0142,W0212,R0201,W0703,R0801,R0901,W0511,E1103,W0231,R0921,W0402,I0011,wrong-import-position,wrong-import-order,ungrouped-imports,redefined-variable-type,missing-docstring,redefined-outer-name,redefined-builtin,relative-import,c-extension-no-member,useless-object-inheritance,no-else-return,consider-using-in,consider-using-dict-comprehension,unnecessary-pass
+disable=F0401,E0611,E1101,W0142,W0212,R0201,W0703,R0801,R0901,W0511,E1103,W0231,R0921,W0402,I0011,wrong-import-position,wrong-import-order,ungrouped-imports,redefined-variable-type,missing-docstring,redefined-outer-name,redefined-builtin,relative-import,c-extension-no-member,useless-object-inheritance,no-else-return,consider-using-in,consider-using-dict-comprehension,unnecessary-pass,unnecessary-comprehension
[REPORTS]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jenkinsapi-0.3.9/setup.cfg
new/jenkinsapi-0.3.11/setup.cfg
--- old/jenkinsapi-0.3.9/setup.cfg 2019-04-13 02:46:42.000000000 +0200
+++ new/jenkinsapi-0.3.11/setup.cfg 2019-10-31 13:00:22.000000000 +0100
@@ -51,7 +51,7 @@
universal = 1
[pycodestyle]
-exclude = .tox,doc/source/conf.py,build
+exclude = .tox,doc/source/conf.py,build,.venv,.eggs
max-line-length = 99
[egg_info]