Add function to get running builds

It can be useful to get a list of running builds from jenkins. This is
particularly useful when you need to take an action on a specific built
or if you need to know when the jenkins master has finished running all
builds (say after quieting down). Add a function to return this list.

Change-Id: I5c7dac8076250f94cd2b358c5b153d9410f53aee
This commit is contained in:
Clark Boylan 2015-09-14 13:15:36 -07:00
parent f763f5c703
commit f80e54b4bc
3 changed files with 225 additions and 1 deletions

View File

@ -22,6 +22,7 @@ the things you can use it for:
* Get information on nodes
* Create/delete/reconfig views
* Put server in shutdown mode (quiet down)
* List running builds
* and many more..
To install::

View File

@ -57,7 +57,7 @@ import six
from six.moves.http_client import BadStatusLine
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError
from six.moves.urllib.parse import quote, urlencode, urljoin
from six.moves.urllib.parse import quote, urlencode, urljoin, urlparse
from six.moves.urllib.request import Request, urlopen
if sys.version_info < (2, 7, 0):
@ -726,6 +726,46 @@ class Jenkins(object):
self.jenkins_open(Request(
self._build_url(STOP_BUILD, locals()), b''))
def get_running_builds(self):
'''Return list of running builds.
Each build is a dict with keys 'name', 'number', 'url', 'node',
and 'executor'.
:returns: List of builds,
``[ { str: str, str: int, str:str, str: str, str: int} ]``
Example::
>>> builds = server.get_running_builds()
>>> print(builds)
[{'node': 'foo-slave', 'url': 'https://localhost/job/test/15/',
'executor': 0, 'name': 'test', 'number': 15}]
'''
builds = []
nodes = self.get_nodes()
for node in nodes:
# the name returned is not the name to lookup when
# dealing with master :/
if node['name'] == 'master':
node_name = '(master)'
else:
node_name = node['name']
info = self.get_node_info(node_name, depth=2)
for executor in info['executors']:
executable = executor['currentExecutable']
if executable:
executor_number = executor['number']
build_number = executable['number']
url = executable['url']
m = re.match(r'/job/([^/]+)/.*', urlparse(url).path)
job_name = m.group(1)
builds.append({'name': job_name,
'number': build_number,
'url': url,
'node': node_name,
'executor': executor_number})
return builds
def get_nodes(self):
'''Get a list of nodes connected to the Master

View File

@ -127,3 +127,186 @@ class JenkinsStopBuildTest(JenkinsTestBase):
jenkins_mock.call_args[0][0].get_full_url(),
u'http://example.com/job/Test%20Job/52/stop')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsListRunningBuildsTest(JenkinsTestBase):
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_builds_master(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "master", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
build = {
"actions": [
{
"parameters": [
{
"name": "FOO",
"value": "foo"
},
{
"name": "BAR",
"value": "bar"
}
]
},
{
"causes": [
{
"shortDescription": "Started by user foo",
"userId": "foo",
"userName": "Foo Bar"
}
]
}
],
"artifacts": [],
"building": True,
"description": None,
"duration": 0,
"estimatedDuration": 20148,
"executor": {},
"fullDisplayName": "test #1",
"id": "2015-09-14_20-25-42",
"keepLog": False,
"number": 1,
"result": None,
"timestamp": 1442262342729,
"url": "https://localhost/job/test/1/",
"builtOn": "",
"changeSet": {
"items": [],
"kind": None
},
"culprits": []
}
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 0,
"progress": -1
},
{
"currentExecutable": build,
"currentWorkUnit": {},
"idle": False,
"likelyStuck": False,
"number": 1,
"progress": 14
}
],
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([{'name': 'test',
'number': 1,
'node': '(master)',
'executor': 1,
'url': 'https://localhost/job/test/1/'}], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_builds_non_master(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "foo-slave", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
build = {
"actions": [
{
"parameters": [
{
"name": "FOO",
"value": "foo"
},
{
"name": "BAR",
"value": "bar"
}
]
},
{
"causes": [
{
"shortDescription": "Started by user foo",
"userId": "foo",
"userName": "Foo Bar"
}
]
}
],
"artifacts": [],
"building": True,
"description": None,
"duration": 0,
"estimatedDuration": 20148,
"executor": {},
"fullDisplayName": "test #1",
"id": "2015-09-14_20-25-42",
"keepLog": False,
"number": 15,
"result": None,
"timestamp": 1442262342729,
"url": "https://localhost/job/test/15/",
"builtOn": "",
"changeSet": {
"items": [],
"kind": None
},
"culprits": []
}
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 1,
"progress": -1
},
{
"currentExecutable": build,
"currentWorkUnit": {},
"idle": False,
"likelyStuck": False,
"number": 0,
"progress": 14
}
],
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([{'name': 'test',
'number': 15,
'node': 'foo-slave',
'executor': 0,
'url': 'https://localhost/job/test/15/'}], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_no_builds(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "master", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 0,
"progress": -1
}
]
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([], builds)