From 3faf544887f1c28f18869d556e28a0c9385cfb15 Mon Sep 17 00:00:00 2001 From: Philippe Godin Date: Tue, 28 Jan 2014 09:07:18 -0500 Subject: [PATCH] Add best and worst status details for conditional-step plugin. In order for the conditional step plugin to work properly, a more detailed status is required otherwise the current build status is not evaluated properly and is set to SUCCESS in all cases. A local mapping of the java hudson.model.Result class was created to unify build statuses names, ordinal and color scheme. Change-Id: If8a0090b7cd51551ef6756361f6e45af3df1218d --- jenkins_jobs/modules/builders.py | 88 ++++++++++++------- jenkins_jobs/modules/hudson_model.py | 56 ++++++++++++ jenkins_jobs/modules/project_matrix.py | 2 +- jenkins_jobs/modules/publishers.py | 35 +++----- jenkins_jobs/modules/wrappers.py | 6 +- .../conditional-step-notbuild-aborted.xml | 25 ++++++ .../conditional-step-notbuild-aborted.yaml | 7 ++ .../conditional-step-success-failure.xml | 25 ++++++ .../conditional-step-success-failure.yaml | 7 ++ .../conditional-step-success-unstable.xml | 25 ++++++ .../conditional-step-success-unstable.yaml | 7 ++ tests/builders/fixtures/trigger-builds001.xml | 2 +- tests/publishers/fixtures/trigger_success.xml | 13 +++ .../publishers/fixtures/trigger_success.yaml | 4 + 14 files changed, 238 insertions(+), 64 deletions(-) create mode 100644 jenkins_jobs/modules/hudson_model.py create mode 100644 tests/builders/fixtures/conditional-step-notbuild-aborted.xml create mode 100644 tests/builders/fixtures/conditional-step-notbuild-aborted.yaml create mode 100644 tests/builders/fixtures/conditional-step-success-failure.xml create mode 100644 tests/builders/fixtures/conditional-step-success-failure.yaml create mode 100644 tests/builders/fixtures/conditional-step-success-unstable.xml create mode 100644 tests/builders/fixtures/conditional-step-success-unstable.yaml create mode 100644 tests/publishers/fixtures/trigger_success.xml create mode 100644 tests/publishers/fixtures/trigger_success.yaml diff --git a/jenkins_jobs/modules/builders.py b/jenkins_jobs/modules/builders.py index 03e8f9ff6..bfd974c16 100644 --- a/jenkins_jobs/modules/builders.py +++ b/jenkins_jobs/modules/builders.py @@ -39,6 +39,7 @@ Example:: import xml.etree.ElementTree as XML import jenkins_jobs.modules.base +from jenkins_jobs.modules import hudson_model from jenkins_jobs.errors import JenkinsJobsException import logging @@ -271,15 +272,9 @@ def trigger_builds(parser, xml_parent, data): :arg bool block: whether to wait for the triggered jobs to finish or not (default false) - Example:: - - builders: - - trigger-builds: - - project: "build_started" - predefined-parameters: - FOO="bar" - block: true + Example: + .. literalinclude:: /../../tests/builders/fixtures/trigger-builds001.yaml """ tbuilder = XML.SubElement(xml_parent, 'hudson.plugins.parameterizedtrigger.' @@ -323,17 +318,26 @@ def trigger_builds(parser, xml_parent, data): if(block): block = XML.SubElement(tconfig, 'block') bsft = XML.SubElement(block, 'buildStepFailureThreshold') - XML.SubElement(bsft, 'name').text = 'FAILURE' - XML.SubElement(bsft, 'ordinal').text = '2' - XML.SubElement(bsft, 'color').text = 'RED' + XML.SubElement(bsft, 'name').text = \ + hudson_model.FAILURE['name'] + XML.SubElement(bsft, 'ordinal').text = \ + hudson_model.FAILURE['ordinal'] + XML.SubElement(bsft, 'color').text = \ + hudson_model.FAILURE['color'] ut = XML.SubElement(block, 'unstableThreshold') - XML.SubElement(ut, 'name').text = 'UNSTABLE' - XML.SubElement(ut, 'ordinal').text = '1' - XML.SubElement(ut, 'color').text = 'Yellow' + XML.SubElement(ut, 'name').text = \ + hudson_model.UNSTABLE['name'] + XML.SubElement(ut, 'ordinal').text = \ + hudson_model.UNSTABLE['ordinal'] + XML.SubElement(ut, 'color').text = \ + hudson_model.UNSTABLE['color'] ft = XML.SubElement(block, 'failureThreshold') - XML.SubElement(ft, 'name').text = 'FAILURE' - XML.SubElement(ft, 'ordinal').text = '2' - XML.SubElement(ft, 'color').text = 'RED' + XML.SubElement(ft, 'name').text = \ + hudson_model.FAILURE['name'] + XML.SubElement(ft, 'ordinal').text = \ + hudson_model.FAILURE['ordinal'] + XML.SubElement(ft, 'color').text = \ + hudson_model.FAILURE['color'] # If configs is empty, remove the entire tbuilder tree. if(len(configs) == 0): logger.debug("Pruning empty TriggerBuilder tree.") @@ -568,7 +572,8 @@ def create_builders(parser, step): def conditional_step(parser, xml_parent, data): """yaml: conditional-step Conditionaly execute some build steps. Requires the Jenkins `Conditional - BuildStep Plugin`_. + BuildStep Plugin `_. Depending on the number of declared steps, a `Conditional step (single)` or a `Conditional steps (multiple)` is created in Jenkins. @@ -597,8 +602,11 @@ def conditional_step(parser, xml_parent, data): current-status Run the build step if the current build status is within the configured range - :condition-worst: Worst status - :condition-best: Best status + :condition-worst: Accepted values are SUCCESS, + UNSTABLE, FAILURE, NOT_BUILD, ABORTED + :condition-best: Accepted values are SUCCESS, + UNSTABLE, FAILURE, NOT_BUILD, ABORTED + shell Run the step if the shell command succeed :condition-command: Shell command to execute @@ -615,20 +623,11 @@ def conditional_step(parser, xml_parent, data): or `jenkins-home`. Default is `workspace`. ================== ==================================================== - Example:: + Example: - builders: - - conditional-step: - condition-kind: boolean-expression - condition-expression: "${ENV,var=IS_STABLE_BRANCH}" - on-evaluation-failure: mark-unstable - steps: - - shell: "echo Making extra checks" - - .. _Conditional BuildStep Plugin: https://wiki.jenkins-ci.org/display/ - JENKINS/Conditional+BuildStep+Plugin + .. literalinclude:: \ + /../../tests/builders/fixtures/conditional-step-success-failure.yaml """ - def build_condition(cdata): kind = cdata['condition-kind'] ctag = XML.SubElement(root_tag, condition_tag) @@ -648,9 +647,30 @@ def conditional_step(parser, xml_parent, data): 'org.jenkins_ci.plugins.run_condition.core.' 'StatusCondition') wr = XML.SubElement(ctag, 'worstResult') - XML.SubElement(wr, "name").text = cdata['condition-worst'] + wr_name = cdata['condition-worst'] + if wr_name not in hudson_model.THRESHOLDS: + raise JenkinsJobsException( + "threshold must be one of %s" % + ", ".join(hudson_model.THRESHOLDS.keys())) + wr_threshold = hudson_model.THRESHOLDS[wr_name] + XML.SubElement(wr, "name").text = wr_threshold['name'] + XML.SubElement(wr, "ordinal").text = wr_threshold['ordinal'] + XML.SubElement(wr, "color").text = wr_threshold['color'] + XML.SubElement(wr, "completeBuild").text = \ + str(wr_threshold['complete']).lower() + br = XML.SubElement(ctag, 'bestResult') - XML.SubElement(br, "name").text = cdata['condition-best'] + br_name = cdata['condition-best'] + if not br_name in hudson_model.THRESHOLDS: + raise JenkinsJobsException( + "threshold must be one of %s" % + ", ".join(hudson_model.THRESHOLDS.keys())) + br_threshold = hudson_model.THRESHOLDS[br_name] + XML.SubElement(br, "name").text = br_threshold['name'] + XML.SubElement(br, "ordinal").text = br_threshold['ordinal'] + XML.SubElement(br, "color").text = br_threshold['color'] + XML.SubElement(br, "completeBuild").text = \ + str(wr_threshold['complete']).lower() elif kind == "shell": ctag.set('class', 'org.jenkins_ci.plugins.run_condition.contributed.' diff --git a/jenkins_jobs/modules/hudson_model.py b/jenkins_jobs/modules/hudson_model.py new file mode 100644 index 000000000..3f33a38d6 --- /dev/null +++ b/jenkins_jobs/modules/hudson_model.py @@ -0,0 +1,56 @@ +# 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. + +# Representation of the hudson.model.Result class + +SUCCESS = { + 'name': 'SUCCESS', + 'ordinal': '0', + 'color': 'BLUE', + 'complete': True +} + +UNSTABLE = { + 'name': 'UNSTABLE', + 'ordinal': '1', + 'color': 'YELLOW', + 'complete': True +} + +FAILURE = { + 'name': 'FAILURE', + 'ordinal': '2', + 'color': 'RED', + 'complete': True +} + +NOTBUILD = { + 'name': 'NOT_BUILD', + 'ordinal': '3', + 'color': 'NOTBUILD', + 'complete': False +} + +ABORTED = { + 'name': 'ABORTED', + 'ordinal': '4', + 'color': 'ABORTED', + 'complete': False +} + +THRESHOLDS = { + 'SUCCESS': SUCCESS, + 'UNSTABLE': UNSTABLE, + 'FAILURE': FAILURE, + 'NOT_BUILD': NOTBUILD, + 'ABORTED': ABORTED +} diff --git a/jenkins_jobs/modules/project_matrix.py b/jenkins_jobs/modules/project_matrix.py index b1ae09c92..493b246d3 100644 --- a/jenkins_jobs/modules/project_matrix.py +++ b/jenkins_jobs/modules/project_matrix.py @@ -110,7 +110,7 @@ class Matrix(jenkins_jobs.modules.base.Base): ex_r = XML.SubElement(root, 'executionStrategy', {'class': 'hudson.matrix.' - 'DefaultMatrixExecutionStrategyImpl'}) + 'DefaultMatrixExecutionStrategyImpl'}) ex_d = data.get('execution-strategy', {}) XML.SubElement(root, 'combinationFilter').text = \ str(ex_d.get('combination-filter', '')).rstrip() diff --git a/jenkins_jobs/modules/publishers.py b/jenkins_jobs/modules/publishers.py index 8d89ffd66..6b970b163 100644 --- a/jenkins_jobs/modules/publishers.py +++ b/jenkins_jobs/modules/publishers.py @@ -26,6 +26,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.errors import JenkinsJobsException import logging import sys @@ -216,42 +217,26 @@ def trigger(parser, xml_parent, data): :arg str threshold: when to trigger the other job (default 'SUCCESS'), alternatives: SUCCESS, UNSTABLE, FAILURE - Example:: + Example: - publishers: - - trigger: - project: other_job + .. literalinclude:: /../../tests/publishers/fixtures/trigger_success.yaml """ - thresholds = { - 'SUCCESS': { - 'ordinal': '0', - 'color': 'BLUE' - }, - 'UNSTABLE': { - 'ordinal': '1', - 'color': 'YELLOW' - }, - 'FAILURE': { - 'ordinal': '2', - 'color': 'RED' - } - } - tconfig = XML.SubElement(xml_parent, 'hudson.tasks.BuildTrigger') childProjects = XML.SubElement(tconfig, 'childProjects') childProjects.text = data['project'] tthreshold = XML.SubElement(tconfig, 'threshold') threshold = data.get('threshold', 'SUCCESS') - if threshold not in thresholds.keys(): + supported_thresholds = ['SUCCESS', 'UNSTABLE', 'FAILURE'] + if threshold not in supported_thresholds: raise JenkinsJobsException("threshold must be one of %s" % - ", ".join(threshold.keys())) + ", ".join(supported_thresholds)) tname = XML.SubElement(tthreshold, 'name') - tname.text = threshold + tname.text = hudson_model.THRESHOLDS[threshold]['name'] tordinal = XML.SubElement(tthreshold, 'ordinal') - tordinal.text = thresholds[threshold]['ordinal'] + tordinal.text = hudson_model.THRESHOLDS[threshold]['ordinal'] tcolor = XML.SubElement(tthreshold, 'color') - tcolor.text = thresholds[threshold]['color'] + tcolor.text = hudson_model.THRESHOLDS[threshold]['color'] def cloverphp(parser, xml_parent, data): @@ -3093,7 +3078,7 @@ def description_setter(parser, xml_parent, data): Example: .. literalinclude:: - /../../tests/publishers/fixtures/description-setter.yaml + /../../tests/publishers/fixtures/description-setter001.yaml """ diff --git a/jenkins_jobs/modules/wrappers.py b/jenkins_jobs/modules/wrappers.py index bd73c1930..4fb161d46 100644 --- a/jenkins_jobs/modules/wrappers.py +++ b/jenkins_jobs/modules/wrappers.py @@ -320,7 +320,7 @@ def rbenv(parser, xml_parent, data): XML.SubElement(o, 'ignore__local__version', {'ruby-class': ignore_local_class, - 'pluginid': 'rbenv'}) + 'pluginid': 'rbenv'}) def build_name(parser, xml_parent, data): @@ -745,7 +745,7 @@ def sauce_ondemand(parser, xml_parent, data): XML.SubElement(info, 'isWebDriver').text = 'false' XML.SubElement(sauce, 'seleniumBrowsers', {'reference': '../seleniumInformation/' - 'seleniumBrowsers'}) + 'seleniumBrowsers'}) if atype == 'webdriver': browsers = XML.SubElement(info, 'webDriverBrowsers') for platform in data['platforms']: @@ -753,7 +753,7 @@ def sauce_ondemand(parser, xml_parent, data): XML.SubElement(info, 'isWebDriver').text = 'true' XML.SubElement(sauce, 'webDriverBrowsers', {'reference': '../seleniumInformation/' - 'webDriverBrowsers'}) + 'webDriverBrowsers'}) XML.SubElement(sauce, 'launchSauceConnectOnSlave').text = str(data.get( 'launch-sauce-connect-on-slave', False)).lower() protocol = data.get('https-protocol', '') diff --git a/tests/builders/fixtures/conditional-step-notbuild-aborted.xml b/tests/builders/fixtures/conditional-step-notbuild-aborted.xml new file mode 100644 index 000000000..e7a7504a0 --- /dev/null +++ b/tests/builders/fixtures/conditional-step-notbuild-aborted.xml @@ -0,0 +1,25 @@ + + + + + + + ABORTED + 4 + ABORTED + false + + + NOT_BUILD + 3 + NOTBUILD + false + + + + + sl + + + + \ No newline at end of file diff --git a/tests/builders/fixtures/conditional-step-notbuild-aborted.yaml b/tests/builders/fixtures/conditional-step-notbuild-aborted.yaml new file mode 100644 index 000000000..8b0a2e845 --- /dev/null +++ b/tests/builders/fixtures/conditional-step-notbuild-aborted.yaml @@ -0,0 +1,7 @@ +builders: + - conditional-step: + condition-kind: current-status + condition-worst: ABORTED + condition-best: NOT_BUILD + steps: + - shell: "sl" \ No newline at end of file diff --git a/tests/builders/fixtures/conditional-step-success-failure.xml b/tests/builders/fixtures/conditional-step-success-failure.xml new file mode 100644 index 000000000..aae80f247 --- /dev/null +++ b/tests/builders/fixtures/conditional-step-success-failure.xml @@ -0,0 +1,25 @@ + + + + + + + SUCCESS + 0 + BLUE + true + + + FAILURE + 2 + RED + true + + + + + sl + + + + \ No newline at end of file diff --git a/tests/builders/fixtures/conditional-step-success-failure.yaml b/tests/builders/fixtures/conditional-step-success-failure.yaml new file mode 100644 index 000000000..b1a1288ad --- /dev/null +++ b/tests/builders/fixtures/conditional-step-success-failure.yaml @@ -0,0 +1,7 @@ +builders: + - conditional-step: + condition-kind: current-status + condition-worst: SUCCESS + condition-best: FAILURE + steps: + - shell: "sl" \ No newline at end of file diff --git a/tests/builders/fixtures/conditional-step-success-unstable.xml b/tests/builders/fixtures/conditional-step-success-unstable.xml new file mode 100644 index 000000000..177073199 --- /dev/null +++ b/tests/builders/fixtures/conditional-step-success-unstable.xml @@ -0,0 +1,25 @@ + + + + + + + UNSTABLE + 1 + YELLOW + true + + + SUCCESS + 0 + BLUE + true + + + + + sl + + + + \ No newline at end of file diff --git a/tests/builders/fixtures/conditional-step-success-unstable.yaml b/tests/builders/fixtures/conditional-step-success-unstable.yaml new file mode 100644 index 000000000..a5ea5dbb4 --- /dev/null +++ b/tests/builders/fixtures/conditional-step-success-unstable.yaml @@ -0,0 +1,7 @@ +builders: + - conditional-step: + condition-kind: current-status + condition-worst: UNSTABLE + condition-best: SUCCESS + steps: + - shell: "sl" \ No newline at end of file diff --git a/tests/builders/fixtures/trigger-builds001.xml b/tests/builders/fixtures/trigger-builds001.xml index f083ed865..fb76787d8 100644 --- a/tests/builders/fixtures/trigger-builds001.xml +++ b/tests/builders/fixtures/trigger-builds001.xml @@ -22,7 +22,7 @@ UNSTABLE 1 - Yellow + YELLOW FAILURE diff --git a/tests/publishers/fixtures/trigger_success.xml b/tests/publishers/fixtures/trigger_success.xml new file mode 100644 index 000000000..6bd2ef603 --- /dev/null +++ b/tests/publishers/fixtures/trigger_success.xml @@ -0,0 +1,13 @@ + + + + + other_job + + SUCCESS + 0 + BLUE + + + + \ No newline at end of file diff --git a/tests/publishers/fixtures/trigger_success.yaml b/tests/publishers/fixtures/trigger_success.yaml new file mode 100644 index 000000000..de14557df --- /dev/null +++ b/tests/publishers/fixtures/trigger_success.yaml @@ -0,0 +1,4 @@ +publishers: + - trigger: + project: other_job + threshold: SUCCESS