diff --git a/README.rst b/README.rst index b5364a1..6a37401 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,7 @@ the things you can use it for: * List running builds * Create/delete/update folders [#f1]_ * Set the next build number [#f2]_ +* Install plugins * and many more.. To install:: diff --git a/jenkins/__init__.py b/jenkins/__init__.py index aa29712..6826115 100644 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -51,6 +51,7 @@ import json import re import socket import sys +import time import warnings import six @@ -878,6 +879,39 @@ class Jenkins(object): return self.jenkins_open(Request(self._build_url(SCRIPT_TEXT), "script=".encode('utf-8') + script.encode('utf-8'))) + def install_plugin(self, name, include_dependencies=True): + '''Install a plugin and its dependencies from the Jenkins public + repository at http://repo.jenkins-ci.org/repo/org/jenkins-ci/plugins + + :param name: The plugin short name, ``string`` + :param include_dependencies: Install the plugin's dependencies, ``bool`` + :returns: Whether a Jenkins restart is required, ``bool`` + + Example:: + >>> info = server.install_plugin("jabber") + >>> print(info) + True + ''' + # using a groovy script because Jenkins does not provide a REST endpoint + # for installing plugins. + install = ('Jenkins.instance.updateCenter.getPlugin(\"' + name + '\")' + '.deploy();') + if include_dependencies: + install = ('Jenkins.instance.updateCenter.getPlugin(\"' + name + '\")' + '.getNeededDependencies().each{it.deploy()};') + install + + self.run_script(install) + # run_script is an async call to run groovy. we need to wait a little + # before we can get a reliable response on whether a restart is needed + time.sleep(2) + is_restart_required = ('Jenkins.instance.updateCenter' + '.isRestartRequiredForCompletion()') + + # response is a string (i.e. u'Result: true\n'), return a bool instead + response_str = self.run_script(is_restart_required) + response = response_str.split(':')[1].strip().lower() == 'true' + return response + def stop_build(self, name, number): '''Stop a running Jenkins build. diff --git a/tests/test_script.py b/tests/test_script.py index e58d8db..8829def 100644 --- a/tests/test_script.py +++ b/tests/test_script.py @@ -14,3 +14,63 @@ class JenkinsScriptTest(JenkinsTestBase): jenkins_mock.call_args[0][0].get_full_url(), u'http://example.com/scriptText') self._check_requests(jenkins_mock.call_args_list) + + @patch.object(jenkins.Jenkins, 'jenkins_open') + def test_install_plugin(self, jenkins_mock): + '''Installation of plugins is done with the run_script method + ''' + j = jenkins.Jenkins('http://example.com/', 'test', 'test') + j.install_plugin("jabber") + self.assertEqual( + jenkins_mock.call_args[0][0].get_full_url(), + u'http://example.com/scriptText') + self._check_requests(jenkins_mock.call_args_list) + + @patch.object(jenkins.Jenkins, 'jenkins_open') + @patch.object(jenkins.Jenkins, 'run_script') + def test_install_plugin_with_dependencies(self, run_script_mock, jenkins_mock): + '''Verify install plugins with dependencies + ''' + j = jenkins.Jenkins('http://example.com/', 'test', 'test') + j.install_plugin("jabber") + self.assertEqual(len(run_script_mock.call_args_list), 2) + self.assertEqual(run_script_mock.call_args_list[0][0][0], + ('Jenkins.instance.updateCenter.getPlugin(\"jabber\")' + '.getNeededDependencies().each{it.deploy()};Jenkins' + '.instance.updateCenter.getPlugin(\"jabber\").deploy();')) + self.assertEqual(run_script_mock.call_args_list[1][0][0], + ('Jenkins.instance.updateCenter' + '.isRestartRequiredForCompletion()')) + + @patch.object(jenkins.Jenkins, 'jenkins_open') + @patch.object(jenkins.Jenkins, 'run_script') + def test_install_plugin_without_dependencies(self, run_script_mock, jenkins_mock): + '''Verify install plugins without dependencies + ''' + j = jenkins.Jenkins('http://example.com/', 'test', 'test') + j.install_plugin("jabber", include_dependencies=False) + self.assertEqual(len(run_script_mock.call_args_list), 2) + self.assertEqual(run_script_mock.call_args_list[0][0][0], + ('Jenkins.instance.updateCenter' + '.getPlugin(\"jabber\").deploy();')) + self.assertEqual(run_script_mock.call_args_list[1][0][0], + ('Jenkins.instance.updateCenter' + '.isRestartRequiredForCompletion()')) + + @patch.object(jenkins.Jenkins, 'jenkins_open') + @patch.object(jenkins.Jenkins, 'run_script') + def test_install_plugin_no_restart(self, run_script_mock, jenkins_mock): + '''Verify install plugin does not need a restart + ''' + run_script_mock.return_value = u'Result: false\n' + j = jenkins.Jenkins('http://example.com/', 'test', 'test') + self.assertFalse(j.install_plugin("jabber")) + + @patch.object(jenkins.Jenkins, 'jenkins_open') + @patch.object(jenkins.Jenkins, 'run_script') + def test_install_plugin_restart(self, run_script_mock, jenkins_mock): + '''Verify install plugin needs a restart + ''' + run_script_mock.return_value = u'Result: true\n' + j = jenkins.Jenkins('http://example.com/', 'test', 'test') + self.assertTrue(j.install_plugin("jabber"))