From: Joao Vale Date: Fri, 24 Jan 2014 20:53:46 +0000 (+0000) Subject: Add support for Job Folders (CloudBees Folders Plugin). X-Git-Tag: v0.2.23~45^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e284cdad4f2c38ba817705600815984d2c15ddfc;p=tools%2Fpython-jenkinsapi.git Add support for Job Folders (CloudBees Folders Plugin). --- diff --git a/jenkinsapi/jenkinsbase.py b/jenkinsapi/jenkinsbase.py index bc5624b..8b6f321 100644 --- a/jenkinsapi/jenkinsbase.py +++ b/jenkinsapi/jenkinsbase.py @@ -53,6 +53,8 @@ class JenkinsBase(object): def poll(self): self._data = self._poll() + if 'jobs' in self._data: + self._data['jobs'] = self.resolve_job_folders(self._data['jobs']) def _poll(self): url = self.python_api_url(self.baseurl) @@ -67,6 +69,26 @@ class JenkinsBase(object): log.exception('Inappropriate content found at %s', url) raise JenkinsAPIException('Cannot parse %s' % response.content) + def resolve_job_folders(self, jobs): + for job in jobs: + if 'color' not in job.keys(): + jobs.remove(job) + jobs += self.process_job_folder(job) + + return jobs + + def process_job_folder(self, folder): + data = self.get_data(self.python_api_url(folder['url'])) + result = [] + + for job in data.get('jobs', []): + if 'color' not in job.keys(): + result += self.process_job_folder(job) + else: + result.append(job) + + return result + @classmethod def python_api_url(cls, url): if url.endswith(config.JENKINS_API): diff --git a/jenkinsapi_tests/unittests/test_job_folders.py b/jenkinsapi_tests/unittests/test_job_folders.py new file mode 100644 index 0000000..a23c4d8 --- /dev/null +++ b/jenkinsapi_tests/unittests/test_job_folders.py @@ -0,0 +1,191 @@ +import mock +import unittest + +from jenkinsapi.jenkins import JenkinsBase + + +class TestJobFolders(unittest.TestCase): + def setUp(self): + self.jb = JenkinsBase('http://localhost:8080/', poll=False) + + @mock.patch('jenkinsapi.jenkins.JenkinsBase.resolve_job_folders') + @mock.patch('jenkinsapi.jenkins.JenkinsBase._poll') + def test_called_in__poll(self, _poll_mock, resolve_job_folders_mock): + _poll_mock.return_value = { + 'description': "My jobs", + 'jobs': [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + ], + 'name': "All", + 'property': [], + 'url': "http://localhost:8080/view/All/", + } + + self.jb.poll() + + resolve_job_folders_mock.assert_called_once_with( + [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + ], + ) + + def test_no_folders(self): + jobs = [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Bar", + 'color': "disabled", + }, + ] + + self.assertEquals( + self.jb.resolve_job_folders(jobs), + [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Bar", + 'color': "disabled", + }, + ] + ) + + @mock.patch('jenkinsapi.jenkins.JenkinsBase.get_data') + def test_empty_folder(self, get_data_mock): + get_data_mock.return_value = {'jobs': []} + jobs = [ + { + 'name': "Folder1", + 'url': "http://localhost:8080/job/Folder1", + }, + ] + + self.assertEquals(self.jb.resolve_job_folders(jobs), []) + get_data_mock.assert_called_once_with('http://localhost:8080/job/Folder1/api/python') + + @mock.patch('jenkinsapi.jenkins.JenkinsBase.get_data') + def test_folder_job_mix(self, get_data_mock): + get_data_mock.return_value = {'jobs': [ + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Folder1/job/Bar", + 'color': "disabled", + }, + ] + } + jobs = [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Folder1", + 'url': "http://localhost:8080/job/Folder1", + }, + ] + + self.assertEquals( + self.jb.resolve_job_folders(jobs), + [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Folder1/job/Bar", + 'color': "disabled", + }, + ] + ) + get_data_mock.assert_called_once_with('http://localhost:8080/job/Folder1/api/python') + + @mock.patch('jenkinsapi.jenkins.JenkinsBase.get_data') + def test_multiple_folder_levels(self, get_data_mock): + get_data_mock.side_effect = [ + # first call + { + 'jobs': [ + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Folder1/job/Bar", + 'color': "disabled", + }, + { + 'name': "Folder2", + 'url': "http://localhost:8080/job/Folder1/job/Folder2", + }, + ] + }, + + # second call + { + 'jobs': [ + { + 'name': "Baz", + 'url': "http://localhost:8080/job/Folder1/job/Folder2/job/Baz", + 'color': "disabled", + }, + ] + }, + ] + + jobs = [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Folder1", + 'url': "http://localhost:8080/job/Folder1", + }, + ] + + self.assertEquals( + self.jb.resolve_job_folders(jobs), + [ + { + 'name': "Foo", + 'url': "http://localhost:8080/job/Foo", + 'color': "blue", + }, + { + 'name': "Bar", + 'url': "http://localhost:8080/job/Folder1/job/Bar", + 'color': "disabled", + }, + { + 'name': "Baz", + 'url': "http://localhost:8080/job/Folder1/job/Folder2/job/Baz", + 'color': "disabled", + }, + ] + ) + + self.assertEquals( + get_data_mock.call_args_list, + [ + mock.call('http://localhost:8080/job/Folder1/api/python'), + mock.call('http://localhost:8080/job/Folder1/job/Folder2/api/python'), + ] + ) diff --git a/jenkinsapi_tests/unittests/test_queue.py b/jenkinsapi_tests/unittests/test_queue.py index ad0da6c..8afaea1 100644 --- a/jenkinsapi_tests/unittests/test_queue.py +++ b/jenkinsapi_tests/unittests/test_queue.py @@ -29,6 +29,7 @@ class TestQueue(unittest.TestCase): 'jobs': [ { 'name': 'utmebvpxrw', + 'color': 'blue', 'url': 'http://localhost/job/utmebvpxrw' } ]