diff --git a/jenkins_jobs/modules/wrappers.py b/jenkins_jobs/modules/wrappers.py index e0a6bb371..8579b10b9 100644 --- a/jenkins_jobs/modules/wrappers.py +++ b/jenkins_jobs/modules/wrappers.py @@ -24,11 +24,16 @@ Wrappers can alter the way the build is run as well as the build output. import logging import xml.etree.ElementTree as XML +import pkg_resources import jenkins_jobs.modules.base -from jenkins_jobs.errors import JenkinsJobsException +from jenkins_jobs.errors import (JenkinsJobsException, InvalidAttributeError) from jenkins_jobs.modules.builders import create_builders from jenkins_jobs.modules.helpers import config_file_provider_builder +logger = logging.getLogger(__name__) + +MIN_TO_SEC = 60 + def ci_skip(parser, xml_parent, data): """yaml: ci-skip @@ -129,50 +134,153 @@ def timeout(parser, xml_parent, data): `. :arg bool fail: Mark the build as failed (default false) + :arg bool abort: Mark the build as aborted (default false) :arg bool write-description: Write a message in the description (default false) :arg int timeout: Abort the build after this number of minutes (default 3) :arg str timeout-var: Export an environment variable to reference the timeout value (optional) :arg str type: Timeout type to use (default absolute) - :arg int elastic-percentage: Percentage of the three most recent builds - where to declare a timeout (default 0) - :arg int elastic-default-timeout: Timeout to use if there were no previous - builds (default 3) - :type values: - * **likely-stuck** - * **elastic** - * **absolute** + * **likely-stuck** + * **no-activity** + * **elastic** + * **absolute** - Example: + :arg int elastic-percentage: Percentage of the three most recent builds + where to declare a timeout, only applies to **elastic** type. + (default 0) + :arg int elastic-number-builds: Number of builds to consider computing + average duration, only applies to **elastic** type. (default 3) + :arg int elastic-default-timeout: Timeout to use if there were no previous + builds, only applies to **elastic** type. (default 3) - .. literalinclude:: /../../tests/wrappers/fixtures/timeout001.yaml + Example (Version < 1.14): - .. literalinclude:: /../../tests/wrappers/fixtures/timeout002.yaml + .. literalinclude:: /../../tests/wrappers/fixtures/timeout/timeout001.yaml + + .. literalinclude:: /../../tests/wrappers/fixtures/timeout/timeout002.yaml + + .. literalinclude:: /../../tests/wrappers/fixtures/timeout/timeout003.yaml + + Example (Version >= 1.14): + + .. literalinclude:: + /../../tests/wrappers/fixtures/timeout/version-1.14/absolute001.yaml + + .. literalinclude:: + /../../tests/wrappers/fixtures/timeout/version-1.14/no-activity001.yaml + + .. literalinclude:: + /../../tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.yaml + + .. literalinclude:: + /../../tests/wrappers/fixtures/timeout/version-1.14/elastic001.yaml - .. literalinclude:: /../../tests/wrappers/fixtures/timeout003.yaml """ - twrapper = XML.SubElement(xml_parent, - 'hudson.plugins.build__timeout.' - 'BuildTimeoutWrapper') - XML.SubElement(twrapper, 'timeoutMinutes').text = str( - data.get('timeout', 3)) - timeout_env_var = data.get('timeout-var') - if timeout_env_var: - XML.SubElement(twrapper, 'timeoutEnvVar').text = str(timeout_env_var) - XML.SubElement(twrapper, 'failBuild').text = str( - data.get('fail', 'false')).lower() - XML.SubElement(twrapper, 'writingDescription').text = str( - data.get('write-description', 'false')).lower() - XML.SubElement(twrapper, 'timeoutPercentage').text = str( - data.get('elastic-percentage', 0)) - XML.SubElement(twrapper, 'timeoutMinutesElasticDefault').text = str( - data.get('elastic-default-timeout', 3)) - tout_type = str(data.get('type', 'absolute')).lower() - if tout_type == 'likely-stuck': - tout_type = 'likelyStuck' - XML.SubElement(twrapper, 'timeoutType').text = tout_type + prefix = 'hudson.plugins.build__timeout.' + twrapper = XML.SubElement(xml_parent, prefix + 'BuildTimeoutWrapper') + + plugin_info = parser.registry.get_plugin_info( + "Jenkins build timeout plugin") + version = pkg_resources.parse_version(plugin_info.get("version", "0")) + + valid_strategies = ['absolute', 'no-activity', 'likely-stuck', 'elastic'] + + if version >= pkg_resources.parse_version("1.14"): + strategy = data.get('type', 'absolute') + if strategy not in valid_strategies: + InvalidAttributeError('type', strategy, valid_strategies) + + if strategy == "absolute": + strategy_element = XML.SubElement( + twrapper, 'strategy', + {'class': "hudson.plugins.build_timeout." + "impl.AbsoluteTimeOutStrategy"}) + XML.SubElement(strategy_element, 'timeoutMinutes' + ).text = str(data.get('timeout', 3)) + elif strategy == "no-activity": + strategy_element = XML.SubElement( + twrapper, 'strategy', + {'class': "hudson.plugins.build_timeout." + "impl.NoActivityTimeOutStrategy"}) + timeout_sec = int(data.get('timeout', 3)) * MIN_TO_SEC + XML.SubElement(strategy_element, + 'timeoutSecondsString').text = str(timeout_sec) + elif strategy == "likely-stuck": + strategy_element = XML.SubElement( + twrapper, 'strategy', + {'class': "hudson.plugins.build_timeout." + "impl.LikelyStuckTimeOutStrategy"}) + XML.SubElement(strategy_element, + 'timeoutMinutes').text = str(data.get('timeout', 3)) + elif strategy == "elastic": + strategy_element = XML.SubElement( + twrapper, 'strategy', + {'class': "hudson.plugins.build_timeout." + "impl.ElasticTimeOutStrategy"}) + XML.SubElement(strategy_element, 'timeoutPercentage' + ).text = str(data.get('elastic-percentage', 0)) + XML.SubElement(strategy_element, 'numberOfBuilds' + ).text = str(data.get('elastic-number-builds', 0)) + XML.SubElement(strategy_element, 'timeoutMinutesElasticDefault' + ).text = str(data.get('elastic-default-timeout', 3)) + + actions = [] + + for action in ['fail', 'abort']: + if str(data.get(action, 'false')).lower() == 'true': + actions.append(action) + + # Set the default action to "abort" + if len(actions) == 0: + actions.append("abort") + + description = data.get('write-description', None) + if description is not None: + actions.append('write-description') + + operation_list = XML.SubElement(twrapper, 'operationList') + + for action in actions: + fmt_str = prefix + "operations.{0}Operation" + if action == "abort": + XML.SubElement(operation_list, fmt_str.format("Abort")) + elif action == "fail": + XML.SubElement(operation_list, fmt_str.format("Fail")) + elif action == "write-description": + write_description = XML.SubElement( + operation_list, fmt_str.format("WriteDescription")) + XML.SubElement(write_description, "description" + ).text = description + else: + raise JenkinsJobsException("Unsupported BuiltTimeoutWrapper " + "plugin action: {0}".format(action)) + timeout_env_var = data.get('timeout-var') + if timeout_env_var: + XML.SubElement(twrapper, + 'timeoutEnvVar').text = str(timeout_env_var) + else: + XML.SubElement(twrapper, + 'timeoutMinutes').text = str(data.get('timeout', 3)) + timeout_env_var = data.get('timeout-var') + if timeout_env_var: + XML.SubElement(twrapper, + 'timeoutEnvVar').text = str(timeout_env_var) + XML.SubElement(twrapper, 'failBuild' + ).text = str(data.get('fail', 'false')).lower() + XML.SubElement(twrapper, 'writingDescription' + ).text = str(data.get('write-description', 'false') + ).lower() + XML.SubElement(twrapper, 'timeoutPercentage' + ).text = str(data.get('elastic-percentage', 0)) + XML.SubElement(twrapper, 'timeoutMinutesElasticDefault' + ).text = str(data.get('elastic-default-timeout', 3)) + + tout_type = str(data.get('type', 'absolute')).lower() + if tout_type == 'likely-stuck': + tout_type = 'likelyStuck' + XML.SubElement(twrapper, 'timeoutType').text = tout_type def timestamps(parser, xml_parent, data): diff --git a/tests/wrappers/fixtures/timeout001.xml b/tests/wrappers/fixtures/timeout/timeout001.xml similarity index 97% rename from tests/wrappers/fixtures/timeout001.xml rename to tests/wrappers/fixtures/timeout/timeout001.xml index 34e0e287e..8e6fbd82c 100644 --- a/tests/wrappers/fixtures/timeout001.xml +++ b/tests/wrappers/fixtures/timeout/timeout001.xml @@ -11,4 +11,4 @@ absolute - \ No newline at end of file + diff --git a/tests/wrappers/fixtures/timeout001.yaml b/tests/wrappers/fixtures/timeout/timeout001.yaml similarity index 100% rename from tests/wrappers/fixtures/timeout001.yaml rename to tests/wrappers/fixtures/timeout/timeout001.yaml diff --git a/tests/wrappers/fixtures/timeout002.xml b/tests/wrappers/fixtures/timeout/timeout002.xml similarity index 100% rename from tests/wrappers/fixtures/timeout002.xml rename to tests/wrappers/fixtures/timeout/timeout002.xml diff --git a/tests/wrappers/fixtures/timeout002.yaml b/tests/wrappers/fixtures/timeout/timeout002.yaml similarity index 100% rename from tests/wrappers/fixtures/timeout002.yaml rename to tests/wrappers/fixtures/timeout/timeout002.yaml diff --git a/tests/wrappers/fixtures/timeout003.xml b/tests/wrappers/fixtures/timeout/timeout003.xml similarity index 97% rename from tests/wrappers/fixtures/timeout003.xml rename to tests/wrappers/fixtures/timeout/timeout003.xml index c62d6ea73..727d9a33f 100644 --- a/tests/wrappers/fixtures/timeout003.xml +++ b/tests/wrappers/fixtures/timeout/timeout003.xml @@ -11,4 +11,4 @@ elastic - \ No newline at end of file + diff --git a/tests/wrappers/fixtures/timeout003.yaml b/tests/wrappers/fixtures/timeout/timeout003.yaml similarity index 100% rename from tests/wrappers/fixtures/timeout003.yaml rename to tests/wrappers/fixtures/timeout/timeout003.yaml diff --git a/tests/wrappers/fixtures/timeout/version-1.14/absolute001.plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.plugins_info.yaml new file mode 120000 index 000000000..31c7817b9 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.plugins_info.yaml @@ -0,0 +1 @@ +plugins_info.yaml \ No newline at end of file diff --git a/tests/wrappers/fixtures/timeout/version-1.14/absolute001.xml b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.xml new file mode 100644 index 000000000..cbbb0d351 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.xml @@ -0,0 +1,14 @@ + + + + + + 90 + + + + + BUILD_TIMEOUT + + + diff --git a/tests/wrappers/fixtures/timeout/version-1.14/absolute001.yaml b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.yaml new file mode 100644 index 000000000..0d286ab5e --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/absolute001.yaml @@ -0,0 +1,6 @@ +wrappers: + - timeout: + timeout: 90 + timeout-var: 'BUILD_TIMEOUT' + fail: true + type: absolute diff --git a/tests/wrappers/fixtures/timeout/version-1.14/elastic001.plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.plugins_info.yaml new file mode 120000 index 000000000..31c7817b9 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.plugins_info.yaml @@ -0,0 +1 @@ +plugins_info.yaml \ No newline at end of file diff --git a/tests/wrappers/fixtures/timeout/version-1.14/elastic001.xml b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.xml new file mode 100644 index 000000000..b1011d542 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.xml @@ -0,0 +1,16 @@ + + + + + + 150 + 14 + 3 + + + + + BUILD_TIMEOUT + + + diff --git a/tests/wrappers/fixtures/timeout/version-1.14/elastic001.yaml b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.yaml new file mode 100644 index 000000000..52962cf9c --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/elastic001.yaml @@ -0,0 +1,8 @@ +wrappers: + - timeout: + elastic-percentage: 150 + elastic-default-timeout: 3 + elastic-number-builds: 14 + timeout-var: 'BUILD_TIMEOUT' + abort: true + type: elastic diff --git a/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.plugins_info.yaml new file mode 120000 index 000000000..31c7817b9 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.plugins_info.yaml @@ -0,0 +1 @@ +plugins_info.yaml \ No newline at end of file diff --git a/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.xml b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.xml new file mode 100644 index 000000000..3a2d38ede --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.xml @@ -0,0 +1,14 @@ + + + + + + 90 + + + + + BUILD_TIMEOUT + + + diff --git a/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.yaml b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.yaml new file mode 100644 index 000000000..a09dcd80a --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/likely-stuck001.yaml @@ -0,0 +1,6 @@ +wrappers: + - timeout: + timeout: 90 + timeout-var: 'BUILD_TIMEOUT' + abort: true + type: likely-stuck diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-action001.plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.plugins_info.yaml new file mode 120000 index 000000000..31c7817b9 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.plugins_info.yaml @@ -0,0 +1 @@ +plugins_info.yaml \ No newline at end of file diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-action001.xml b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.xml new file mode 100644 index 000000000..b24b96890 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.xml @@ -0,0 +1,14 @@ + + + + + + 90 + + + + + BUILD_TIMEOUT + + + diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-action001.yaml b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.yaml new file mode 100644 index 000000000..eb320f557 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-action001.yaml @@ -0,0 +1,5 @@ +wrappers: + - timeout: + timeout: 90 + timeout-var: 'BUILD_TIMEOUT' + type: absolute diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.plugins_info.yaml new file mode 120000 index 000000000..31c7817b9 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.plugins_info.yaml @@ -0,0 +1 @@ +plugins_info.yaml \ No newline at end of file diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.xml b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.xml new file mode 100644 index 000000000..ff6ffa6b6 --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.xml @@ -0,0 +1,17 @@ + + + + + + 300 + + + + + Blah Blah Blah + + + BUILD_TIMEOUT + + + diff --git a/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.yaml b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.yaml new file mode 100644 index 000000000..76141246c --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/no-activity001.yaml @@ -0,0 +1,7 @@ +wrappers: + - timeout: + timeout: 5 + timeout-var: 'BUILD_TIMEOUT' + type: no-activity + abort: true + write-description: "Blah Blah Blah" diff --git a/tests/wrappers/fixtures/timeout/version-1.14/plugins_info.yaml b/tests/wrappers/fixtures/timeout/version-1.14/plugins_info.yaml new file mode 100644 index 000000000..618c6beaf --- /dev/null +++ b/tests/wrappers/fixtures/timeout/version-1.14/plugins_info.yaml @@ -0,0 +1,3 @@ +- longName: 'Jenkins build timeout plugin' + shortName: 'build-timeout' + version: "1.14"