Merge lp:~hashar/python-jenkins/trunk into lp:~python-jenkins-developers/python-jenkins/trunk

Proposed by Antoine "hashar" Musso
Status: Merged
Merged at revision: 17
Proposed branch: lp:~hashar/python-jenkins/trunk
Merge into: lp:~python-jenkins-developers/python-jenkins/trunk
Diff against target: 988 lines (+256/-329)
9 files modified
.pep8 (+2/-0)
doc/Makefile (+27/-4)
doc/source/api.rst (+8/-0)
doc/source/conf.py (+23/-16)
doc/source/example.rst (+22/-0)
doc/source/index.rst (+7/-201)
doc/source/install.rst (+24/-0)
jenkins/__init__.py (+142/-107)
setup.py (+1/-1)
To merge this branch: bzr merge lp:~hashar/python-jenkins/trunk
Reviewer Review Type Date Requested Status
James Page Approve
Review via email: mp+158768@code.launchpad.net

Commit message

fix pep8 issues and refactor sphinx documentation.

Description of the change

My place had a rainy saturday so I decided to do some maintenance work on python-jenkins. This branch has:
- r17: fix pep8 errors on the original code

pep8 is a python standard that is always nice to stick to. Lot of other developers are expecting that style. I haven't tested the changes though :(

- r18: overhaul the sphinx documentation

The module had documentation in both an index.rst and inlined in the jenkins/__init__.py file. The revision drop index.rst manually maintained doc in favor of the inlined one. I have synced a couple of outdated doc blocks. See commit message for details :-]

To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

