From 9b40708294135c88708a1b0e746614758c08493c Mon Sep 17 00:00:00 2001 From: mriehl Date: Wed, 25 Feb 2015 09:06:17 +0100 Subject: [PATCH] initial version of a sonarqube plugin --- .../plugins/python/sonarqube_plugin.py | 73 ++++++++++++++++ .../plugins/python/sonarqube_plugin_tests.py | 86 +++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 src/main/python/pybuilder/plugins/python/sonarqube_plugin.py create mode 100644 src/unittest/python/plugins/python/sonarqube_plugin_tests.py diff --git a/src/main/python/pybuilder/plugins/python/sonarqube_plugin.py b/src/main/python/pybuilder/plugins/python/sonarqube_plugin.py new file mode 100644 index 000000000..c1a0c786d --- /dev/null +++ b/src/main/python/pybuilder/plugins/python/sonarqube_plugin.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# This file is part of PyBuilder +# +# Copyright 2011-2015 PyBuilder Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from pybuilder.core import task, init, before, depends +from pybuilder.errors import BuildFailedException +from pybuilder.utils import assert_can_execute +from pybuilder.pluginhelper.external_command import ExternalCommandBuilder + + +@before("run_sonar_analysis") +def check_sonar_runner_availability(): + assert_can_execute( + ("sonar-runner", "-h"), + "sonar-runner", "plugin python.sonarqube") + + +@init +def initialize_sonarqube_plugin(project): + project.set_property_if_unset("sonarqube_project_key", project.name) + project.set_property_if_unset("sonarqube_project_name", project.name) + + +@task("run_sonar_analysis", description="Writes the sonar-project.properties and launches sonar-runner for analysis.") +@depends("analyze") +def run_sonar_analysis(project, logger): + + sonar_runner = build_sonar_runner(project) + + return_code = sonar_runner.run(project.expand_path("$dir_reports/sonar-runner")) + + if return_code != 0: + raise BuildFailedException( + "sonar-runner exited with code {exit_code}. See reports at {reports_dir} for more information.".format( + exit_code=return_code, + reports_dir=project.expand_path("$dir_reports"))) + + +def build_sonar_runner(project): + return (SonarCommandBuilder("sonar-runner", project) + .set_sonar_key("sonar.projectKey").to_property_value("sonarqube_project_key") + .set_sonar_key("sonar.projectName").to_property_value("sonarqube_project_name") + .set_sonar_key("sonar.projectVersion").to(project.version) + .set_sonar_key("file.sonar.sources").to_property_value("dir_source_main_python") + .set_sonar_key("sonar.python.coverage.reportPath").to(project.expand_path("$dir_reports/coverage.xml"))) + + +class SonarCommandBuilder(ExternalCommandBuilder): + + def set_sonar_key(self, key): + self.key = key + return self + + def to(self, value): + self.use_argument("-D{key}={value}".format(key=self.key, value=value)) + return self + + def to_property_value(self, property_name): + return self.to(self.project.get_property(property_name)) diff --git a/src/unittest/python/plugins/python/sonarqube_plugin_tests.py b/src/unittest/python/plugins/python/sonarqube_plugin_tests.py new file mode 100644 index 000000000..f39bdf60e --- /dev/null +++ b/src/unittest/python/plugins/python/sonarqube_plugin_tests.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# +# This file is part of PyBuilder +# +# Copyright 2011-2015 PyBuilder Team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unittest import TestCase + +from mock import Mock, patch + +from pybuilder.core import Project +from pybuilder.errors import BuildFailedException +from pybuilder.plugins.python.sonarqube_plugin import (SonarCommandBuilder, + build_sonar_runner, + run_sonar_analysis) + + +class RunSonarAnalysisTest(TestCase): + + def setUp(self): + self.project = Project("any-project") + self.project.version = "0.0.1" + self.project.set_property("sonarqube_project_key", "project_key") + self.project.set_property("sonarqube_project_name", "project_name") + self.project.set_property("dir_source_main_python", "src/main/python") + self.project.set_property("dir_reports", "target/reports") + + def test_should_build_sonar_runner_for_project(self): + self.assertEqual( + build_sonar_runner(self.project).as_string, + "sonar-runner -Dsonar.projectKey=project_key " + "-Dsonar.projectName=project_name " + "-Dsonar.projectVersion=0.0.1 " + "-Dfile.sonar.sources=src/main/python " + "-Dsonar.python.coverage.reportPath=any-project/target/reports/coverage.xml") + + @patch("pybuilder.plugins.python.sonarqube_plugin.SonarCommandBuilder.run") + def test_should_break_build_when_sonar_runner_fails(self, run_sonar_command): + run_sonar_command.return_value = 1 + + self.assertRaises(BuildFailedException, run_sonar_analysis, self.project, Mock()) + + @patch("pybuilder.plugins.python.sonarqube_plugin.SonarCommandBuilder.run") + def test_should_not_break_build_when_sonar_runner_succeeds(self, run_sonar_command): + run_sonar_command.return_value = 0 + + run_sonar_analysis(self.project, Mock()) + + +class SonarCommandBuilderTests(TestCase): + + def setUp(self): + self.project = Project("any-project") + self.project.set_property("any-property-name", "any-property-value") + self.sonar_builder = SonarCommandBuilder("sonar", self.project) + + def test_should_set_sonar_key_to_specific_value(self): + self.sonar_builder.set_sonar_key("anySonarKey").to("anyValue") + + self.assertEqual( + self.sonar_builder.as_string, + "sonar -DanySonarKey=anyValue") + + def test_should_set_sonar_key_to_two_specific_values(self): + self.sonar_builder.set_sonar_key("anySonarKey").to("anyValue").set_sonar_key("other").to("otherValue") + + self.assertEqual( + self.sonar_builder.as_string, + "sonar -DanySonarKey=anyValue -Dother=otherValue") + + def test_should_set_sonar_key_to_property_value(self): + self.sonar_builder.set_sonar_key("anySonarKey").to_property_value("any-property-name") + + self.assertEqual(self.sonar_builder.as_string, "sonar -DanySonarKey=any-property-value")