diff --git a/jenkins_jobs/modules/helpers.py b/jenkins_jobs/modules/helpers.py index b416b7ff3..e5ce23580 100644 --- a/jenkins_jobs/modules/helpers.py +++ b/jenkins_jobs/modules/helpers.py @@ -1,5 +1,87 @@ +# Copyright 2015 Thanh Ha +# +# 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. + import xml.etree.ElementTree as XML +from jenkins_jobs.errors import JenkinsJobsException + + +def build_trends_publisher(plugin_name, xml_element, data): + """Helper to create various trend publishers. + """ + + def append_thresholds(element, data, only_totals): + """Appends the status thresholds. + """ + + for status in ['unstable', 'failed']: + status_data = data.get(status, {}) + + limits = [ + ('total-all', 'TotalAll'), + ('total-high', 'TotalHigh'), + ('total-normal', 'TotalNormal'), + ('total-low', 'TotalLow')] + + if only_totals is False: + limits.extend([ + ('new-all', 'NewAll'), + ('new-high', 'NewHigh'), + ('new-normal', 'NewNormal'), + ('new-low', 'NewLow')]) + + for key, tag_suffix in limits: + tag_name = status + tag_suffix + XML.SubElement(element, tag_name).text = str( + status_data.get(key, '')) + + # Tuples containing: setting name, tag name, default value + settings = [ + ('healthy', 'healthy', ''), + ('unhealthy', 'unHealthy', ''), + ('health-threshold', 'thresholdLimit', 'low'), + ('plugin-name', 'pluginName', plugin_name), + ('default-encoding', 'defaultEncoding', ''), + ('can-run-on-failed', 'canRunOnFailed', False), + ('use-stable-build-as-reference', 'useStableBuildAsReference', False), + ('use-delta-values', 'useDeltaValues', False), + ('thresholds', 'thresholds', {}), + ('should-detect-modules', 'shouldDetectModules', False), + ('dont-compute-new', 'dontComputeNew', True), + ('do-not-resolve-relative-paths', 'doNotResolveRelativePaths', False), + ('pattern', 'pattern', '')] + + thresholds = ['low', 'normal', 'high'] + + for key, tag_name, default in settings: + xml_config = XML.SubElement(xml_element, tag_name) + config_value = data.get(key, default) + + if key == 'thresholds': + append_thresholds( + xml_config, + config_value, + data.get('dont-compute-new', True)) + elif key == 'health-threshold' and config_value not in thresholds: + raise JenkinsJobsException("health-threshold must be one of %s" % + ", ".join(thresholds)) + else: + if isinstance(default, bool): + xml_config.text = str(config_value).lower() + else: + xml_config.text = str(config_value) + def config_file_provider_settings(xml_parent, data): settings = { diff --git a/jenkins_jobs/modules/publishers.py b/jenkins_jobs/modules/publishers.py index 78ea8e5f2..d52060597 100644 --- a/jenkins_jobs/modules/publishers.py +++ b/jenkins_jobs/modules/publishers.py @@ -29,6 +29,7 @@ the build is complete. import xml.etree.ElementTree as XML import jenkins_jobs.modules.base from jenkins_jobs.modules import hudson_model +from jenkins_jobs.modules.helpers import build_trends_publisher from jenkins_jobs.errors import JenkinsJobsException import logging import sys @@ -3745,72 +3746,6 @@ def valgrind(parser, xml_parent, data): data.get('publish-if-failed', False)).lower() -def build_trends_publisher(plugin_name, xml_element, data): - """Helper to create various trend publishers. - """ - - def append_thresholds(element, data, only_totals): - """Appends the status thresholds. - """ - - for status in ['unstable', 'failed']: - status_data = data.get(status, {}) - - limits = [ - ('total-all', 'TotalAll'), - ('total-high', 'TotalHigh'), - ('total-normal', 'TotalNormal'), - ('total-low', 'TotalLow')] - - if only_totals is False: - limits.extend([ - ('new-all', 'NewAll'), - ('new-high', 'NewHigh'), - ('new-normal', 'NewNormal'), - ('new-low', 'NewLow')]) - - for key, tag_suffix in limits: - tag_name = status + tag_suffix - XML.SubElement(element, tag_name).text = str( - status_data.get(key, '')) - - # Tuples containing: setting name, tag name, default value - settings = [ - ('healthy', 'healthy', ''), - ('unhealthy', 'unHealthy', ''), - ('health-threshold', 'thresholdLimit', 'low'), - ('plugin-name', 'pluginName', plugin_name), - ('default-encoding', 'defaultEncoding', ''), - ('can-run-on-failed', 'canRunOnFailed', False), - ('use-stable-build-as-reference', 'useStableBuildAsReference', False), - ('use-delta-values', 'useDeltaValues', False), - ('thresholds', 'thresholds', {}), - ('should-detect-modules', 'shouldDetectModules', False), - ('dont-compute-new', 'dontComputeNew', True), - ('do-not-resolve-relative-paths', 'doNotResolveRelativePaths', False), - ('pattern', 'pattern', '')] - - thresholds = ['low', 'normal', 'high'] - - for key, tag_name, default in settings: - xml_config = XML.SubElement(xml_element, tag_name) - config_value = data.get(key, default) - - if key == 'thresholds': - append_thresholds( - xml_config, - config_value, - data.get('dont-compute-new', True)) - elif key == 'health-threshold' and config_value not in thresholds: - raise JenkinsJobsException("health-threshold must be one of %s" % - ", ".join(thresholds)) - else: - if isinstance(default, bool): - xml_config.text = str(config_value).lower() - else: - xml_config.text = str(config_value) - - def pmd(parser, xml_parent, data): """yaml: pmd Publish trend reports with PMD. diff --git a/jenkins_jobs/modules/reporters.py b/jenkins_jobs/modules/reporters.py index 1dfa4083a..75c6a0924 100644 --- a/jenkins_jobs/modules/reporters.py +++ b/jenkins_jobs/modules/reporters.py @@ -34,6 +34,7 @@ Example:: import xml.etree.ElementTree as XML import jenkins_jobs.modules.base +from jenkins_jobs.modules.helpers import build_trends_publisher from jenkins_jobs.errors import JenkinsJobsException @@ -69,6 +70,83 @@ def email(parser, xml_parent, data): XML.SubElement(mailer, 'perModuleEmail').text = 'true' +def findbugs(parser, xml_parent, data): + """yaml: findbugs + FindBugs reporting for builds + + Requires the Jenkins :jenkins-wiki:`FindBugs Plugin + `. + + :arg bool rank-priority: Use rank as priority (default: false) + :arg str include-files: Comma separated list of files to include. + (Optional) + :arg str exclude-files: Comma separated list of files to exclude. + (Optional) + :arg bool can-run-on-failed: Weather or not to run plug-in on failed builds + (default: false) + :arg int healthy: Sunny threshold (optional) + :arg int unhealthy: Stormy threshold (optional) + :arg str health-threshold: Threshold priority for health status + ('low', 'normal' or 'high', defaulted to 'low') + :arg bool dont-compute-new: If set to false, computes new warnings based on + the reference build (default true) + :arg bool use-delta-values: Use delta for new warnings. (Default: false) + :arg bool use-previous-build-as-reference: If set then the number of new + warnings will always be calculated based on the previous build. Otherwise + the reference build. (Default: false) + :arg bool use-stable-build-as-reference: The number of new warnings will be + calculated based on the last stable build, allowing reverts of unstable + builds where the number of warnings was decreased. (default false) + :arg dict thresholds: + :thresholds: + * **unstable** (`dict`) + :unstable: * **total-all** (`int`) + * **total-high** (`int`) + * **total-normal** (`int`) + * **total-low** (`int`) + * **new-all** (`int`) + * **new-high** (`int`) + * **new-normal** (`int`) + * **new-low** (`int`) + + * **failed** (`dict`) + :failed: * **total-all** (`int`) + * **total-high** (`int`) + * **total-normal** (`int`) + * **total-low** (`int`) + * **new-all** (`int`) + * **new-high** (`int`) + * **new-normal** (`int`) + * **new-low** (`int`) + + Minimal Example: + + .. literalinclude:: /../../tests/reporters/fixtures/findbugs-minimal.yaml + + Full Example: + + .. literalinclude:: /../../tests/reporters/fixtures/findbugs01.yaml + + """ + findbugs = XML.SubElement(xml_parent, + 'hudson.plugins.findbugs.FindBugsReporter') + findbugs.set('plugin', 'findbugs') + + # General Options + rank_priority = str(data.get('rank-priority', False)).lower() + XML.SubElement(findbugs, 'isRankActivated').text = rank_priority + include_files = data.get('include-files', '') + XML.SubElement(findbugs, 'includePattern').text = include_files + exclude_files = data.get('exclude-files', '') + XML.SubElement(findbugs, 'excludePattern').text = exclude_files + use_previous_build = str(data.get('use-previous-build-as-reference', + False)).lower() + XML.SubElement(findbugs, + 'usePreviousBuildAsReference').text = use_previous_build + + build_trends_publisher('[FINDBUGS] ', findbugs, data) + + class Reporters(jenkins_jobs.modules.base.Base): sequence = 55 diff --git a/setup.cfg b/setup.cfg index 35d83e133..3c6083561 100644 --- a/setup.cfg +++ b/setup.cfg @@ -73,6 +73,7 @@ jenkins_jobs.builders = trigger-builds=jenkins_jobs.modules.builders:trigger_builds jenkins_jobs.reporters = email=jenkins_jobs.modules.reporters:email + findbugs=jenkins_jobs.modules.reporters:findbugs jenkins_jobs.properties = authenticated-build=jenkins_jobs.modules.properties:authenticated_build authorization=jenkins_jobs.modules.properties:authorization diff --git a/tests/reporters/__init__.py b/tests/reporters/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/reporters/fixtures/findbugs-minimal.xml b/tests/reporters/fixtures/findbugs-minimal.xml new file mode 100644 index 000000000..21fa9e03d --- /dev/null +++ b/tests/reporters/fixtures/findbugs-minimal.xml @@ -0,0 +1,33 @@ + + + + + false + + + false + + + low + [FINDBUGS] + + false + false + false + + + + + + + + + + + false + true + false + + + + diff --git a/tests/reporters/fixtures/findbugs-minimal.yaml b/tests/reporters/fixtures/findbugs-minimal.yaml new file mode 100644 index 000000000..96b83ee14 --- /dev/null +++ b/tests/reporters/fixtures/findbugs-minimal.yaml @@ -0,0 +1,3 @@ +project-type: maven +reporters: + - findbugs diff --git a/tests/reporters/fixtures/findbugs01.xml b/tests/reporters/fixtures/findbugs01.xml new file mode 100644 index 000000000..2d8959734 --- /dev/null +++ b/tests/reporters/fixtures/findbugs01.xml @@ -0,0 +1,41 @@ + + + + + true + f,d,e,.* + a,c,d,.* + true + 80 + 10 + high + [FINDBUGS] + + true + true + true + + 90 + 80 + 50 + 20 + 95 + 85 + 55 + 25 + 80 + 70 + 40 + 10 + 85 + 75 + 45 + 15 + + false + false + false + + + + diff --git a/tests/reporters/fixtures/findbugs01.yaml b/tests/reporters/fixtures/findbugs01.yaml new file mode 100644 index 000000000..020ff6791 --- /dev/null +++ b/tests/reporters/fixtures/findbugs01.yaml @@ -0,0 +1,34 @@ +project-type: maven +reporters: + - findbugs: + rank-priority: true + include-files: 'f,d,e,.*' + exclude-files: 'a,c,d,.*' + can-run-on-failed: true + healthy: 80 + unhealthy: 10 + use-delta-values: true + health-threshold: 'high' + thresholds: + unstable: + total-all: 90 + total-high: 80 + total-normal: 50 + total-low: 20 + new-all: 95 + new-high: 85 + new-normal: 55 + new-low: 25 + failed: + total-all: 80 + total-high: 70 + total-normal: 40 + total-low: 10 + new-all: 85 + new-high: 75 + new-normal: 45 + new-low: 15 + dont-compute-new: false + use-delta-values: true + use-previous-build-as-reference: true + use-stable-build-as-reference: true diff --git a/tests/reporters/test_reporters.py b/tests/reporters/test_reporters.py new file mode 100644 index 000000000..497c538b5 --- /dev/null +++ b/tests/reporters/test_reporters.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# +# Copyright 2015 Thanh Ha +# +# 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. + +import os +from testtools import TestCase +from testscenarios.testcase import TestWithScenarios +from jenkins_jobs.modules import reporters +from tests.base import get_scenarios, BaseTestCase + + +class TestCaseModuleReporters(TestWithScenarios, TestCase, BaseTestCase): + fixtures_path = os.path.join(os.path.dirname(__file__), 'fixtures') + scenarios = get_scenarios(fixtures_path) + klass = reporters.Reporters