Works for me - thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.pep8'
2--- .pep8 1970-01-01 00:00:00 +0000
3+++ .pep8 2013-04-13 22:12:24 +0000
4@@ -0,0 +1,2 @@
5+[pep8]
6+ignore = E221,E501
7
8=== modified file 'doc/Makefile'
9--- doc/Makefile 2011-09-04 00:00:30 +0000
10+++ doc/Makefile 2013-04-13 22:12:24 +0000
11@@ -5,14 +5,16 @@
12 SPHINXOPTS =
13 SPHINXBUILD = sphinx-build
14 PAPER =
15-BUILDDIR = _build
16+BUILDDIR = build
17
18 # Internal variables.
19 PAPEROPT_a4 = -D latex_paper_size=a4
20 PAPEROPT_letter = -D latex_paper_size=letter
21-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
22+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
23+# the i18n builder cannot share the environment and doctrees with the others
24+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
25
26-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
27+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
28
29 help:
30 @echo "Please use \`make <target>' where <target> is one of"
31@@ -29,6 +31,9 @@
32 @echo " latexpdf to make LaTeX files and run them through pdflatex"
33 @echo " text to make text files"
34 @echo " man to make manual pages"
35+ @echo " texinfo to make Texinfo files"
36+ @echo " info to make Texinfo files and run them through makeinfo"
37+ @echo " gettext to make PO message catalogs"
38 @echo " changes to make an overview of all changed/added/deprecated items"
39 @echo " linkcheck to check all external links for integrity"
40 @echo " doctest to run all doctests embedded in the documentation (if enabled)"
41@@ -100,7 +105,7 @@
42 latexpdf:
43 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
44 @echo "Running LaTeX files through pdflatex..."
45- make -C $(BUILDDIR)/latex all-pdf
46+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
47 @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
48
49 text:
50@@ -113,6 +118,24 @@
51 @echo
52 @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
53
54+texinfo:
55+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
56+ @echo
57+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
58+ @echo "Run \`make' in that directory to run these through makeinfo" \
59+ "(use \`make info' here to do that automatically)."
60+
61+info:
62+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
63+ @echo "Running Texinfo files through makeinfo..."
64+ make -C $(BUILDDIR)/texinfo info
65+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
66+
67+gettext:
68+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
69+ @echo
70+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
71+
72 changes:
73 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
74 @echo
75
76=== added directory 'doc/build'
77=== added directory 'doc/source'
78=== added file 'doc/source/api.rst'
79--- doc/source/api.rst 1970-01-01 00:00:00 +0000
80+++ doc/source/api.rst 2013-04-13 22:12:24 +0000
81@@ -0,0 +1,8 @@
82+:title: API reference
83+
84+API reference
85+=============
86+
87+.. automodule:: jenkins
88+ :members:
89+ :undoc-members:
90
91=== renamed file 'doc/conf.py' => 'doc/source/conf.py'
92--- doc/conf.py 2011-09-04 00:00:30 +0000
93+++ doc/source/conf.py 2013-04-13 22:12:24 +0000
94@@ -3,7 +3,8 @@
95 # Python Jenkins documentation build configuration file, created by
96 # sphinx-quickstart on Sat Sep 3 16:24:58 2011.
97 #
98-# This file is execfile()d with the current directory set to its containing dir.
99+# This file is execfile()d with the current directory set to its containing
100+# dir.
101 #
102 # Note that not all possible configuration values are present in this
103 # autogenerated file.
104@@ -11,25 +12,31 @@
105 # All configuration values have a default; values that are commented out
106 # serve to show the default.
107
108-import sys, os
109-
110-import sys, os
111-sys.path.insert(0, os.path.abspath('..'))
112+import os
113+import sys
114
115 # If extensions (or modules to document with autodoc) are in another directory,
116 # add these directories to sys.path here. If the directory is relative to the
117 # documentation root, use os.path.abspath to make it absolute, like shown here.
118 #sys.path.insert(0, os.path.abspath('.'))
119+sys.path.insert(0, os.path.abspath('../..'))
120+sys.path.insert(0, os.path.abspath('../../jenkins'))
121
122-# -- General configuration -----------------------------------------------------
123+# -- General configuration ----------------------------------------------------
124
125 # If your documentation needs a minimal Sphinx version, state it here.
126 #needs_sphinx = '1.0'
127
128-# Add any Sphinx extension module names here, as strings. They can be extensions
129-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
130+# Add any Sphinx extension module names here, as strings. They can be
131+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
132 extensions = ['sphinx.ext.autodoc']
133
134+# Also document __init__
135+autoclass_content = 'both'
136+
137+# Change that to 'alphabetical' if you want
138+autodoc_member_order = 'bysource'
139+
140 # Add any paths that contain templates here, relative to this directory.
141 templates_path = ['_templates']
142
143@@ -69,7 +76,7 @@
144 # directories to ignore when looking for source files.
145 exclude_patterns = ['_build']
146
147-# The reST default role (used for this markup: `text`) to use for all documents.
148+# The reST default role (used for this markup: `text`) to use for all documents
149 #default_role = None
150
151 # If true, '()' will be appended to :func: etc. cross-reference text.
152@@ -90,7 +97,7 @@
153 #modindex_common_prefix = []
154
155
156-# -- Options for HTML output ---------------------------------------------------
157+# -- Options for HTML output --------------------------------------------------
158
159 # The theme to use for HTML and HTML Help pages. See the documentation for
160 # a list of builtin themes.
161@@ -123,7 +130,7 @@
162 # Add any paths that contain custom static files (such as style sheets) here,
163 # relative to this directory. They are copied after the builtin static files,
164 # so a file named "default.css" will overwrite the builtin "default.css".
165-html_static_path = ['_static']
166+#html_static_path = ['_static']
167
168 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
169 # using the given strftime format.
170@@ -170,7 +177,7 @@
171 htmlhelp_basename = 'PythonJenkinsdoc'
172
173
174-# -- Options for LaTeX output --------------------------------------------------
175+# -- Options for LaTeX output -------------------------------------------------
176
177 # The paper size ('letter' or 'a4').
178 #latex_paper_size = 'letter'
179@@ -179,10 +186,10 @@
180 #latex_font_size = '10pt'
181
182 # Grouping the document tree into LaTeX files. List of tuples
183-# (source start file, target name, title, author, documentclass [howto/manual]).
184+# (source start file, target name, title, author, documentclass [howto/manual])
185 latex_documents = [
186- ('index', 'PythonJenkins.tex', u'Python Jenkins Documentation',
187- u'Ken Conley, James Page, Tully Foote, Matthew Gertner', 'manual'),
188+ ('index', 'PythonJenkins.tex', u'Python Jenkins Documentation',
189+ u'Ken Conley, James Page, Tully Foote, Matthew Gertner', 'manual'),
190 ]
191
192 # The name of an image file (relative to this directory) to place at the top of
193@@ -209,7 +216,7 @@
194 #latex_domain_indices = True
195
196
197-# -- Options for manual page output --------------------------------------------
198+# -- Options for manual page output -------------------------------------------
199
200 # One entry per manual page. List of tuples
201 # (source start file, name, description, authors, manual section).
202
203=== added file 'doc/source/example.rst'
204--- doc/source/example.rst 1970-01-01 00:00:00 +0000
205+++ doc/source/example.rst 2013-04-13 22:12:24 +0000
206@@ -0,0 +1,22 @@
207+Example usage
208+=============
209+
210+Example usage::
211+
212+ j = jenkins.Jenkins('http://your_url_here', 'username', 'password')
213+ j.get_jobs()
214+ j.create_job('empty', jenkins.EMPTY_CONFIG_XML)
215+ j.disable_job('empty')
216+ j.copy_job('empty', 'empty_copy')
217+ j.enable_job('empty_copy')
218+ j.reconfig_job('empty_copy', jenkins.RECONFIG_XML)
219+
220+ j.delete_job('empty')
221+ j.delete_job('empty_copy')
222+
223+ # build a parameterized job
224+ j.build_job('api-test', {'param1': 'test value 1', 'param2': 'test value 2'})
225+ build_info = j.get_build_info('build_name', next_build_number)
226+ print(build_info)
227+
228+Look at the :doc:`api` for more details.
229
230=== renamed file 'doc/index.rst' => 'doc/source/index.rst'
231--- doc/index.rst 2012-03-01 18:03:09 +0000
232+++ doc/source/index.rst 2013-04-13 22:12:24 +0000
233@@ -5,213 +5,19 @@
234 <http://jenkins-ci.org/>`_ continuous integration server. It is useful
235 for creating and managing jobs as well as build nodes.
236
237-Example usage::
238-
239- j = jenkins.Jenkins('http://your_url_here', 'username', 'password')
240- j.get_jobs()
241- j.create_job('empty', jenkins.EMPTY_CONFIG_XML)
242- j.disable_job('empty')
243- j.copy_job('empty', 'empty_copy')
244- j.enable_job('empty_copy')
245- j.reconfig_job('empty_copy', jenkins.RECONFIG_XML)
246-
247- j.delete_job('empty')
248- j.delete_job('empty_copy')
249-
250- # build a parameterized job
251- j.build_job('api-test', {'param1': 'test value 1', 'param2': 'test value 2'})
252- build_info = j.get_build_info('build_name', next_build_number)
253- print(build_info)
254+Table of content:
255+
256+.. toctree::
257+ :maxdepth: 2
258+ :glob:
259+
260+ *
261
262 Python Jenkins development is hosted on Launchpad: https://launchpad.net/python-jenkins
263
264-Installing
265-==========
266-
267-``pip``::
268-
269- pip install python-jenkins
270-
271-``easy_install``::
272-
273- easy_install python-jenkins
274-
275-Ubuntu Oneiric or later::
276-
277- apt-get install python-jenkins
278-
279-
280-API documentation
281-=================
282-
283-.. class:: JenkinsException
284-
285- General exception type for jenkins-API-related failures.
286-
287-.. class:: Jenkins(url, [username=None, [password=None]])
288-
289- Create handle to Jenkins instance.
290-
291- All methods will raise :class:`JenkinsException` on failure.
292-
293- :param username: Server username, ``str``
294- :param password: Server password, ``str``
295- :param url: URL of Jenkins server, ``str``
296-
297-
298- .. method:: get_jobs(self)
299-
300- Get list of jobs running. Each job is a dictionary with
301- 'name', 'url', and 'color' keys.
302-
303- :returns: list of jobs, ``[ { str: str} ]``
304-
305- .. method:: job_exists(name)
306-
307- :param name: Name of Jenkins job, ``str``
308- :returns: ``True`` if Jenkins job exists
309-
310- .. method:: build_job(name, [parameters=None, [token=None]])
311-
312- Trigger build job.
313-
314- :param parameters: parameters for job, or ``None``, ``dict``
315-
316- .. method:: build_job_url(name, [parameters=None, [token=None]])
317-
318- Get URL to trigger build job. Authenticated setups may require configuring a token on the server side.
319-
320- :param parameters: parameters for job, or None., ``dict``
321- :param token: (optional) token for building job, ``str``
322- :returns: URL for building job
323-
324- .. method:: create_job(name, config_xml)
325-
326- Create a new Jenkins job
327-
328- :param name: Name of Jenkins job, ``str``
329- :param config_xml: config file text, ``str``
330-
331- .. method:: copy_job(from_name, to_name)
332-
333- Copy a Jenkins job
334-
335- :param from_name: Name of Jenkins job to copy from, ``str``
336- :param to_name: Name of Jenkins job to copy to, ``str``
337-
338- .. method:: delete_job(name)
339-
340- Delete Jenkins job permanently.
341-
342- :param name: Name of Jenkins job, ``str``
343-
344- .. method:: enable_job(name)
345-
346- Enable Jenkins job.
347-
348- :param name: Name of Jenkins job, ``str``
349-
350- .. method:: disable_job(name)
351-
352- Disable Jenkins job. To re-enable, call :meth:`Jenkins.enable_job`.
353-
354- :param name: Name of Jenkins job, ``str``
355-
356- .. method:: get_build_info(name, number)
357-
358- Get build information dictionary.
359-
360- :param name: Job name, ``str``
361- :param name: Build number, ``int``
362- :returns: dictionary of build information
363-
364- .. method:: get_job_config(name) -> str
365-
366- Get configuration XML of existing Jenkins job.
367-
368- :param name: Name of Jenkins job, ``str``
369- :returns: Job configuration XML
370-
371- .. method:: get_job_info(name)
372-
373- Get job information dictionary.
374-
375- :param name: Job name, ``str``
376- :returns: dictionary of job information
377-
378- .. method:: debug_job_info(job_name)
379-
380- Print out job info in more readable format
381-
382- .. method:: reconfig_job(name, config_xml)
383-
384- Change configuration of existing Jenkins job. To create a new job, see :meth:`Jenkins.create_job`.
385-
386- :param name: Name of Jenkins job, ``str``
387- :param config_xml: New XML configuration, ``str``
388-
389- .. method:: get_node_info(name) -> dict
390-
391- Get node information dictionary
392-
393- :param name: Node name, ``str``
394- :returns: Dictionary of node info, ``dict``
395-
396- .. method:: node_exists(name) -> bool
397-
398- :param name: Name of Jenkins node, ``str``
399- :returns: ``True`` if Jenkins node exists
400-
401- .. method:: create_node(name, [numExecutors=2, [nodeDescription=None, [remoteFS='/var/lib/jenkins', [labels=None, [exclusive=False]]]]])
402-
403- :param name: name of node to create, ``str``
404- :param numExecutors: number of executors for node, ``int``
405- :param nodeDescription: Description of node, ``str``
406- :param remoteFS: Remote filesystem location to use, ``str``
407- :param labels: Labels to associate with node, ``str``
408- :param exclusive: Use this node for tied jobs only, ``bool``
409-
410- .. method:: delete_node(name)
411-
412- Delete Jenkins node permanently.
413-
414- :param name: Name of Jenkins node, ``str``
415-
416- .. method:: get_queue_info(self)
417-
418- :returns: list of job dictionaries, ``[dict]``
419-
420- Example::
421-
422- >>> queue_info = j.get_queue_info()
423- >>> print(queue_info[0])
424- {u'task': {u'url': u'http://your_url/job/my_job/', u'color': u'aborted_anime', u'name': u'my_job'}, u'stuck': False, u'actions': [{u'causes': [{u'shortDescription': u'Started by timer'}]}], u'buildable': False, u'params': u'', u'buildableStartMilliseconds': 1315087293316, u'why': u'Build #2,532 is already in progress (ETA:10 min)', u'blocked': True}
425-
426- .. method:: get_info(self)
427-
428- Get information on this Master. This information
429- includes job list and view information.
430-
431- :returns: dictionary of information about Master, ``dict``
432-
433- Example::
434-
435- >>> info = j.get_info()
436- >>> jobs = info['jobs']
437- >>> print(jobs[0])
438- {u'url': u'http://your_url_here/job/my_job/', u'color': u'blue', u'name': u'my_job'}
439-
440-
441- .. method:: jenkins_open(req)
442-
443- Utility routine for opening an HTTP request to a Jenkins server. This should only be used
444- to extends the :class:`Jenkins` API.
445-
446-
447 Indices and tables
448 ==================
449
450 * :ref:`genindex`
451 * :ref:`modindex`
452 * :ref:`search`
453-
454
455=== added file 'doc/source/install.rst'
456--- doc/source/install.rst 1970-01-01 00:00:00 +0000
457+++ doc/source/install.rst 2013-04-13 22:12:24 +0000
458@@ -0,0 +1,24 @@
459+:title: Installing
460+
461+Installing
462+==========
463+
464+The module is known to pip and Debian based distribution as
465+``python-jenkins``.
466+
467+``pip``::
468+
469+ pip install python-jenkins
470+
471+``easy_install``::
472+
473+ easy_install python-jenkins
474+
475+The module has been packaged since Ubuntu Oneiric (11.10)::
476+
477+ apt-get install python-jenkins
478+
479+For developpement purpose you can get a fake module installed on your system
480+that will point to your working copy. Simply use::
481+
482+ python setup.py develop
483
484=== modified file 'jenkins/__init__.py'
485--- jenkins/__init__.py 2012-06-25 11:48:32 +0000
486+++ jenkins/__init__.py 2013-04-13 22:12:24 +0000
487@@ -38,57 +38,45 @@
488 # Matthew Gertner <matthew.gertner@gmail.com>
489
490 '''
491-Python API for Jenkins
492-
493-Examples::
494-
495- j = jenkins.Jenkins('http://your_url_here', 'username', 'password')
496- j.get_jobs()
497- j.create_job('empty', jenkins.EMPTY_CONFIG_XML)
498- j.disable_job('empty')
499- j.copy_job('empty', 'empty_copy')
500- j.enable_job('empty_copy')
501- j.reconfig_job('empty_copy', jenkins.RECONFIG_XML)
502-
503- j.delete_job('empty')
504- j.delete_job('empty_copy')
505-
506- # build a parameterized job
507- j.build_job('api-test', {'param1': 'test value 1', 'param2': 'test value 2'})
508+.. module:: jenkins
509+ :platform: Unix, Windows
510+ :synopsis: Python API to interact with Jenkins
511+
512+See examples at :doc:`example`
513 '''
514
515-import sys
516+#import sys
517 import urllib2
518 import urllib
519 import base64
520-import traceback
521+#import traceback
522 import json
523 import httplib
524
525-LAUNCHER_SSH = 'hudson.plugins.sshslaves.SSHLauncher'
526-LAUNCHER_COMMAND = 'hudson.slaves.CommandLauncher'
527+LAUNCHER_SSH = 'hudson.plugins.sshslaves.SSHLauncher'
528+LAUNCHER_COMMAND = 'hudson.slaves.CommandLauncher'
529 LAUNCHER_WINDOWS_SERVICE = 'hudson.os.windows.ManagedWindowsServiceLauncher'
530
531-INFO = 'api/json'
532-JOB_INFO = 'job/%(name)s/api/json?depth=0'
533-Q_INFO = 'queue/api/json?depth=0'
534+INFO = 'api/json'
535+JOB_INFO = 'job/%(name)s/api/json?depth=0'
536+Q_INFO = 'queue/api/json?depth=0'
537 CANCEL_QUEUE = 'queue/item/%(number)s/cancelQueue'
538-CREATE_JOB = 'createItem?name=%(name)s' #also post config.xml
539-CONFIG_JOB = 'job/%(name)s/config.xml'
540-DELETE_JOB = 'job/%(name)s/doDelete'
541-ENABLE_JOB = 'job/%(name)s/enable'
542-DISABLE_JOB = 'job/%(name)s/disable'
543-COPY_JOB = 'createItem?name=%(to_name)s&mode=copy&from=%(from_name)s'
544-BUILD_JOB = 'job/%(name)s/build'
545-STOP_BUILD = 'job/%(name)s/%(number)s/stop'
546+CREATE_JOB = 'createItem?name=%(name)s' # also post config.xml
547+CONFIG_JOB = 'job/%(name)s/config.xml'
548+DELETE_JOB = 'job/%(name)s/doDelete'
549+ENABLE_JOB = 'job/%(name)s/enable'
550+DISABLE_JOB = 'job/%(name)s/disable'
551+COPY_JOB = 'createItem?name=%(to_name)s&mode=copy&from=%(from_name)s'
552+BUILD_JOB = 'job/%(name)s/build'
553+STOP_BUILD = 'job/%(name)s/%(number)s/stop'
554 BUILD_WITH_PARAMS_JOB = 'job/%(name)s/buildWithParameters'
555-BUILD_INFO = 'job/%(name)s/%(number)d/api/json?depth=0'
556+BUILD_INFO = 'job/%(name)s/%(number)d/api/json?depth=0'
557
558
559 CREATE_NODE = 'computer/doCreateItem?%s'
560 DELETE_NODE = 'computer/%(name)s/doDelete'
561-NODE_INFO = 'computer/%(name)s/api/json?depth=0'
562-NODE_TYPE = 'hudson.slaves.DumbSlave$DescriptorImpl'
563+NODE_INFO = 'computer/%(name)s/api/json?depth=0'
564+NODE_TYPE = 'hudson.slaves.DumbSlave$DescriptorImpl'
565 TOGGLE_OFFLINE = 'computer/%(name)s/toggleOffline?offlineMessage=%(msg)s'
566
567 #for testing only
568@@ -118,33 +106,41 @@
569 <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
570 <triggers class='vector'/>
571 <concurrentBuild>false</concurrentBuild>
572-<builders>
573- <jenkins.tasks.Shell>
574- <command>export FOO=bar</command>
575- </jenkins.tasks.Shell>
576- </builders>
577+<builders>
578+ <jenkins.tasks.Shell>
579+ <command>export FOO=bar</command>
580+ </jenkins.tasks.Shell>
581+ </builders>
582 <publishers/>
583 <buildWrappers/>
584 </project>'''
585
586+
587 class JenkinsException(Exception):
588 '''
589 General exception type for jenkins-API-related failures.
590 '''
591 pass
592
593+
594 def auth_headers(username, password):
595 '''
596- Simple implementation of HTTP Basic Authentication. Returns the 'Authentication' header value.
597+ Simple implementation of HTTP Basic Authentication. Returns the
598+ 'Authentication' header value.
599 '''
600 return 'Basic ' + base64.encodestring('%s:%s' % (username, password))[:-1]
601
602+
603 class Jenkins(object):
604
605 def __init__(self, url, username=None, password=None):
606 '''
607 Create handle to Jenkins instance.
608
609+ All methods will raise :class:`JenkinsException` on failure.
610+
611+ :param username: Server username, ``str``
612+ :param password: Server password, ``str``
613 :param url: URL of Jenkins server, ``str``
614 '''
615 if url[-1] == '/':
616@@ -164,15 +160,17 @@
617 :returns: dictionary of job information
618 '''
619 try:
620- response = self.jenkins_open(urllib2.Request(self.server + JOB_INFO%locals()))
621+ response = self.jenkins_open(urllib2.Request(
622+ self.server + JOB_INFO % locals()))
623 if response:
624 return json.loads(response)
625 else:
626- raise JenkinsException('job[%s] does not exist'%name)
627+ raise JenkinsException('job[%s] does not exist' % name)
628 except urllib2.HTTPError:
629- raise JenkinsException('job[%s] does not exist'%name)
630+ raise JenkinsException('job[%s] does not exist' % name)
631 except ValueError:
632- raise JenkinsException("Could not parse JSON info for job[%s]"%name)
633+ raise JenkinsException(
634+ "Could not parse JSON info for job[%s]" % name)
635
636 def debug_job_info(self, job_name):
637 '''
638@@ -183,17 +181,21 @@
639
640 def jenkins_open(self, req):
641 '''
642- Utility routine for opening an HTTP request to a Jenkins server. This should only be used
643- to extends the :class:`Jenkins` API.
644+ Utility routine for opening an HTTP request to a Jenkins server. This
645+ should only be used to extends the :class:`Jenkins` API.
646 '''
647 try:
648 if self.auth:
649 req.add_header('Authorization', self.auth)
650 return urllib2.urlopen(req).read()
651 except urllib2.HTTPError, e:
652- # Jenkins's funky authentication means its nigh impossible to distinguish errors.
653+ # Jenkins's funky authentication means its nigh impossible to
654+ # distinguish errors.
655 if e.code in [401, 403, 500]:
656- raise JenkinsException('Error in request. Possibly authentication failed [%s]'%(e.code))
657+ raise JenkinsException(
658+ 'Error in request.' +
659+ 'Possibly authentication failed [%s]' % (e.code)
660+ )
661 # right now I'm getting 302 infinites on a successful delete
662
663 def get_build_info(self, name, number):
664@@ -214,15 +216,21 @@
665 {u'building': False, u'changeSet': {u'items': [{u'date': u'2011-12-19T18:01:52.540557Z', u'msg': u'test', u'revision': 66, u'user': u'unknown', u'paths': [{u'editType': u'edit', u'file': u'/branches/demo/index.html'}]}], u'kind': u'svn', u'revisions': [{u'module': u'http://eaas-svn01.i3.level3.com/eaas', u'revision': 66}]}, u'builtOn': u'', u'description': None, u'artifacts': [{u'relativePath': u'dist/eaas-87-2011-12-19_18-01-57.war', u'displayPath': u'eaas-87-2011-12-19_18-01-57.war', u'fileName': u'eaas-87-2011-12-19_18-01-57.war'}, {u'relativePath': u'dist/eaas-87-2011-12-19_18-01-57.war.zip', u'displayPath': u'eaas-87-2011-12-19_18-01-57.war.zip', u'fileName': u'eaas-87-2011-12-19_18-01-57.war.zip'}], u'timestamp': 1324317717000, u'number': 87, u'actions': [{u'parameters': [{u'name': u'SERVICE_NAME', u'value': u'eaas'}, {u'name': u'PROJECT_NAME', u'value': u'demo'}]}, {u'causes': [{u'userName': u'anonymous', u'shortDescription': u'Started by user anonymous'}]}, {}, {}, {}], u'id': u'2011-12-19_18-01-57', u'keepLog': False, u'url': u'http://eaas-jenkins01.i3.level3.com:9080/job/build_war/87/', u'culprits': [{u'absoluteUrl': u'http://eaas-jenkins01.i3.level3.com:9080/user/unknown', u'fullName': u'unknown'}], u'result': u'SUCCESS', u'duration': 8826, u'fullDisplayName': u'build_war #87'}
666 '''
667 try:
668- response = self.jenkins_open(urllib2.Request(self.server + BUILD_INFO%locals()))
669+ response = self.jenkins_open(urllib2.Request(
670+ self.server + BUILD_INFO % locals()))
671 if response:
672 return json.loads(response)
673 else:
674- raise JenkinsException('job[%s] number[%d] does not exist'%(name, number))
675+ raise JenkinsException('job[%s] number[%d] does not exist'
676+ % (name, number))
677 except urllib2.HTTPError:
678- raise JenkinsException('job[%s] number[%d] does not exist'%(name, number))
679+ raise JenkinsException('job[%s] number[%d] does not exist'
680+ % (name, number))
681 except ValueError:
682- raise JenkinsException('Could not parse JSON info for job[%s] number[%d]'%(name, number))
683+ raise JenkinsException(
684+ 'Could not parse JSON info for job[%s] number[%d]'
685+ % (name, number)
686+ )
687
688 def get_queue_info(self):
689 '''
690@@ -233,7 +241,9 @@
691 >>> print(queue_info[0])
692 {u'task': {u'url': u'http://your_url/job/my_job/', u'color': u'aborted_anime', u'name': u'my_job'}, u'stuck': False, u'actions': [{u'causes': [{u'shortDescription': u'Started by timer'}]}], u'buildable': False, u'params': u'', u'buildableStartMilliseconds': 1315087293316, u'why': u'Build #2,532 is already in progress (ETA:10 min)', u'blocked': True}
693 '''
694- return json.loads(self.jenkins_open(urllib2.Request(self.server + Q_INFO)))['items']
695+ return json.loads(self.jenkins_open(
696+ urllib2.Request(self.server + Q_INFO)
697+ ))['items']
698
699 def cancel_queue(self, number):
700 '''
701@@ -259,17 +269,22 @@
702 >>> info = j.get_info()
703 >>> jobs = info['jobs']
704 >>> print(jobs[0])
705- {u'url': u'http://your_url_here/job/my_job/', u'color': u'blue', u'name': u'my_job'}
706+ {u'url': u'http://your_url_here/job/my_job/', u'color': u'blue',
707+ u'name': u'my_job'}
708
709 """
710 try:
711- return json.loads(self.jenkins_open(urllib2.Request(self.server + INFO)))
712+ return json.loads(self.jenkins_open(
713+ urllib2.Request(self.server + INFO)))
714 except urllib2.HTTPError:
715- raise JenkinsException("Error communicating with server[%s]"%self.server)
716+ raise JenkinsException("Error communicating with server[%s]"
717+ % self.server)
718 except httplib.BadStatusLine:
719- raise JenkinsException("Error communicating with server[%s]"%self.server)
720+ raise JenkinsException("Error communicating with server[%s]"
721+ % self.server)
722 except ValueError:
723- raise JenkinsException("Could not parse JSON info for server[%s]"%self.server)
724+ raise JenkinsException("Could not parse JSON info for server[%s]"
725+ % self.server)
726
727 def get_jobs(self):
728 """
729@@ -288,20 +303,22 @@
730 :param to_name: Name of Jenkins job to copy to, ``str``
731 '''
732 self.get_job_info(from_name)
733- self.jenkins_open(urllib2.Request(self.server + COPY_JOB%locals(), ''))
734+ self.jenkins_open(urllib2.Request(
735+ self.server + COPY_JOB % locals(), ''))
736 if not self.job_exists(to_name):
737- raise JenkinsException('create[%s] failed'%(to_name))
738+ raise JenkinsException('create[%s] failed' % (to_name))
739
740 def delete_job(self, name):
741 '''
742 Delete Jenkins job permanently.
743-
744+
745 :param name: Name of Jenkins job, ``str``
746 '''
747 self.get_job_info(name)
748- self.jenkins_open(urllib2.Request(self.server + DELETE_JOB%locals(), ''))
749+ self.jenkins_open(urllib2.Request(
750+ self.server + DELETE_JOB % locals(), ''))
751 if self.job_exists(name):
752- raise JenkinsException('delete[%s] failed'%(name))
753+ raise JenkinsException('delete[%s] failed' % (name))
754
755 def enable_job(self, name):
756 '''
757@@ -310,7 +327,8 @@
758 :param name: Name of Jenkins job, ``str``
759 '''
760 self.get_job_info(name)
761- self.jenkins_open(urllib2.Request(self.server + ENABLE_JOB%locals(), ''))
762+ self.jenkins_open(urllib2.Request(
763+ self.server + ENABLE_JOB % locals(), ''))
764
765 def disable_job(self, name):
766 '''
767@@ -319,7 +337,8 @@
768 :param name: Name of Jenkins job, ``str``
769 '''
770 self.get_job_info(name)
771- self.jenkins_open(urllib2.Request(self.server + DISABLE_JOB%locals(), ''))
772+ self.jenkins_open(urllib2.Request(
773+ self.server + DISABLE_JOB % locals(), ''))
774
775 def job_exists(self, name):
776 '''
777@@ -340,12 +359,13 @@
778 :param config_xml: config file text, ``str``
779 '''
780 if self.job_exists(name):
781- raise JenkinsException('job[%s] already exists'%(name))
782+ raise JenkinsException('job[%s] already exists' % (name))
783
784 headers = {'Content-Type': 'text/xml'}
785- self.jenkins_open(urllib2.Request(self.server + CREATE_JOB%locals(), config_xml, headers))
786+ self.jenkins_open(urllib2.Request(
787+ self.server + CREATE_JOB % locals(), config_xml, headers))
788 if not self.job_exists(name):
789- raise JenkinsException('create[%s] failed'%(name))
790+ raise JenkinsException('create[%s] failed' % (name))
791
792 def get_job_config(self, name):
793 '''
794@@ -360,20 +380,22 @@
795
796 def reconfig_job(self, name, config_xml):
797 '''
798- Change configuration of existing Jenkins job. To create a new job, see :meth:`Jenkins.create_job`.
799+ Change configuration of existing Jenkins job. To create a new job, see
800+ :meth:`Jenkins.create_job`.
801
802 :param name: Name of Jenkins job, ``str``
803 :param config_xml: New XML configuration, ``str``
804 '''
805 self.get_job_info(name)
806 headers = {'Content-Type': 'text/xml'}
807- reconfig_url = self.server + CONFIG_JOB%locals()
808+ reconfig_url = self.server + CONFIG_JOB % locals()
809 self.jenkins_open(urllib2.Request(reconfig_url, config_xml, headers))
810
811 def build_job_url(self, name, parameters=None, token=None):
812 '''
813- Get URL to trigger build job. Authenticated setups may require configuring a token on the server side.
814-
815+ Get URL to trigger build job. Authenticated setups may require
816+ configuring a token on the server side.
817+
818 :param parameters: parameters for job, or None., ``dict``
819 :param token: (optional) token for building job, ``str``
820 :returns: URL for building job
821@@ -381,21 +403,26 @@
822 if parameters:
823 if token:
824 parameters['token'] = token
825- return self.server + BUILD_WITH_PARAMS_JOB%locals() + '?' + urllib.urlencode(parameters)
826+ return (self.server + BUILD_WITH_PARAMS_JOB % locals() +
827+ '?' + urllib.urlencode(parameters))
828 elif token:
829- return self.server + BUILD_JOB%locals() + '?' + urllib.urlencode({'token': token})
830+ return (self.server + BUILD_JOB % locals() +
831+ '?' + urllib.urlencode({'token': token}))
832 else:
833- return self.server + BUILD_JOB%locals()
834+ return self.server + BUILD_JOB % locals()
835
836 def build_job(self, name, parameters=None, token=None):
837 '''
838 Trigger build job.
839-
840+
841+ :param name: name of job
842 :param parameters: parameters for job, or ``None``, ``dict``
843+ :param token: Jenkins API token
844 '''
845 if not self.job_exists(name):
846- raise JenkinsException('no such job[%s]'%(name))
847- return self.jenkins_open(urllib2.Request(self.build_job_url(name, parameters, token)))
848+ raise JenkinsException('no such job[%s]' % (name))
849+ return self.jenkins_open(urllib2.Request(
850+ self.build_job_url(name, parameters, token)))
851
852 def stop_build(self, name, number):
853 '''
854@@ -414,15 +441,17 @@
855 :returns: Dictionary of node info, ``dict``
856 '''
857 try:
858- response = self.jenkins_open(urllib2.Request(self.server + NODE_INFO%locals()))
859+ response = self.jenkins_open(urllib2.Request(
860+ self.server + NODE_INFO % locals()))
861 if response:
862 return json.loads(response)
863 else:
864- raise JenkinsException('node[%s] does not exist'%name)
865+ raise JenkinsException('node[%s] does not exist' % name)
866 except urllib2.HTTPError:
867- raise JenkinsException('node[%s] does not exist'%name)
868+ raise JenkinsException('node[%s] does not exist' % name)
869 except ValueError:
870- raise JenkinsException("Could not parse JSON info for node[%s]"%name)
871+ raise JenkinsException("Could not parse JSON info for node[%s]"
872+ % name)
873
874 def node_exists(self, name):
875 '''
876@@ -438,38 +467,40 @@
877 def delete_node(self, name):
878 '''
879 Delete Jenkins node permanently.
880-
881+
882 :param name: Name of Jenkins node, ``str``
883 '''
884 self.get_node_info(name)
885- self.jenkins_open(urllib2.Request(self.server + DELETE_NODE%locals(), ''))
886+ self.jenkins_open(urllib2.Request(
887+ self.server + DELETE_NODE % locals(), ''))
888 if self.node_exists(name):
889- raise JenkinsException('delete[%s] failed'%(name))
890-
891+ raise JenkinsException('delete[%s] failed' % (name))
892
893 def disable_node(self, name, msg=''):
894 '''
895 Disable a node
896-
897+
898 :param name: Jenkins node name, ``str``
899 :param msg: Offline message, ``str``
900 '''
901 info = self.get_node_info(name)
902 if info['offline']:
903 return
904- self.jenkins_open(urllib2.Request(self.server + TOGGLE_OFFLINE%locals()))
905+ self.jenkins_open(urllib2.Request(
906+ self.server + TOGGLE_OFFLINE % locals()))
907
908 def enable_node(self, name):
909 '''
910 Enable a node
911-
912+
913 :param name: Jenkins node name, ``str``
914 '''
915 info = self.get_node_info(name)
916 if not info['offline']:
917 return
918 msg = ''
919- self.jenkins_open(urllib2.Request(self.server + TOGGLE_OFFLINE%locals()))
920+ self.jenkins_open(urllib2.Request(
921+ self.server + TOGGLE_OFFLINE % locals()))
922
923 def create_node(self, name, numExecutors=2, nodeDescription=None,
924 remoteFS='/var/lib/jenkins', labels=None, exclusive=False,
925@@ -485,7 +516,7 @@
926 :param launcher_params: Additional parameters for the launcher, ``dict``
927 '''
928 if self.node_exists(name):
929- raise JenkinsException('node[%s] already exists'%(name))
930+ raise JenkinsException('node[%s] already exists' % (name))
931
932 mode = 'NORMAL'
933 if exclusive:
934@@ -494,25 +525,29 @@
935 launcher_params['stapler-class'] = launcher
936
937 inner_params = {
938- 'name' : name,
939- 'nodeDescription' : nodeDescription,
940- 'numExecutors' : numExecutors,
941- 'remoteFS' : remoteFS,
942- 'labelString' : labels,
943- 'mode' : mode,
944- 'type' : NODE_TYPE,
945- 'retentionStrategy' : { 'stapler-class' : 'hudson.slaves.RetentionStrategy$Always' },
946- 'nodeProperties' : { 'stapler-class-bag' : 'true' },
947- 'launcher' : launcher_params
948+ 'name': name,
949+ 'nodeDescription': nodeDescription,
950+ 'numExecutors': numExecutors,
951+ 'remoteFS': remoteFS,
952+ 'labelString': labels,
953+ 'mode': mode,
954+ 'type': NODE_TYPE,
955+ 'retentionStrategy': {
956+ 'stapler-class':
957+ 'hudson.slaves.RetentionStrategy$Always'
958+ },
959+ 'nodeProperties': {'stapler-class-bag': 'true'},
960+ 'launcher': launcher_params
961 }
962
963 params = {
964- 'name' : name,
965- 'type' : NODE_TYPE,
966- 'json' : json.dumps(inner_params)
967+ 'name': name,
968+ 'type': NODE_TYPE,
969+ 'json': json.dumps(inner_params)
970 }
971
972- self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params)))
973+ self.jenkins_open(urllib2.Request(
974+ self.server + CREATE_NODE % urllib.urlencode(params)))
975
976 if not self.node_exists(name):
977- raise JenkinsException('create[%s] failed'%(name))
978+ raise JenkinsException('create[%s] failed' % (name))
979
980=== modified file 'setup.py'
981--- setup.py 2012-05-17 15:35:18 +0000
982+++ setup.py 2013-04-13 22:12:24 +0000
983@@ -9,4 +9,4 @@
984 author_email='kwc@willowgarage.com',
985 url='http://launchpad.net/python-jenkins',
986 packages=['jenkins'],
987- )
988+ )

Subscribers

People subscribed via source and target branches