From 2af93d33bf4debcacd4d183c134d0aadde9f2b9f Mon Sep 17 00:00:00 2001 From: Ken Rumer Date: Wed, 29 Feb 2012 10:23:45 -0700 Subject: [PATCH 1/3] Added build_info --- doc/index.rst | 8 ++++++++ jenkins/__init__.py | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/doc/index.rst b/doc/index.rst index 7a314da..8dc32fc 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -115,6 +115,14 @@ API documentation :param name: Name of Jenkins job, ``str`` + .. method:: get_build_info(name, number) + + Get build information dictionary. + + :param name: Job name, ``str`` + :param name: Job number, ``str`` + :returns: dictionary of build information + .. method:: get_job_config(name) -> str Get configuration XML of existing Jenkins job. diff --git a/jenkins/__init__.py b/jenkins/__init__.py index b7a2b9b..eb3e7c4 100644 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -76,6 +76,7 @@ DISABLE_JOB = 'job/%(name)s/disable' COPY_JOB = 'createItem?name=%(to_name)s&mode=copy&from=%(from_name)s' BUILD_JOB = 'job/%(name)s/build' BUILD_WITH_PARAMS_JOB = 'job/%(name)s/buildWithParameters' +BUILD_INFO = 'job/%(name)s/%(number)d/api/json?depth=0' CREATE_NODE = 'computer/doCreateItem?%s' @@ -188,6 +189,18 @@ class Jenkins(object): if e.code in [401, 403, 500]: raise JenkinsException('Error in request. Possibly authentication failed [%s]'%(e.code)) # right now I'm getting 302 infinites on a successful delete + + def get_build_info(self, name, number): + try: + response = self.jenkins_open(urllib2.Request(self.server + BUILD_INFO%locals())) + if response: + return json.loads(response) + else: + raise JenkinsException('job[!s] number[!d] does not exist'.format(name, number)) + except urllib2.HTTPError: + raise JenkinsException('job[!s] number[!d] does not exist'.format(name, number)) + except ValueError: + raise JenkinsException("Could not parse JSON info for job[!s] number[!d]".format(name, number)) def get_queue_info(self): ''' From 7aee9185238032a70575aca5bc808609772bfd99 Mon Sep 17 00:00:00 2001 From: Ken Rumer Date: Thu, 1 Mar 2012 11:03:09 -0700 Subject: [PATCH 2/3] Updated documentation, updated error handler for consistency --- doc/index.rst | 4 +++- jenkins/__init__.py | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 8dc32fc..4536dea 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -20,6 +20,8 @@ Example usage:: # build a parameterized job j.build_job('api-test', {'param1': 'test value 1', 'param2': 'test value 2'}) + build_info = j.get_build_info('build_name', next_build_number) + print(build_info) Python Jenkins development is hosted on Launchpad: https://launchpad.net/python-jenkins @@ -120,7 +122,7 @@ API documentation Get build information dictionary. :param name: Job name, ``str`` - :param name: Job number, ``str`` + :param name: Build number, ``int`` :returns: dictionary of build information .. method:: get_job_config(name) -> str diff --git a/jenkins/__init__.py b/jenkins/__init__.py index eb3e7c4..8b1e441 100644 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -191,16 +191,31 @@ class Jenkins(object): # right now I'm getting 302 infinites on a successful delete def get_build_info(self, name, number): + ''' + Get information on this Master. This information + includes status of build. + + :returns: dictionary of information about build, ``dict`` + + Example:: + + >>> next_build_number = j.get_job_info('build_name')['next_build_number'] + >>> output = j.build_job('build_'+kwargs['vcs_server_type'], params) + >>> sleep(10) + >>> build_info = j.get_build_info('build_name', next_build_number) + >>> print(build_info) + {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'} + ''' try: response = self.jenkins_open(urllib2.Request(self.server + BUILD_INFO%locals())) if response: return json.loads(response) else: - raise JenkinsException('job[!s] number[!d] does not exist'.format(name, number)) + raise JenkinsException('job[%s] number[%d] does not exist'%(name, number)) except urllib2.HTTPError: - raise JenkinsException('job[!s] number[!d] does not exist'.format(name, number)) + raise JenkinsException('job[%s] number[%d] does not exist'%(name, number)) except ValueError: - raise JenkinsException("Could not parse JSON info for job[!s] number[!d]".format(name, number)) + raise JenkinsException('Could not parse JSON info for job[%s] number[%d]'%(name, number)) def get_queue_info(self): ''' From 2ccd2c77d8ecfd755ac5192ddf50a09af66e1937 Mon Sep 17 00:00:00 2001 From: James Page Date: Fri, 2 Mar 2012 16:26:13 +0000 Subject: [PATCH 3/3] Tidied trailing whitespace --- jenkins/__init__.py | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/jenkins/__init__.py b/jenkins/__init__.py index 8b1e441..a1043a6 100644 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -134,7 +134,7 @@ def auth_headers(username, password): return 'Basic ' + base64.encodestring('%s:%s' % (username, password))[:-1] class Jenkins(object): - + def __init__(self, url, username=None, password=None): ''' Create handle to Jenkins instance. @@ -145,11 +145,11 @@ class Jenkins(object): self.server = url else: self.server = url + '/' - if username is not None and password is not None: + if username is not None and password is not None: self.auth = auth_headers(username, password) else: self.auth = None - + def get_job_info(self, name): ''' Get job information dictionary. @@ -167,7 +167,7 @@ class Jenkins(object): raise JenkinsException('job[%s] does not exist'%name) except ValueError: raise JenkinsException("Could not parse JSON info for job[%s]"%name) - + def debug_job_info(self, job_name): ''' Print out job info in more readable format @@ -192,10 +192,11 @@ class Jenkins(object): def get_build_info(self, name, number): ''' - Get information on this Master. This information - includes status of build. + Get build information dictionary. - :returns: dictionary of information about build, ``dict`` + :param name: Job name, ``str`` + :param name: Build number, ``int`` + :returns: dictionary of build information, ``dict`` Example:: @@ -215,8 +216,8 @@ class Jenkins(object): except urllib2.HTTPError: raise JenkinsException('job[%s] number[%d] does not exist'%(name, number)) except ValueError: - raise JenkinsException('Could not parse JSON info for job[%s] number[%d]'%(name, number)) - + raise JenkinsException('Could not parse JSON info for job[%s] number[%d]'%(name, number)) + def get_queue_info(self): ''' :returns: list of job dictionaries, ``[dict]`` @@ -283,7 +284,7 @@ class Jenkins(object): self.jenkins_open(urllib2.Request(self.server + DELETE_JOB%locals(), '')) if self.job_exists(name): raise JenkinsException('delete[%s] failed'%(name)) - + def enable_job(self, name): ''' Enable Jenkins job. @@ -327,7 +328,7 @@ class Jenkins(object): self.jenkins_open(urllib2.Request(self.server + CREATE_JOB%locals(), config_xml, headers)) if not self.job_exists(name): raise JenkinsException('create[%s] failed'%(name)) - + def get_job_config(self, name): ''' Get configuration of existing Jenkins job. @@ -375,8 +376,8 @@ class Jenkins(object): ''' if not self.job_exists(name): raise JenkinsException('no such job[%s]'%(name)) - return self.jenkins_open(urllib2.Request(self.build_job_url(name, parameters, token))) - + return self.jenkins_open(urllib2.Request(self.build_job_url(name, parameters, token))) + def get_node_info(self, name): ''' Get node information dictionary @@ -394,7 +395,7 @@ class Jenkins(object): raise JenkinsException('node[%s] does not exist'%name) except ValueError: raise JenkinsException("Could not parse JSON info for node[%s]"%name) - + def node_exists(self, name): ''' :param name: Name of Jenkins node, ``str`` @@ -405,7 +406,7 @@ class Jenkins(object): return True except JenkinsException: return False - + def delete_node(self, name): ''' Delete Jenkins node permanently. @@ -416,8 +417,8 @@ class Jenkins(object): self.jenkins_open(urllib2.Request(self.server + DELETE_NODE%locals(), '')) if self.node_exists(name): raise JenkinsException('delete[%s] failed'%(name)) - - + + def create_node(self, name, numExecutors=2, nodeDescription=None, remoteFS='/var/lib/jenkins', labels=None, exclusive=False): ''' @@ -430,11 +431,11 @@ class Jenkins(object): ''' if self.node_exists(name): raise JenkinsException('node[%s] already exists'%(name)) - + mode = 'NORMAL' if exclusive: mode = 'EXCLUSIVE' - + params = { 'name' : name, 'type' : NODE_TYPE, @@ -451,7 +452,7 @@ class Jenkins(object): 'launcher' : { 'stapler-class' : 'hudson.slaves.JNLPLauncher' } }) } - - self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params))) + + self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params))) if not self.node_exists(name): raise JenkinsException('create[%s] failed'%(name))