3116 lines
126 KiB
Python
3116 lines
126 KiB
Python
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
|
# Copyright 2012 Varnish Software AS
|
|
#
|
|
# 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.
|
|
|
|
|
|
"""
|
|
Publishers define actions that the Jenkins job should perform after
|
|
the build is complete.
|
|
|
|
**Component**: publishers
|
|
:Macro: publisher
|
|
:Entry Point: jenkins_jobs.publishers
|
|
"""
|
|
|
|
|
|
import xml.etree.ElementTree as XML
|
|
import jenkins_jobs.modules.base
|
|
from jenkins_jobs.errors import JenkinsJobsException
|
|
import logging
|
|
import sys
|
|
import random
|
|
|
|
|
|
def archive(parser, xml_parent, data):
|
|
"""yaml: archive
|
|
Archive build artifacts
|
|
|
|
:arg str artifacts: path specifier for artifacts to archive
|
|
:arg str excludes: path specifier for artifacts to exclude
|
|
:arg bool latest-only: only keep the artifacts from the latest
|
|
successful build
|
|
:arg bool allow-empty: pass the build if no artifacts are
|
|
found (default false)
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: /../../tests/publishers/fixtures/archive001.yaml
|
|
|
|
"""
|
|
logger = logging.getLogger("%s:archive" % __name__)
|
|
archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver')
|
|
artifacts = XML.SubElement(archiver, 'artifacts')
|
|
artifacts.text = data['artifacts']
|
|
if 'excludes' in data:
|
|
excludes = XML.SubElement(archiver, 'excludes')
|
|
excludes.text = data['excludes']
|
|
latest = XML.SubElement(archiver, 'latestOnly')
|
|
# backward compatibility
|
|
latest_only = data.get('latest_only', False)
|
|
if 'latest_only' in data:
|
|
logger.warn('latest_only is deprecated please use latest-only')
|
|
if 'latest-only' in data:
|
|
latest_only = data['latest-only']
|
|
if latest_only:
|
|
latest.text = 'true'
|
|
else:
|
|
latest.text = 'false'
|
|
|
|
if 'allow-empty' in data:
|
|
empty = XML.SubElement(archiver, 'allowEmptyArchive')
|
|
# Default behavior is to fail the build.
|
|
empty.text = str(data.get('allow-empty', False)).lower()
|
|
|
|
|
|
def blame_upstream(parser, xml_parent, data):
|
|
"""yaml: blame-upstream
|
|
Notify upstream commiters when build fails
|
|
Requires the Jenkins `Blame upstream commiters Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/
|
|
Blame+Upstream+Committers+Plugin>`_
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: /../../tests/publishers/fixtures/blame001.yaml
|
|
|
|
"""
|
|
|
|
XML.SubElement(xml_parent,
|
|
'hudson.plugins.blame__upstream__commiters.'
|
|
'BlameUpstreamCommitersPublisher')
|
|
|
|
|
|
def emotional_jenkins(parser, xml_parent, data):
|
|
"""yaml: emotional-jenkins
|
|
Emotional Jenkins.
|
|
Requires the Jenkins `Emotional Jenkins Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Emotional+Jenkins+Plugin>`_
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/emotional-jenkins.yaml
|
|
"""
|
|
XML.SubElement(xml_parent,
|
|
'org.jenkinsci.plugins.emotional__jenkins.'
|
|
'EmotionalJenkinsPublisher')
|
|
|
|
|
|
def trigger_parameterized_builds(parser, xml_parent, data):
|
|
"""yaml: trigger-parameterized-builds
|
|
Trigger parameterized builds of other jobs.
|
|
Requires the Jenkins `Parameterized Trigger Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/
|
|
Parameterized+Trigger+Plugin>`_
|
|
|
|
:arg str project: name of the job to trigger
|
|
:arg str predefined-parameters: parameters to pass to the other
|
|
job (optional)
|
|
:arg bool current-parameters: Whether to include the parameters passed
|
|
to the current build to the triggered job (optional)
|
|
:arg bool svn-revision: Pass svn revision to the triggered job (optional)
|
|
:arg bool git-revision: Pass git revision to the other job (optional)
|
|
:arg str condition: when to trigger the other job (default 'ALWAYS')
|
|
:arg str property-file: Use properties from file (optional)
|
|
:arg bool fail-on-missing: Blocks the triggering of the downstream jobs
|
|
if any of the files are not found in the workspace (default 'False')
|
|
:arg str restrict-matrix-project: Filter that restricts the subset
|
|
of the combinations that the downstream project will run (optional)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- trigger-parameterized-builds:
|
|
- project: other_job, foo, bar
|
|
predefined-parameters: foo=bar
|
|
- project: other_job1, other_job2
|
|
predefined-parameters: BUILD_NUM=${BUILD_NUMBER}
|
|
property-file: version.prop
|
|
fail-on-missing: true
|
|
- project: yet_another_job
|
|
predefined-parameters: foo=bar
|
|
git-revision: true
|
|
restrict-matrix-project: label=="x86"
|
|
|
|
"""
|
|
tbuilder = XML.SubElement(xml_parent,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'BuildTrigger')
|
|
configs = XML.SubElement(tbuilder, 'configs')
|
|
for project_def in data:
|
|
tconfig = XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'BuildTriggerConfig')
|
|
tconfigs = XML.SubElement(tconfig, 'configs')
|
|
if ('predefined-parameters' in project_def
|
|
or 'git-revision' in project_def
|
|
or 'property-file' in project_def
|
|
or 'current-parameters' in project_def
|
|
or 'svn-revision' in project_def
|
|
or 'restrict-matrix-project' in project_def):
|
|
|
|
if 'predefined-parameters' in project_def:
|
|
params = XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'PredefinedBuildParameters')
|
|
properties = XML.SubElement(params, 'properties')
|
|
properties.text = project_def['predefined-parameters']
|
|
|
|
if 'git-revision' in project_def and project_def['git-revision']:
|
|
params = XML.SubElement(tconfigs,
|
|
'hudson.plugins.git.'
|
|
'GitRevisionBuildParameters')
|
|
properties = XML.SubElement(params, 'combineQueuedCommits')
|
|
properties.text = 'false'
|
|
if 'property-file' in project_def and project_def['property-file']:
|
|
params = XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'FileBuildParameters')
|
|
properties = XML.SubElement(params, 'propertiesFile')
|
|
properties.text = project_def['property-file']
|
|
failOnMissing = XML.SubElement(params, 'failTriggerOnMissing')
|
|
failOnMissing.text = str(project_def.get('fail-on-missing',
|
|
False)).lower()
|
|
if ('current-parameters' in project_def
|
|
and project_def['current-parameters']):
|
|
XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'CurrentBuildParameters')
|
|
if 'svn-revision' in project_def and project_def['svn-revision']:
|
|
XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'SubversionRevisionBuildParameters')
|
|
if ('restrict-matrix-project' in project_def
|
|
and project_def['restrict-matrix-project']):
|
|
subset = XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'matrix.MatrixSubsetBuildParameters')
|
|
XML.SubElement(subset, 'filter').text = \
|
|
project_def['restrict-matrix-project']
|
|
else:
|
|
tconfigs.set('class', 'java.util.Collections$EmptyList')
|
|
projects = XML.SubElement(tconfig, 'projects')
|
|
projects.text = project_def['project']
|
|
condition = XML.SubElement(tconfig, 'condition')
|
|
condition.text = project_def.get('condition', 'ALWAYS')
|
|
trigger_with_no_params = XML.SubElement(tconfig,
|
|
'triggerWithNoParameters')
|
|
trigger_with_no_params.text = 'false'
|
|
|
|
|
|
def trigger(parser, xml_parent, data):
|
|
"""yaml: trigger
|
|
Trigger non-parametrised builds of other jobs.
|
|
|
|
:arg str project: name of the job to trigger
|
|
:arg str threshold: when to trigger the other job (default 'SUCCESS'),
|
|
alternatives: SUCCESS, UNSTABLE, FAILURE
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- trigger:
|
|
project: other_job
|
|
"""
|
|
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():
|
|
raise JenkinsJobsException("threshold must be one of %s" %
|
|
", ".join(threshold.keys()))
|
|
tname = XML.SubElement(tthreshold, 'name')
|
|
tname.text = threshold
|
|
tordinal = XML.SubElement(tthreshold, 'ordinal')
|
|
tordinal.text = thresholds[threshold]['ordinal']
|
|
tcolor = XML.SubElement(tthreshold, 'color')
|
|
tcolor.text = thresholds[threshold]['color']
|
|
|
|
|
|
def cloverphp(parser, xml_parent, data):
|
|
"""yaml: cloverphp
|
|
Capture code coverage reports from PHPUnit
|
|
Requires the Jenkins `Clover PHP Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Clover+PHP+Plugin>`_
|
|
|
|
Your job definition should pass to PHPUnit the --coverage-clover option
|
|
pointing to a file in the workspace (ex: clover-coverage.xml). The filename
|
|
has to be filled in the `xml-location` field.
|
|
|
|
:arg str xml-location: Path to the coverage XML file generated by PHPUnit
|
|
using --coverage-clover. Relative to workspace. (required)
|
|
:arg dict html: When existent, whether the plugin should generate a HTML
|
|
report. Note that PHPUnit already provide a HTML report via its
|
|
--cover-html option which can be set in your builder (optional):
|
|
|
|
* **dir** (str): Directory where HTML report will be generated relative
|
|
to workspace. (required in `html` dict).
|
|
* **archive** (bool): Whether to archive HTML reports (default True).
|
|
|
|
:arg list metric-targets: List of metric targets to reach, must be one of
|
|
**healthy**, **unhealthy** and **failing**. Each metric target can takes
|
|
two parameters:
|
|
|
|
* **method** Target for method coverage
|
|
* **statement** Target for statements coverage
|
|
|
|
Whenever a metric target is not filled in, the Jenkins plugin can fill in
|
|
defaults for you (as of v0.3.3 of the plugin the healthy target will have
|
|
method: 70 and statement: 80 if both are left empty). Jenkins Job Builder
|
|
will mimic that feature to ensure clean configuration diff.
|
|
|
|
Minimal example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/cloverphp001.yaml
|
|
|
|
Full example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/cloverphp002.yaml
|
|
|
|
"""
|
|
cloverphp = XML.SubElement(
|
|
xml_parent,
|
|
'org.jenkinsci.plugins.cloverphp.CloverPHPPublisher')
|
|
|
|
# The plugin requires clover XML file to parse
|
|
if 'xml-location' not in data:
|
|
raise JenkinsJobsException('xml-location must be set')
|
|
|
|
# Whether HTML publishing has been checked
|
|
html_publish = False
|
|
# By default, disableArchiving = false. Note that we use
|
|
# reversed logic.
|
|
html_archive = True
|
|
|
|
if 'html' in data:
|
|
html_publish = True
|
|
html_dir = data['html'].get('dir', None)
|
|
html_archive = data['html'].get('archive', html_archive)
|
|
if html_dir is None:
|
|
# No point in going further, the plugin would not work
|
|
raise JenkinsJobsException('htmldir is required in a html block')
|
|
|
|
XML.SubElement(cloverphp, 'publishHtmlReport').text = \
|
|
str(html_publish).lower()
|
|
if html_publish:
|
|
XML.SubElement(cloverphp, 'reportDir').text = html_dir
|
|
XML.SubElement(cloverphp, 'xmlLocation').text = data.get('xml-location')
|
|
XML.SubElement(cloverphp, 'disableArchiving').text = \
|
|
str(not html_archive).lower()
|
|
|
|
# Handle targets
|
|
|
|
# Plugin v0.3.3 will fill defaults for us whenever healthy targets are both
|
|
# blanks.
|
|
default_metrics = {
|
|
'healthy': {'method': 70, 'statement': 80}
|
|
}
|
|
allowed_metrics = ['healthy', 'unhealthy', 'failing']
|
|
|
|
metrics = data.get('metric-targets', [])
|
|
# list of dicts to dict
|
|
metrics = dict(kv for m in metrics for kv in m.iteritems())
|
|
|
|
# Populate defaults whenever nothing has been filled by user.
|
|
for default in default_metrics.keys():
|
|
if metrics.get(default, None) is None:
|
|
metrics[default] = default_metrics[default]
|
|
|
|
# The plugin would at least define empty targets so make sure
|
|
# we output them all in the XML regardless of what the user
|
|
# has or has not entered.
|
|
for target in allowed_metrics:
|
|
cur_target = XML.SubElement(cloverphp, target + 'Target')
|
|
|
|
for t_type in ['method', 'statement']:
|
|
val = metrics.get(target, {}).get(t_type)
|
|
if val is None or type(val) != int:
|
|
continue
|
|
if val < 0 or val > 100:
|
|
raise JenkinsJobsException(
|
|
"Publisher cloverphp metric target %s:%s = %s "
|
|
"is not in valid range 0-100." % (target, t_type, val))
|
|
XML.SubElement(cur_target, t_type + 'Coverage').text = str(val)
|
|
|
|
|
|
def coverage(parser, xml_parent, data):
|
|
"""yaml: coverage
|
|
WARNING: The coverage function is deprecated. Instead, use the
|
|
cobertura function to generate a cobertura coverage report.
|
|
Requires the Jenkins `Cobertura Coverage Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin>`_
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- coverage
|
|
"""
|
|
logger = logging.getLogger(__name__)
|
|
logger.warn("Coverage function is deprecated. Switch to cobertura.")
|
|
|
|
cobertura = XML.SubElement(xml_parent,
|
|
'hudson.plugins.cobertura.CoberturaPublisher')
|
|
XML.SubElement(cobertura, 'coberturaReportFile').text = '**/coverage.xml'
|
|
XML.SubElement(cobertura, 'onlyStable').text = 'false'
|
|
healthy = XML.SubElement(cobertura, 'healthyTarget')
|
|
targets = XML.SubElement(healthy, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'CONDITIONAL'
|
|
XML.SubElement(entry, 'int').text = '70'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'LINE'
|
|
XML.SubElement(entry, 'int').text = '80'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'METHOD'
|
|
XML.SubElement(entry, 'int').text = '80'
|
|
unhealthy = XML.SubElement(cobertura, 'unhealthyTarget')
|
|
targets = XML.SubElement(unhealthy, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'CONDITIONAL'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'LINE'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'METHOD'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
failing = XML.SubElement(cobertura, 'failingTarget')
|
|
targets = XML.SubElement(failing, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'CONDITIONAL'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'LINE'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric'
|
|
).text = 'METHOD'
|
|
XML.SubElement(entry, 'int').text = '0'
|
|
XML.SubElement(cobertura, 'sourceEncoding').text = 'ASCII'
|
|
|
|
|
|
def cobertura(parser, xml_parent, data):
|
|
"""yaml: cobertura
|
|
Generate a cobertura coverage report.
|
|
Requires the Jenkins `Cobertura Coverage Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin>`_
|
|
|
|
:arg str report-file: This is a file name pattern that can be used
|
|
to locate the cobertura xml report files (optional)
|
|
:arg bool only-stable: Include only stable builds (default false)
|
|
:arg bool fail-no-reports: fail builds if no coverage reports are found
|
|
(default false)
|
|
:arg bool fail-unhealthy: Unhealthy projects will be failed
|
|
(default false)
|
|
:arg bool fail-unstable: Unstable projects will be failed (default false)
|
|
:arg bool health-auto-update: Auto update threshold for health on
|
|
successful build (default false)
|
|
:arg bool stability-auto-update: Auto update threshold for stability on
|
|
successful build (default false)
|
|
:arg bool zoom-coverage-chart: Zoom the coverage chart and crop area below
|
|
the minimum and above the maximum coverage
|
|
of the past reports (default false)
|
|
:arg str source-encoding: Override the source encoding (default ASCII)
|
|
:arg dict targets:
|
|
|
|
:targets: (packages, files, classes, method, line, conditional)
|
|
|
|
* **healthy** (`int`): Healthy threshold (default 0)
|
|
* **unhealthy** (`int`): Unhealthy threshold (default 0)
|
|
* **failing** (`int`): Failing threshold (default 0)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- cobertura:
|
|
report-file: "/reports/cobertura/coverage.xml"
|
|
only-stable: "true"
|
|
fail-no-reports: "true"
|
|
fail-unhealthy: "true"
|
|
fail-unstable: "true"
|
|
health-auto-update: "true"
|
|
stability-auto-update: "true"
|
|
zoom-coverage-chart: "true"
|
|
source-encoding: "Big5"
|
|
targets:
|
|
- files:
|
|
healthy: 10
|
|
unhealthy: 20
|
|
failing: 30
|
|
- method:
|
|
healthy: 50
|
|
unhealthy: 40
|
|
failing: 30
|
|
|
|
|
|
"""
|
|
cobertura = XML.SubElement(xml_parent,
|
|
'hudson.plugins.cobertura.CoberturaPublisher')
|
|
XML.SubElement(cobertura, 'coberturaReportFile').text = data.get(
|
|
'report-file', '**/coverage.xml')
|
|
XML.SubElement(cobertura, 'onlyStable').text = str(
|
|
data.get('only-stable', False)).lower()
|
|
XML.SubElement(cobertura, 'failUnhealthy').text = str(
|
|
data.get('fail-unhealthy', False)).lower()
|
|
XML.SubElement(cobertura, 'failUnstable').text = str(
|
|
data.get('fail-unstable', False)).lower()
|
|
XML.SubElement(cobertura, 'autoUpdateHealth').text = str(
|
|
data.get('health-auto-update', False)).lower()
|
|
XML.SubElement(cobertura, 'autoUpdateStability').text = str(
|
|
data.get('stability-auto-update', False)).lower()
|
|
XML.SubElement(cobertura, 'zoomCoverageChart').text = str(
|
|
data.get('zoom-coverage-chart', False)).lower()
|
|
XML.SubElement(cobertura, 'failNoReports').text = str(
|
|
data.get('fail-no-reports', False)).lower()
|
|
healthy = XML.SubElement(cobertura, 'healthyTarget')
|
|
targets = XML.SubElement(healthy, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
for item in data['targets']:
|
|
item_name = item.keys()[0]
|
|
item_values = item.get(item_name, 0)
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry,
|
|
'hudson.plugins.cobertura.targets.'
|
|
'CoverageMetric').text = str(item_name).upper()
|
|
XML.SubElement(entry, 'int').text = str(item_values.get('healthy', 0))
|
|
unhealthy = XML.SubElement(cobertura, 'unhealthyTarget')
|
|
targets = XML.SubElement(unhealthy, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
for item in data['targets']:
|
|
item_name = item.keys()[0]
|
|
item_values = item.get(item_name, 0)
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.'
|
|
'CoverageMetric').text = str(item_name).upper()
|
|
XML.SubElement(entry, 'int').text = str(item_values.get('unhealthy',
|
|
0))
|
|
failing = XML.SubElement(cobertura, 'failingTarget')
|
|
targets = XML.SubElement(failing, 'targets', {
|
|
'class': 'enum-map',
|
|
'enum-type': 'hudson.plugins.cobertura.targets.CoverageMetric'})
|
|
for item in data['targets']:
|
|
item_name = item.keys()[0]
|
|
item_values = item.get(item_name, 0)
|
|
entry = XML.SubElement(targets, 'entry')
|
|
XML.SubElement(entry, 'hudson.plugins.cobertura.targets.'
|
|
'CoverageMetric').text = str(item_name).upper()
|
|
XML.SubElement(entry, 'int').text = str(item_values.get('failing', 0))
|
|
XML.SubElement(cobertura, 'sourceEncoding').text = data.get(
|
|
'source-encoding', 'ASCII')
|
|
|
|
|
|
def jacoco(parser, xml_parent, data):
|
|
"""yaml: jacoco
|
|
Generate a JaCoCo coverage report.
|
|
Requires the Jenkins `JaCoCo Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/JaCoCo+Plugin>`_
|
|
|
|
:arg str exec-pattern: This is a file name pattern that can be used to
|
|
locate the jacoco report files (default
|
|
``**/**.exec``)
|
|
:arg str class-pattern: This is a file name pattern that can be used
|
|
to locate class files (default ``**/classes``)
|
|
:arg str source-pattern: This is a file name pattern that can be used
|
|
to locate source files (default ``**/src/main/java``)
|
|
:arg bool update-build-status: Update the build according to the results
|
|
(default False)
|
|
:arg str inclusion-pattern: This is a file name pattern that can be used
|
|
to include certain class files (optional)
|
|
:arg str exclusion-pattern: This is a file name pattern that can be used
|
|
to exclude certain class files (optional)
|
|
:arg dict targets:
|
|
|
|
:targets: (instruction, branch, complexity, line, method, class)
|
|
|
|
* **healthy** (`int`): Healthy threshold (default 0)
|
|
* **unhealthy** (`int`): Unhealthy threshold (default 0)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- jacoco:
|
|
exec-pattern: "**/**.exec"
|
|
class-pattern: "**/classes"
|
|
source-pattern: "**/src/main/java"
|
|
status-update: true
|
|
targets:
|
|
- branch:
|
|
healthy: 10
|
|
unhealthy: 20
|
|
- method:
|
|
healthy: 50
|
|
unhealthy: 40
|
|
|
|
"""
|
|
|
|
jacoco = XML.SubElement(xml_parent,
|
|
'hudson.plugins.jacoco.JacocoPublisher')
|
|
XML.SubElement(jacoco, 'execPattern').text = data.get(
|
|
'exec-pattern', '**/**.exec')
|
|
XML.SubElement(jacoco, 'classPattern').text = data.get(
|
|
'class-pattern', '**/classes')
|
|
XML.SubElement(jacoco, 'sourcePattern').text = data.get(
|
|
'source-pattern', '**/src/main/java')
|
|
XML.SubElement(jacoco, 'changeBuildStatus').text = data.get(
|
|
'update-build-status', False)
|
|
XML.SubElement(jacoco, 'inclusionPattern').text = data.get(
|
|
'inclusion-pattern', '')
|
|
XML.SubElement(jacoco, 'exclusionPattern').text = data.get(
|
|
'exclusion-pattern', '')
|
|
|
|
itemsList = ['instruction',
|
|
'branch',
|
|
'complexity',
|
|
'line',
|
|
'method',
|
|
'class']
|
|
|
|
for item in data['targets']:
|
|
item_name = item.keys()[0]
|
|
if item_name not in itemsList:
|
|
raise JenkinsJobsException("item entered is not valid must be "
|
|
"one of: %s" % ",".join(itemsList))
|
|
item_values = item.get(item_name, 0)
|
|
|
|
XML.SubElement(jacoco,
|
|
'maximum' +
|
|
item_name.capitalize() +
|
|
'Coverage').text = str(item_values.get('healthy', 0))
|
|
XML.SubElement(jacoco,
|
|
'minimum' +
|
|
item_name.capitalize() +
|
|
'Coverage').text = str(item_values.get('unhealthy', 0))
|
|
|
|
|
|
def ftp(parser, xml_parent, data):
|
|
"""yaml: ftp
|
|
Upload files via FTP.
|
|
Requires the Jenkins `Publish over FTP Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+FTP+Plugin>`_
|
|
|
|
:arg str site: name of the ftp site
|
|
:arg str target: destination directory
|
|
:arg bool target-is-date-format: whether target is a date format. If true,
|
|
raw text should be quoted (defaults to False)
|
|
:arg bool clean-remote: should the remote directory be deleted before
|
|
transfering files (defaults to False)
|
|
:arg str source: source path specifier
|
|
:arg str excludes: excluded file pattern (optional)
|
|
:arg str remove-prefix: prefix to remove from uploaded file paths
|
|
(optional)
|
|
:arg bool fail-on-error: fail the build if an error occurs (defaults to
|
|
False).
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- ftp:
|
|
site: 'ftp.example.com'
|
|
target: 'dest/dir'
|
|
source: 'base/source/dir/**'
|
|
remove-prefix: 'base/source/dir'
|
|
excludes: '**/*.excludedfiletype'
|
|
"""
|
|
console_prefix = 'FTP: '
|
|
plugin_tag = 'jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin'
|
|
publisher_tag = 'jenkins.plugins.publish__over__ftp.BapFtpPublisher'
|
|
transfer_tag = 'jenkins.plugins.publish__over__ftp.BapFtpTransfer'
|
|
plugin_reference_tag = 'jenkins.plugins.publish_over_ftp.' \
|
|
'BapFtpPublisherPlugin'
|
|
(_, transfer_node) = base_publish_over(xml_parent,
|
|
data,
|
|
console_prefix,
|
|
plugin_tag,
|
|
publisher_tag,
|
|
transfer_tag,
|
|
plugin_reference_tag)
|
|
XML.SubElement(transfer_node, 'asciiMode').text = 'false'
|
|
|
|
|
|
def junit(parser, xml_parent, data):
|
|
"""yaml: junit
|
|
Publish JUnit test results.
|
|
|
|
:arg str results: results filename
|
|
:arg bool keep-long-stdio: Retain long standard output/error in test
|
|
results (default true).
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- junit:
|
|
results: nosetests.xml
|
|
keep-long-stdio: false
|
|
"""
|
|
junitresult = XML.SubElement(xml_parent,
|
|
'hudson.tasks.junit.JUnitResultArchiver')
|
|
XML.SubElement(junitresult, 'testResults').text = data['results']
|
|
XML.SubElement(junitresult, 'keepLongStdio').text = str(
|
|
data.get('keep-long-stdio', True)).lower()
|
|
XML.SubElement(junitresult, 'testDataPublishers')
|
|
|
|
|
|
def xunit(parser, xml_parent, data):
|
|
"""yaml: xunit
|
|
Publish tests results. Requires the Jenkins `xUnit Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/xUnit+Plugin>`_
|
|
|
|
:arg str thresholdmode: whether thresholds represents an absolute \
|
|
number of tests or a percentage. Either 'number' or 'percent', will \
|
|
default to 'number' if omitted.
|
|
|
|
:arg dict thresholds: list containing the thresholds for both \
|
|
'failed' and 'skipped' tests. Each entry should in turn have a \
|
|
list of "threshold name: values". The threshold names are \
|
|
'unstable', 'unstablenew', 'failure', 'failurenew'. Omitting a \
|
|
value will resort on xUnit default value (should be 0).
|
|
|
|
:arg dict types: per framework configuration. The key should be \
|
|
one of the internal types we support:\
|
|
'aunit', 'boosttest', 'checktype', 'cpptest', 'cppunit', 'fpcunit', \
|
|
'junit', 'mstest', 'nunit', 'phpunit', 'tusar', 'unittest', 'valgrind'. \
|
|
The 'custom' type is not supported.
|
|
|
|
Each framework type can be configured using the following parameters:
|
|
|
|
:arg str pattern: An Ant pattern to look for Junit result files, \
|
|
relative to the workspace root.
|
|
|
|
:arg bool requireupdate: fail the build whenever fresh tests \
|
|
results have not been found (default: true).
|
|
|
|
:arg bool deleteoutput: delete temporary JUnit files (default: true)
|
|
|
|
:arg bool stoponerror: Fail the build whenever an error occur during \
|
|
a result file processing (default: true).
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- xunit:
|
|
thresholdmode: 'percent'
|
|
thresholds:
|
|
- failed:
|
|
unstable: 0
|
|
unstablenew: 0
|
|
failure: 0
|
|
failurenew: 0
|
|
- skipped:
|
|
unstable: 0
|
|
unstablenew: 0
|
|
failure: 0
|
|
failurenew: 0
|
|
types:
|
|
- phpunit:
|
|
pattern: junit.log
|
|
- cppUnit:
|
|
pattern: cppunit.log
|
|
|
|
"""
|
|
logger = logging.getLogger(__name__)
|
|
xunit = XML.SubElement(xml_parent, 'xunit')
|
|
|
|
# Map our internal types to the XML element names used by Jenkins plugin
|
|
types_to_plugin_types = {
|
|
'aunit': 'AUnitJunitHudsonTestType',
|
|
'boosttest': 'BoostTestJunitHudsonTestType',
|
|
'checktype': 'CheckType',
|
|
'cpptest': 'CppTestJunitHudsonTestType',
|
|
'cppunit': 'CppUnitJunitHudsonTestType',
|
|
'fpcunit': 'FPCUnitJunitHudsonTestType',
|
|
'junit': 'JUnitType',
|
|
'mstest': 'MSTestJunitHudsonTestType',
|
|
'nunit': 'NUnitJunitHudsonTestType',
|
|
'phpunit': 'PHPUnitJunitHudsonTestType',
|
|
'tusar': 'TUSARJunitHudsonTestType',
|
|
'unittest': 'UnitTestJunitHudsonTestType',
|
|
'valgrind': 'ValgrindJunitHudsonTestType',
|
|
# FIXME should implement the 'custom' type
|
|
}
|
|
implemented_types = types_to_plugin_types.keys() # shortcut
|
|
|
|
# Unit framework we are going to generate xml for
|
|
supported_types = []
|
|
|
|
for configured_type in data['types']:
|
|
type_name = configured_type.keys()[0]
|
|
if type_name not in implemented_types:
|
|
logger.warn("Requested xUnit type '%s' is not yet supported" %
|
|
type_name)
|
|
else:
|
|
# Append for generation
|
|
supported_types.append(configured_type)
|
|
|
|
# Generate XML for each of the supported framework types
|
|
xmltypes = XML.SubElement(xunit, 'types')
|
|
for supported_type in supported_types:
|
|
framework_name = supported_type.keys()[0]
|
|
xmlframework = XML.SubElement(xmltypes,
|
|
types_to_plugin_types[framework_name])
|
|
|
|
XML.SubElement(xmlframework, 'pattern').text = \
|
|
supported_type[framework_name].get('pattern', '')
|
|
XML.SubElement(xmlframework, 'failIfNotNew').text = \
|
|
str(supported_type[framework_name].get(
|
|
'requireupdate', True)).lower()
|
|
XML.SubElement(xmlframework, 'deleteOutputFiles').text = \
|
|
str(supported_type[framework_name].get(
|
|
'deleteoutput', True)).lower()
|
|
XML.SubElement(xmlframework, 'stopProcessingIfError').text = \
|
|
str(supported_type[framework_name].get(
|
|
'stoponerror', True)).lower()
|
|
|
|
xmlthresholds = XML.SubElement(xunit, 'thresholds')
|
|
if 'thresholds' in data:
|
|
for t in data['thresholds']:
|
|
if not ('failed' in t or 'skipped' in t):
|
|
logger.warn(
|
|
"Unrecognized threshold, should be 'failed' or 'skipped'")
|
|
continue
|
|
elname = "org.jenkinsci.plugins.xunit.threshold.%sThreshold" \
|
|
% t.keys()[0].title()
|
|
el = XML.SubElement(xmlthresholds, elname)
|
|
for threshold_name, threshold_value in t.values()[0].items():
|
|
# Normalize and craft the element name for this threshold
|
|
elname = "%sThreshold" % threshold_name.lower().replace(
|
|
'new', 'New')
|
|
XML.SubElement(el, elname).text = threshold_value
|
|
|
|
# Whether to use percent of exact number of tests.
|
|
# Thresholdmode is either:
|
|
# - 1 : absolute (number of tests), default.
|
|
# - 2 : relative (percentage of tests)
|
|
thresholdmode = '1'
|
|
if 'percent' == data.get('thresholdmode', 'number'):
|
|
thresholdmode = '2'
|
|
XML.SubElement(xunit, 'thresholdMode').text = \
|
|
thresholdmode
|
|
|
|
|
|
def _violations_add_entry(xml_parent, name, data):
|
|
vmin = data.get('min', 10)
|
|
vmax = data.get('max', 999)
|
|
vunstable = data.get('unstable', 999)
|
|
pattern = data.get('pattern', None)
|
|
|
|
entry = XML.SubElement(xml_parent, 'entry')
|
|
XML.SubElement(entry, 'string').text = name
|
|
tconfig = XML.SubElement(entry, 'hudson.plugins.violations.TypeConfig')
|
|
XML.SubElement(tconfig, 'type').text = name
|
|
XML.SubElement(tconfig, 'min').text = str(vmin)
|
|
XML.SubElement(tconfig, 'max').text = str(vmax)
|
|
XML.SubElement(tconfig, 'unstable').text = str(vunstable)
|
|
XML.SubElement(tconfig, 'usePattern').text = 'false'
|
|
if pattern:
|
|
XML.SubElement(tconfig, 'pattern').text = pattern
|
|
else:
|
|
XML.SubElement(tconfig, 'pattern')
|
|
|
|
|
|
def violations(parser, xml_parent, data):
|
|
"""yaml: violations
|
|
Publish code style violations.
|
|
Requires the Jenkins `Violations Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Violations>`_
|
|
|
|
The violations component accepts any number of dictionaries keyed
|
|
by the name of the violations system. The dictionary has the
|
|
following values:
|
|
|
|
:arg int min: sunny threshold
|
|
:arg int max: stormy threshold
|
|
:arg int unstable: unstable threshold
|
|
:arg str pattern: report filename pattern
|
|
|
|
Any system without a dictionary provided will use default values.
|
|
|
|
Valid systems are:
|
|
|
|
checkstyle, codenarc, cpd, cpplint, csslint, findbugs, fxcop,
|
|
gendarme, jcreport, jslint, pep8, pmd, pylint, simian, stylecop
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- violations:
|
|
pep8:
|
|
min: 0
|
|
max: 1
|
|
unstable: 1
|
|
pattern: '**/pep8.txt'
|
|
"""
|
|
violations = XML.SubElement(xml_parent,
|
|
'hudson.plugins.violations.'
|
|
'ViolationsPublisher')
|
|
config = XML.SubElement(violations, 'config')
|
|
suppressions = XML.SubElement(config, 'suppressions',
|
|
{'class': 'tree-set'})
|
|
XML.SubElement(suppressions, 'no-comparator')
|
|
configs = XML.SubElement(config, 'typeConfigs')
|
|
XML.SubElement(configs, 'no-comparator')
|
|
|
|
for name in [
|
|
'checkstyle',
|
|
'codenarc',
|
|
'cpd',
|
|
'cpplint',
|
|
'csslint',
|
|
'findbugs',
|
|
'fxcop',
|
|
'gendarme',
|
|
'jcreport',
|
|
'jslint',
|
|
'pep8',
|
|
'pmd',
|
|
'pylint',
|
|
'simian',
|
|
'stylecop']:
|
|
_violations_add_entry(configs, name, data.get(name, {}))
|
|
|
|
XML.SubElement(config, 'limit').text = '100'
|
|
XML.SubElement(config, 'sourcePathPattern')
|
|
XML.SubElement(config, 'fauxProjectPath')
|
|
XML.SubElement(config, 'encoding').text = 'default'
|
|
|
|
|
|
def checkstyle(parser, xml_parent, data):
|
|
"""yaml: checkstyle
|
|
Publish trend reports with Checkstyle.
|
|
Requires the Jenkins `Checkstyle Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin>`_
|
|
|
|
The checkstyle component accepts a dictionary with the
|
|
following values:
|
|
|
|
:arg str pattern: report filename pattern
|
|
:arg bool canRunOnFailed: also runs for failed builds
|
|
(instead of just stable or unstable builds)
|
|
:arg bool shouldDetectModules:
|
|
:arg int healthy: sunny threshold
|
|
:arg int unHealthy: stormy threshold
|
|
:arg str healthThreshold: threshold priority for health status
|
|
(high: only high, normal: high and normal, low: all)
|
|
:arg dict thresholds:
|
|
:thresholds:
|
|
* **unstable** (`dict`)
|
|
:unstable: * **totalAll** (`int`)
|
|
* **totalHigh** (`int`)
|
|
* **totalNormal** (`int`)
|
|
* **totalLow** (`int`)
|
|
* **failed** (`dict`)
|
|
:failed: * **totalAll** (`int`)
|
|
* **totalHigh** (`int`)
|
|
* **totalNormal** (`int`)
|
|
* **totalLow** (`int`)
|
|
:arg str defaultEncoding: encoding for parsing or showing files
|
|
(empty will use platform default)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- checkstyle:
|
|
pattern: '**/checkstyle-result.xml'
|
|
healthy: 0
|
|
unHealthy: 100
|
|
healthThreshold: 'high'
|
|
thresholds:
|
|
unstable:
|
|
totalHigh: 10
|
|
failed:
|
|
totalHigh: 1
|
|
"""
|
|
checkstyle = XML.SubElement(xml_parent,
|
|
'hudson.plugins.checkstyle.'
|
|
'CheckStylePublisher')
|
|
|
|
dval = data.get('healthy', None)
|
|
if dval:
|
|
XML.SubElement(checkstyle, 'healthy').text = str(dval)
|
|
else:
|
|
XML.SubElement(checkstyle, 'healthy')
|
|
|
|
dval = data.get('unHealthy', None)
|
|
if dval:
|
|
XML.SubElement(checkstyle, 'unHealthy').text = str(dval)
|
|
else:
|
|
XML.SubElement(checkstyle, 'unHealthy')
|
|
|
|
XML.SubElement(checkstyle, 'thresholdLimit').text = \
|
|
data.get('healthThreshold', 'low')
|
|
|
|
XML.SubElement(checkstyle, 'pluginName').text = '[CHECKSTYLE] '
|
|
|
|
XML.SubElement(checkstyle, 'defaultEncoding').text = \
|
|
data.get('defaultEncoding', '')
|
|
|
|
if data.get('canRunOnFailed', False):
|
|
XML.SubElement(checkstyle, 'canRunOnFailed').text = 'true'
|
|
else:
|
|
XML.SubElement(checkstyle, 'canRunOnFailed').text = 'false'
|
|
|
|
XML.SubElement(checkstyle, 'useStableBuildAsReference').text = 'false'
|
|
|
|
XML.SubElement(checkstyle, 'useDeltaValues').text = 'false'
|
|
|
|
dthresholds = data.get('thresholds', {})
|
|
dunstable = dthresholds.get('unstable', {})
|
|
dfailed = dthresholds.get('failed', {})
|
|
thresholds = XML.SubElement(checkstyle, 'thresholds')
|
|
|
|
dval = dunstable.get('totalAll', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'unstableTotalAll').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'unstableTotalAll')
|
|
|
|
dval = dunstable.get('totalHigh', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'unstableTotalHigh').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'unstableTotalHigh')
|
|
|
|
dval = dunstable.get('totalNormal', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'unstableTotalNormal').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'unstableTotalNormal')
|
|
|
|
dval = dunstable.get('totalLow', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'unstableTotalLow').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'unstableTotalLow')
|
|
|
|
dval = dfailed.get('totalAll', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'failedTotalAll').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'failedTotalAll')
|
|
|
|
dval = dfailed.get('totalHigh', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'failedTotalHigh').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'failedTotalHigh')
|
|
|
|
dval = dfailed.get('totalNormal', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'failedTotalNormal').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'failedTotalNormal')
|
|
|
|
dval = dfailed.get('totalLow', None)
|
|
if dval:
|
|
XML.SubElement(thresholds, 'failedTotalLow').text = str(dval)
|
|
else:
|
|
XML.SubElement(thresholds, 'failedTotalLow')
|
|
|
|
if data.get('shouldDetectModules', False):
|
|
XML.SubElement(checkstyle, 'shouldDetectModules').text = 'true'
|
|
else:
|
|
XML.SubElement(checkstyle, 'shouldDetectModules').text = 'false'
|
|
|
|
XML.SubElement(checkstyle, 'dontComputeNew').text = 'true'
|
|
|
|
XML.SubElement(checkstyle, 'doNotResolveRelativePaths').text = 'false'
|
|
|
|
XML.SubElement(checkstyle, 'pattern').text = data.get('pattern', '')
|
|
|
|
|
|
def scp(parser, xml_parent, data):
|
|
"""yaml: scp
|
|
Upload files via SCP
|
|
Requires the Jenkins `SCP Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/SCP+plugin>`_
|
|
|
|
:arg str site: name of the scp site
|
|
:arg str target: destination directory
|
|
:arg str source: source path specifier
|
|
:arg bool keep-hierarchy: keep the file hierarchy when uploading
|
|
(default false)
|
|
:arg bool copy-after-failure: copy files even if the job fails
|
|
(default false)
|
|
:arg bool copy-console: copy the console log (default false); if
|
|
specified, omit 'target'
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/scp001.yaml
|
|
"""
|
|
site = data['site']
|
|
scp = XML.SubElement(xml_parent,
|
|
'be.certipost.hudson.plugin.SCPRepositoryPublisher')
|
|
XML.SubElement(scp, 'siteName').text = site
|
|
entries = XML.SubElement(scp, 'entries')
|
|
for entry in data['files']:
|
|
entry_e = XML.SubElement(entries, 'be.certipost.hudson.plugin.Entry')
|
|
XML.SubElement(entry_e, 'filePath').text = entry['target']
|
|
XML.SubElement(entry_e, 'sourceFile').text = entry.get('source', '')
|
|
if entry.get('keep-hierarchy', False):
|
|
XML.SubElement(entry_e, 'keepHierarchy').text = 'true'
|
|
else:
|
|
XML.SubElement(entry_e, 'keepHierarchy').text = 'false'
|
|
if entry.get('copy-console', False):
|
|
XML.SubElement(entry_e, 'copyConsoleLog').text = 'true'
|
|
else:
|
|
XML.SubElement(entry_e, 'copyConsoleLog').text = 'false'
|
|
if entry.get('copy-after-failure', False):
|
|
XML.SubElement(entry_e, 'copyAfterFailure').text = 'true'
|
|
else:
|
|
XML.SubElement(entry_e, 'copyAfterFailure').text = 'false'
|
|
|
|
|
|
def ssh(parser, xml_parent, data):
|
|
"""yaml: ssh
|
|
Upload files via SCP.
|
|
Requires the Jenkins `Publish over SSH Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+SSH+Plugin>`_
|
|
|
|
:arg str site: name of the ssh site
|
|
:arg str target: destination directory
|
|
:arg bool target-is-date-format: whether target is a date format. If true,
|
|
raw text should be quoted (defaults to False)
|
|
:arg bool clean-remote: should the remote directory be deleted before
|
|
transfering files (defaults to False)
|
|
:arg str source: source path specifier
|
|
:arg str command: a command to execute on the remote server (optional)
|
|
:arg int timeout: timeout in milliseconds for the Exec command (optional)
|
|
:arg bool use-pty: run the exec command in pseudo TTY (defaults to False)
|
|
:arg str excludes: excluded file pattern (optional)
|
|
:arg str remove-prefix: prefix to remove from uploaded file paths
|
|
(optional)
|
|
:arg bool fail-on-error: fail the build if an error occurs (defaults to
|
|
False).
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- ssh:
|
|
site: 'server.example.com'
|
|
target: 'dest/dir'
|
|
source: 'base/source/dir/**'
|
|
remove-prefix: 'base/source/dir'
|
|
excludes: '**/*.excludedfiletype'
|
|
use-pty: true
|
|
command: 'rm -r jenkins_$BUILD_NUMBER'
|
|
timeout: 1800000
|
|
"""
|
|
console_prefix = 'SSH: '
|
|
plugin_tag = 'jenkins.plugins.publish__over__ssh.BapSshPublisherPlugin'
|
|
publisher_tag = 'jenkins.plugins.publish__over__ssh.BapSshPublisher'
|
|
transfer_tag = 'jenkins.plugins.publish__over__ssh.BapSshTransfer'
|
|
plugin_reference_tag = 'jenkins.plugins.publish_over_ssh.' \
|
|
'BapSshPublisherPlugin'
|
|
base_publish_over(xml_parent,
|
|
data,
|
|
console_prefix,
|
|
plugin_tag,
|
|
publisher_tag,
|
|
transfer_tag,
|
|
plugin_reference_tag)
|
|
|
|
|
|
def pipeline(parser, xml_parent, data):
|
|
"""yaml: pipeline
|
|
Specify a downstream project in a pipeline.
|
|
Requires the Jenkins `Build Pipeline Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Build+Pipeline+Plugin>`_
|
|
|
|
:arg str project: the name of the downstream project
|
|
:arg str predefined-parameters: parameters to pass to the other
|
|
job (optional)
|
|
:arg bool current-parameters: Whether to include the parameters passed
|
|
to the current build to the triggered job (optional)
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/pipeline002.yaml
|
|
|
|
|
|
You can build pipeline jobs that are re-usable in different pipelines by
|
|
using a :ref:`job-template` to define the pipeline jobs,
|
|
and variable substitution to specify the name of
|
|
the downstream job in the pipeline.
|
|
Job-specific substitutions are useful here (see :ref:`project`).
|
|
|
|
See 'samples/pipeline.yaml' for an example pipeline implementation.
|
|
"""
|
|
if 'project' in data and data['project'] != '':
|
|
pippub = XML.SubElement(xml_parent,
|
|
'au.com.centrumsystems.hudson.plugin.'
|
|
'buildpipeline.trigger.BuildPipelineTrigger')
|
|
|
|
configs = XML.SubElement(pippub, 'configs')
|
|
|
|
if 'predefined-parameters' in data:
|
|
params = XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'PredefinedBuildParameters')
|
|
properties = XML.SubElement(params, 'properties')
|
|
properties.text = data['predefined-parameters']
|
|
|
|
if ('current-parameters' in data
|
|
and data['current-parameters']):
|
|
XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'CurrentBuildParameters')
|
|
|
|
XML.SubElement(pippub, 'downstreamProjectNames').text = data['project']
|
|
|
|
|
|
def email(parser, xml_parent, data):
|
|
"""yaml: email
|
|
Email notifications on build failure.
|
|
|
|
:arg str recipients: Recipient email addresses
|
|
:arg bool notify-every-unstable-build: Send an email for every
|
|
unstable build (default true)
|
|
:arg bool send-to-individuals: Send an email to the individual
|
|
who broke the build (default false)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- email:
|
|
recipients: breakage@example.com
|
|
"""
|
|
|
|
# TODO: raise exception if this is applied to a maven job
|
|
mailer = XML.SubElement(xml_parent,
|
|
'hudson.tasks.Mailer')
|
|
XML.SubElement(mailer, 'recipients').text = data['recipients']
|
|
|
|
# Note the logic reversal (included here to match the GUI
|
|
if data.get('notify-every-unstable-build', True):
|
|
XML.SubElement(mailer, 'dontNotifyEveryUnstableBuild').text = 'false'
|
|
else:
|
|
XML.SubElement(mailer, 'dontNotifyEveryUnstableBuild').text = 'true'
|
|
XML.SubElement(mailer, 'sendToIndividuals').text = str(
|
|
data.get('send-to-individuals', False)).lower()
|
|
|
|
|
|
def claim_build(parser, xml_parent, data):
|
|
"""yaml: claim-build
|
|
Claim build failures
|
|
Requires the Jenkins `Claim Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Claim+plugin>`_
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- claim-build
|
|
"""
|
|
|
|
XML.SubElement(xml_parent, 'hudson.plugins.claim.ClaimPublisher')
|
|
|
|
|
|
def base_email_ext(parser, xml_parent, data, ttype):
|
|
trigger = XML.SubElement(xml_parent,
|
|
'hudson.plugins.emailext.plugins.trigger.'
|
|
+ ttype)
|
|
email = XML.SubElement(trigger, 'email')
|
|
XML.SubElement(email, 'recipientList').text = ''
|
|
XML.SubElement(email, 'subject').text = '$PROJECT_DEFAULT_SUBJECT'
|
|
XML.SubElement(email, 'body').text = '$PROJECT_DEFAULT_CONTENT'
|
|
XML.SubElement(email, 'sendToDevelopers').text = 'false'
|
|
XML.SubElement(email, 'sendToRequester').text = 'false'
|
|
XML.SubElement(email, 'includeCulprits').text = 'false'
|
|
XML.SubElement(email, 'sendToRecipientList').text = 'true'
|
|
|
|
|
|
def email_ext(parser, xml_parent, data):
|
|
"""yaml: email-ext
|
|
Extend Jenkin's built in email notification
|
|
Requires the Jenkins `Email-ext Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin>`_
|
|
|
|
:arg str recipients: Comma separated list of emails
|
|
:arg str reply-to: Comma separated list of emails that should be in
|
|
the Reply-To header for this project (default is $DEFAULT_RECIPIENTS)
|
|
:arg str subject: Subject for the email, can include variables like
|
|
${BUILD_NUMBER} or even groovy or javascript code
|
|
:arg str body: Content for the body of the email, can include variables
|
|
like ${BUILD_NUMBER}, but the real magic is using groovy or
|
|
javascript to hook into the Jenkins API itself
|
|
:arg bool attach-build-log: Include build log in the email (default false)
|
|
:arg bool unstable: Send an email for an unstable result (default false)
|
|
:arg bool first-failure: Send an email for just the first failure
|
|
(default false)
|
|
:arg bool not-built: Send an email if not built (default false)
|
|
:arg bool aborted: Send an email if the build is aborted (default false)
|
|
:arg bool regression: Send an email if there is a regression
|
|
(default false)
|
|
:arg bool failure: Send an email if the build fails (default true)
|
|
:arg bool improvement: Send an email if the build improves (default false)
|
|
:arg bool still-failing: Send an email if the build is still failing
|
|
(default false)
|
|
:arg bool success: Send an email for a successful build (default false)
|
|
:arg bool fixed: Send an email if the build is fixed (default false)
|
|
:arg bool still-unstable: Send an email if the build is still unstable
|
|
(default false)
|
|
:arg bool pre-build: Send an email before the build (default false)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- email-ext:
|
|
recipients: foo@example.com, bar@example.com
|
|
reply-to: foo@example.com
|
|
subject: Subject for Build ${BUILD_NUMBER}
|
|
body: The build has finished
|
|
attach-build-log: false
|
|
unstable: true
|
|
first-failure: true
|
|
not-built: true
|
|
aborted: true
|
|
regression: true
|
|
failure: true
|
|
improvement: true
|
|
still-failing: true
|
|
success: true
|
|
fixed: true
|
|
still-unstable: true
|
|
pre-build: true
|
|
"""
|
|
emailext = XML.SubElement(xml_parent,
|
|
'hudson.plugins.emailext.ExtendedEmailPublisher')
|
|
if 'recipients' in data:
|
|
XML.SubElement(emailext, 'recipientList').text = data['recipients']
|
|
else:
|
|
XML.SubElement(emailext, 'recipientList').text = '$DEFAULT_RECIPIENTS'
|
|
ctrigger = XML.SubElement(emailext, 'configuredTriggers')
|
|
if data.get('unstable', False):
|
|
base_email_ext(parser, ctrigger, data, 'UnstableTrigger')
|
|
if data.get('first-failure', False):
|
|
base_email_ext(parser, ctrigger, data, 'FirstFailureTrigger')
|
|
if data.get('not-built', False):
|
|
base_email_ext(parser, ctrigger, data, 'NotBuiltTrigger')
|
|
if data.get('aborted', False):
|
|
base_email_ext(parser, ctrigger, data, 'AbortedTrigger')
|
|
if data.get('regression', False):
|
|
base_email_ext(parser, ctrigger, data, 'RegressionTrigger')
|
|
if data.get('failure', True):
|
|
base_email_ext(parser, ctrigger, data, 'FailureTrigger')
|
|
if data.get('improvement', False):
|
|
base_email_ext(parser, ctrigger, data, 'ImprovementTrigger')
|
|
if data.get('still-failing', False):
|
|
base_email_ext(parser, ctrigger, data, 'StillFailingTrigger')
|
|
if data.get('success', False):
|
|
base_email_ext(parser, ctrigger, data, 'SuccessTrigger')
|
|
if data.get('fixed', False):
|
|
base_email_ext(parser, ctrigger, data, 'FixedTrigger')
|
|
if data.get('still-unstable', False):
|
|
base_email_ext(parser, ctrigger, data, 'StillUnstableTrigger')
|
|
if data.get('pre-build', False):
|
|
base_email_ext(parser, ctrigger, data, 'PreBuildTrigger')
|
|
XML.SubElement(emailext, 'contentType').text = 'default'
|
|
XML.SubElement(emailext, 'defaultSubject').text = data.get(
|
|
'subject', '$DEFAULT_SUBJECT')
|
|
XML.SubElement(emailext, 'defaultContent').text = data.get(
|
|
'body', '$DEFAULT_CONTENT')
|
|
XML.SubElement(emailext, 'attachmentsPattern').text = ''
|
|
XML.SubElement(emailext, 'presendScript').text = ''
|
|
XML.SubElement(emailext, 'attachBuildLog').text = \
|
|
str(data.get('attach-build-log', False)).lower()
|
|
XML.SubElement(emailext, 'replyTo').text = data.get('reply-to',
|
|
'$DEFAULT_RECIPIENTS')
|
|
|
|
|
|
def fingerprint(parser, xml_parent, data):
|
|
"""yaml: fingerprint
|
|
Fingerprint files to track them across builds
|
|
|
|
:arg str files: files to fingerprint, follows the @includes of Ant fileset
|
|
(default is blank)
|
|
:arg bool record-artifacts: fingerprint all archived artifacts
|
|
(default false)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- fingerprint:
|
|
files: builddir/test*.xml
|
|
record-artifacts: false
|
|
"""
|
|
finger = XML.SubElement(xml_parent, 'hudson.tasks.Fingerprinter')
|
|
XML.SubElement(finger, 'targets').text = data.get('files', '')
|
|
XML.SubElement(finger, 'recordBuildArtifacts').text = str(data.get(
|
|
'record-artifacts', False)).lower()
|
|
|
|
|
|
def aggregate_tests(parser, xml_parent, data):
|
|
"""yaml: aggregate-tests
|
|
Aggregate downstream test results
|
|
|
|
:arg bool include-failed-builds: whether to include failed builds
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- aggregate-tests:
|
|
include-failed-builds: true
|
|
"""
|
|
agg = XML.SubElement(xml_parent,
|
|
'hudson.tasks.test.AggregatedTestResultPublisher')
|
|
XML.SubElement(agg, 'includeFailedBuilds').text = str(data.get(
|
|
'include-failed-builds', False)).lower()
|
|
|
|
|
|
def cppcheck(parser, xml_parent, data):
|
|
"""yaml: cppcheck
|
|
Cppcheck result publisher
|
|
Requires the Jenkins `Cppcheck Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Cppcheck+Plugin>`_
|
|
|
|
:arg str pattern: file pattern for cppcheck xml report
|
|
|
|
for more optional parameters see the example
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- cppcheck:
|
|
pattern: "**/cppcheck.xml"
|
|
# the rest is optional
|
|
# build status (new) error count thresholds
|
|
thresholds:
|
|
unstable: 5
|
|
new-unstable: 5
|
|
failure: 7
|
|
new-failure: 3
|
|
# severities which count towards the threshold, default all true
|
|
severity:
|
|
error: true
|
|
warning: true
|
|
information: false
|
|
graph:
|
|
xysize: [500, 200]
|
|
# which errors to display, default only sum
|
|
display:
|
|
sum: false
|
|
error: true
|
|
"""
|
|
cppextbase = XML.SubElement(xml_parent,
|
|
'org.jenkinsci.plugins.cppcheck.'
|
|
'CppcheckPublisher')
|
|
cppext = XML.SubElement(cppextbase, 'cppcheckConfig')
|
|
XML.SubElement(cppext, 'pattern').text = data['pattern']
|
|
XML.SubElement(cppext, 'ignoreBlankFiles').text = \
|
|
str(data.get('ignoreblankfiles', False)).lower()
|
|
|
|
csev = XML.SubElement(cppext, 'configSeverityEvaluation')
|
|
thrsh = data.get('thresholds', {})
|
|
XML.SubElement(csev, 'threshold').text = str(thrsh.get('unstable', ''))
|
|
XML.SubElement(csev, 'newThreshold').text = \
|
|
str(thrsh.get('new-unstable', ''))
|
|
XML.SubElement(csev, 'failureThreshold').text = \
|
|
str(thrsh.get('failure', ''))
|
|
XML.SubElement(csev, 'newFailureThreshold').text = \
|
|
str(thrsh.get('new-failure', ''))
|
|
XML.SubElement(csev, 'healthy').text = str(thrsh.get('healthy', ''))
|
|
XML.SubElement(csev, 'unHealthy').text = str(thrsh.get('unhealthy', ''))
|
|
|
|
sev = thrsh.get('severity', {})
|
|
XML.SubElement(csev, 'severityError').text = \
|
|
str(sev.get('error', True)).lower()
|
|
XML.SubElement(csev, 'severityWarning').text = \
|
|
str(sev.get('warning', True)).lower()
|
|
XML.SubElement(csev, 'severityStyle').text = \
|
|
str(sev.get('style', True)).lower()
|
|
XML.SubElement(csev, 'severityPerformance').text = \
|
|
str(sev.get('performance', True)).lower()
|
|
XML.SubElement(csev, 'severityInformation').text = \
|
|
str(sev.get('information', True)).lower()
|
|
|
|
graph = data.get('graph', {})
|
|
cgraph = XML.SubElement(cppext, 'configGraph')
|
|
x, y = graph.get('xysize', [500, 200])
|
|
XML.SubElement(cgraph, 'xSize').text = str(x)
|
|
XML.SubElement(cgraph, 'ySize').text = str(y)
|
|
gdisplay = graph.get('display', {})
|
|
XML.SubElement(cgraph, 'displayAllErrors').text = \
|
|
str(gdisplay.get('sum', True)).lower()
|
|
XML.SubElement(cgraph, 'displayErrorSeverity').text = \
|
|
str(gdisplay.get('error', False)).lower()
|
|
XML.SubElement(cgraph, 'displayWarningSeverity').text = \
|
|
str(gdisplay.get('warning', False)).lower()
|
|
XML.SubElement(cgraph, 'displayStyleSeverity').text = \
|
|
str(gdisplay.get('style', False)).lower()
|
|
XML.SubElement(cgraph, 'displayPerformanceSeverity').text = \
|
|
str(gdisplay.get('performance', False)).lower()
|
|
XML.SubElement(cgraph, 'displayInformationSeverity').text = \
|
|
str(gdisplay.get('information', False)).lower()
|
|
|
|
|
|
def logparser(parser, xml_parent, data):
|
|
"""yaml: logparser
|
|
Requires the Jenkins `Log Parser Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Log+Parser+Plugin>`_
|
|
|
|
:arg str parse-rules: full path to parse rules
|
|
:arg bool unstable-on-warning: mark build unstable on warning
|
|
:arg bool fail-on-error: mark build failed on error
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- logparser:
|
|
parse-rules: "/path/to/parserules"
|
|
unstable-on-warning: true
|
|
fail-on-error: true
|
|
"""
|
|
|
|
clog = XML.SubElement(xml_parent,
|
|
'hudson.plugins.logparser.LogParserPublisher')
|
|
XML.SubElement(clog, 'unstableOnWarning').text = \
|
|
str(data.get('unstable-on-warning', False)).lower()
|
|
XML.SubElement(clog, 'failBuildOnError').text = \
|
|
str(data.get('fail-on-error', False)).lower()
|
|
# v1.08: this must be the full path, the name of the rules is not enough
|
|
XML.SubElement(clog, 'parsingRulesPath').text = data.get('parse-rules', '')
|
|
|
|
|
|
def copy_to_master(parser, xml_parent, data):
|
|
"""yaml: copy-to-master
|
|
Copy files to master from slave
|
|
Requires the Jenkins `Copy To Slave Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Copy+To+Slave+Plugin>`_
|
|
|
|
:arg list includes: list of file patterns to copy
|
|
:arg list excludes: list of file patterns to exclude
|
|
:arg string destination: absolute path into which the files will be copied.
|
|
If left blank they will be copied into the
|
|
workspace of the current job
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- copy-to-master:
|
|
includes:
|
|
- file1
|
|
- file2*.txt
|
|
excludes:
|
|
- file2bad.txt
|
|
"""
|
|
p = 'com.michelin.cio.hudson.plugins.copytoslave.CopyToMasterNotifier'
|
|
cm = XML.SubElement(xml_parent, p)
|
|
|
|
XML.SubElement(cm, 'includes').text = ','.join(data.get('includes', ['']))
|
|
XML.SubElement(cm, 'excludes').text = ','.join(data.get('excludes', ['']))
|
|
|
|
XML.SubElement(cm, 'destinationFolder').text = \
|
|
data.get('destination', '')
|
|
|
|
if data.get('destination', ''):
|
|
XML.SubElement(cm, 'overrideDestinationFolder').text = 'true'
|
|
|
|
|
|
def jira(parser, xml_parent, data):
|
|
"""yaml: jira
|
|
Update relevant JIRA issues
|
|
Requires the Jenkins `JIRA Plugin
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/JIRA+Plugin>`_
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- jira
|
|
"""
|
|
XML.SubElement(xml_parent, 'hudson.plugins.jira.JiraIssueUpdater')
|
|
|
|
|
|
def groovy_postbuild(parser, xml_parent, data):
|
|
"""yaml: groovy-postbuild
|
|
Execute a groovy script.
|
|
Requires the Jenkins `Groovy Postbuild Plugin
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin>`_
|
|
|
|
:Parameter: the groovy script to execute
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- groovy-postbuild: "manager.buildFailure()"
|
|
|
|
"""
|
|
root_tag = 'org.jvnet.hudson.plugins.groovypostbuild.'\
|
|
'GroovyPostbuildRecorder'
|
|
groovy = XML.SubElement(xml_parent, root_tag)
|
|
XML.SubElement(groovy, 'groovyScript').text = data
|
|
|
|
|
|
def base_publish_over(xml_parent, data, console_prefix,
|
|
plugin_tag, publisher_tag,
|
|
transferset_tag, reference_plugin_tag):
|
|
outer = XML.SubElement(xml_parent, plugin_tag)
|
|
XML.SubElement(outer, 'consolePrefix').text = console_prefix
|
|
delegate = XML.SubElement(outer, 'delegate')
|
|
publishers = XML.SubElement(delegate, 'publishers')
|
|
inner = XML.SubElement(publishers, publisher_tag)
|
|
XML.SubElement(inner, 'configName').text = data['site']
|
|
XML.SubElement(inner, 'verbose').text = 'true'
|
|
|
|
transfers = XML.SubElement(inner, 'transfers')
|
|
transfersset = XML.SubElement(transfers, transferset_tag)
|
|
XML.SubElement(transfersset, 'remoteDirectory').text = data['target']
|
|
XML.SubElement(transfersset, 'sourceFiles').text = data['source']
|
|
if 'command' in data:
|
|
XML.SubElement(transfersset, 'execCommand').text = data['command']
|
|
if 'timeout' in data:
|
|
XML.SubElement(transfersset, 'execTimeout').text = str(data['timeout'])
|
|
if 'use-pty' in data:
|
|
XML.SubElement(transfersset, 'usePty').text = \
|
|
str(data.get('use-pty', False)).lower()
|
|
XML.SubElement(transfersset, 'excludes').text = data.get('excludes', '')
|
|
XML.SubElement(transfersset, 'removePrefix').text = \
|
|
data.get('remove-prefix', '')
|
|
XML.SubElement(transfersset, 'remoteDirectorySDF').text = \
|
|
str(data.get('target-is-date-format', False)).lower()
|
|
XML.SubElement(transfersset, 'flatten').text = 'false'
|
|
XML.SubElement(transfersset, 'cleanRemote').text = \
|
|
str(data.get('clean-remote', False)).lower()
|
|
|
|
XML.SubElement(inner, 'useWorkspaceInPromotion').text = 'false'
|
|
XML.SubElement(inner, 'usePromotionTimestamp').text = 'false'
|
|
XML.SubElement(delegate, 'continueOnError').text = 'false'
|
|
XML.SubElement(delegate, 'failOnError').text = \
|
|
str(data.get('fail-on-error', False)).lower()
|
|
XML.SubElement(delegate, 'alwaysPublishFromMaster').text = 'false'
|
|
XML.SubElement(delegate, 'hostConfigurationAccess',
|
|
{'class': reference_plugin_tag,
|
|
'reference': '../..'})
|
|
return (outer, transfersset)
|
|
|
|
|
|
def cifs(parser, xml_parent, data):
|
|
"""yaml: cifs
|
|
Upload files via CIFS.
|
|
Requires the Jenkins `Publish over CIFS Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+CIFS+Plugin>`_
|
|
|
|
:arg str site: name of the cifs site/share
|
|
:arg str target: destination directory
|
|
:arg bool target-is-date-format: whether target is a date format. If true,
|
|
raw text should be quoted (defaults to False)
|
|
:arg bool clean-remote: should the remote directory be deleted before
|
|
transfering files (defaults to False)
|
|
:arg str source: source path specifier
|
|
:arg str excludes: excluded file pattern (optional)
|
|
:arg str remove-prefix: prefix to remove from uploaded file paths
|
|
(optional)
|
|
:arg bool fail-on-error: fail the build if an error occurs (defaults to
|
|
False).
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- cifs:
|
|
site: 'cifs.share'
|
|
target: 'dest/dir'
|
|
source: 'base/source/dir/**'
|
|
remove-prefix: 'base/source/dir'
|
|
excludes: '**/*.excludedfiletype'
|
|
"""
|
|
console_prefix = 'CIFS: '
|
|
plugin_tag = 'jenkins.plugins.publish__over__cifs.CifsPublisherPlugin'
|
|
publisher_tag = 'jenkins.plugins.publish__over__cifs.CifsPublisher'
|
|
transfer_tag = 'jenkins.plugins.publish__over__cifs.CifsTransfer'
|
|
plugin_reference_tag = 'jenkins.plugins.publish_over_cifs.' \
|
|
'CifsPublisherPlugin'
|
|
base_publish_over(xml_parent,
|
|
data,
|
|
console_prefix,
|
|
plugin_tag,
|
|
publisher_tag,
|
|
transfer_tag,
|
|
plugin_reference_tag)
|
|
|
|
|
|
def sonar(parser, xml_parent, data):
|
|
"""yaml: sonar
|
|
Sonar plugin support.
|
|
Requires the Jenkins `Sonar Plugin.
|
|
<http://docs.codehaus.org/pages/viewpage.action?pageId=116359341>`_
|
|
|
|
:arg str jdk: JDK to use (inherited from the job if omitted). (optional)
|
|
:arg str branch: branch onto which the analysis will be posted (optional)
|
|
:arg str language: source code language (optional)
|
|
:arg str maven-opts: options given to maven (optional)
|
|
:arg str additional-properties: sonar analysis parameters (optional)
|
|
:arg dict skip-global-triggers:
|
|
:Triggers: * **skip-when-scm-change** (`bool`): skip analysis when
|
|
build triggered by scm
|
|
* **skip-when-upstream-build** (`bool`): skip analysis when
|
|
build triggered by an upstream build
|
|
* **skip-when-envvar-defined** (`str`): skip analysis when
|
|
the specified environment variable is set to true
|
|
|
|
This publisher supports the post-build action exposed by the Jenkins
|
|
Sonar Plugin, which is triggering a Sonar Analysis with Maven.
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- sonar:
|
|
jdk: MyJdk
|
|
branch: myBranch
|
|
language: java
|
|
maven-opts: -DskipTests
|
|
additional-properties: -DsonarHostURL=http://example.com/
|
|
skip-global-triggers:
|
|
skip-when-scm-change: true
|
|
skip-when-upstream-build: true
|
|
skip-when-envvar-defined: SKIP_SONAR
|
|
"""
|
|
sonar = XML.SubElement(xml_parent, 'hudson.plugins.sonar.SonarPublisher')
|
|
if 'jdk' in data:
|
|
XML.SubElement(sonar, 'jdk').text = data['jdk']
|
|
XML.SubElement(sonar, 'branch').text = data.get('branch', '')
|
|
XML.SubElement(sonar, 'language').text = data.get('language', '')
|
|
XML.SubElement(sonar, 'mavenOpts').text = data.get('maven-opts', '')
|
|
XML.SubElement(sonar, 'jobAdditionalProperties').text = \
|
|
data.get('additional-properties', '')
|
|
if 'skip-global-triggers' in data:
|
|
data_triggers = data['skip-global-triggers']
|
|
triggers = XML.SubElement(sonar, 'triggers')
|
|
XML.SubElement(triggers, 'skipScmCause').text = \
|
|
str(data_triggers.get('skip-when-scm-change', False)).lower()
|
|
XML.SubElement(triggers, 'skipUpstreamCause').text = \
|
|
str(data_triggers.get('skip-when-upstream-build', False)).lower()
|
|
XML.SubElement(triggers, 'envVar').text = \
|
|
data_triggers.get('skip-when-envvar-defined', '')
|
|
|
|
|
|
def performance(parser, xml_parent, data):
|
|
"""yaml: performance
|
|
Publish performance test results from jmeter and junit.
|
|
Requires the Jenkins `Performance Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Performance+Plugin>`_
|
|
|
|
:arg int failed-threshold: Specify the error percentage threshold that
|
|
set the build failed. A negative value means
|
|
don't use this threshold (default 0)
|
|
:arg int unstable-threshold: Specify the error percentage threshold that
|
|
set the build unstable. A negative value means
|
|
don't use this threshold (default 0)
|
|
:arg dict report:
|
|
|
|
:(jmeter or junit): (`dict` or `str`): Specify a custom report file
|
|
(optional; jmeter default \**/*.jtl, junit default **/TEST-\*.xml)
|
|
|
|
Examples::
|
|
|
|
publishers:
|
|
- performance:
|
|
failed-threshold: 85
|
|
unstable-threshold: -1
|
|
report:
|
|
- jmeter: "/special/file.jtl"
|
|
- junit: "/special/file.xml"
|
|
|
|
publishers:
|
|
- performance:
|
|
failed-threshold: 85
|
|
unstable-threshold: -1
|
|
report:
|
|
- jmeter
|
|
- junit
|
|
|
|
publishers:
|
|
- performance:
|
|
failed-threshold: 85
|
|
unstable-threshold: -1
|
|
report:
|
|
- jmeter: "/special/file.jtl"
|
|
- junit: "/special/file.xml"
|
|
- jmeter
|
|
- junit
|
|
"""
|
|
logger = logging.getLogger(__name__)
|
|
|
|
perf = XML.SubElement(xml_parent, 'hudson.plugins.performance.'
|
|
'PerformancePublisher')
|
|
XML.SubElement(perf, 'errorFailedThreshold').text = str(data.get(
|
|
'failed-threshold', 0))
|
|
XML.SubElement(perf, 'errorUnstableThreshold').text = str(data.get(
|
|
'unstable-threshold', 0))
|
|
parsers = XML.SubElement(perf, 'parsers')
|
|
for item in data['report']:
|
|
if isinstance(item, dict):
|
|
item_name = item.keys()[0]
|
|
item_values = item.get(item_name, None)
|
|
if item_name == 'jmeter':
|
|
jmhold = XML.SubElement(parsers, 'hudson.plugins.performance.'
|
|
'JMeterParser')
|
|
XML.SubElement(jmhold, 'glob').text = str(item_values)
|
|
elif item_name == 'junit':
|
|
juhold = XML.SubElement(parsers, 'hudson.plugins.performance.'
|
|
'JUnitParser')
|
|
XML.SubElement(juhold, 'glob').text = str(item_values)
|
|
else:
|
|
logger.fatal("You have not specified jmeter or junit, or "
|
|
"you have incorrectly assigned the key value.")
|
|
sys.exit(1)
|
|
elif isinstance(item, str):
|
|
if item == 'jmeter':
|
|
jmhold = XML.SubElement(parsers, 'hudson.plugins.performance.'
|
|
'JMeterParser')
|
|
XML.SubElement(jmhold, 'glob').text = '**/*.jtl'
|
|
elif item == 'junit':
|
|
juhold = XML.SubElement(parsers, 'hudson.plugins.performance.'
|
|
'JUnitParser')
|
|
XML.SubElement(juhold, 'glob').text = '**/TEST-*.xml'
|
|
else:
|
|
logger.fatal("You have not specified jmeter or junit, or "
|
|
"you have incorrectly assigned the key value.")
|
|
sys.exit(1)
|
|
|
|
|
|
def join_trigger(parser, xml_parent, data):
|
|
"""yaml: join-trigger
|
|
Trigger a job after all the immediate downstream jobs have completed
|
|
|
|
:arg list projects: list of projects to trigger
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- join-trigger:
|
|
projects:
|
|
- project-one
|
|
- project-two
|
|
"""
|
|
jointrigger = XML.SubElement(xml_parent, 'join.JoinTrigger')
|
|
|
|
# Simple Project List
|
|
joinProjectsText = ','.join(data.get('projects', ['']))
|
|
XML.SubElement(jointrigger, 'joinProjects').text = joinProjectsText
|
|
|
|
|
|
def jabber(parser, xml_parent, data):
|
|
"""yaml: jabber
|
|
Integrates Jenkins with the Jabber/XMPP instant messaging protocol
|
|
Requires the Jenkins `Jabber Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Jabber+Plugin>`_
|
|
|
|
:arg bool notify-on-build-start: Whether to send notifications
|
|
to channels when a build starts (default false)
|
|
:arg bool notify-scm-committers: Whether to send notifications
|
|
to the users that are suspected of having broken this build
|
|
(default false)
|
|
:arg bool notify-scm-culprits: Also send notifications to 'culprits'
|
|
from previous unstable/failed builds (default false)
|
|
:arg bool notify-upstream-committers: Whether to send notifications to
|
|
upstream committers if no committers were found for a broken build
|
|
(default false)
|
|
:arg bool notify-scm-fixers: Whether to send notifications to the users
|
|
that have fixed a broken build (default false)
|
|
:arg list group-targets: List of group targets to notify
|
|
:arg list individual-targets: List of individual targets to notify
|
|
:arg dict strategy: When to send notifications (default all)
|
|
|
|
:strategy values:
|
|
* **all** -- Always
|
|
* **failure** -- On any failure
|
|
* **failure-fixed** -- On failure and fixes
|
|
* **change** -- Only on state change
|
|
:arg dict message: Channel notification message (default summary-scm)
|
|
|
|
:message values:
|
|
* **summary-scm** -- Summary + SCM changes
|
|
* **summary** -- Just summary
|
|
* **summary-build** -- Summary and build parameters
|
|
* **summary-scm-fail** -- Summary, SCM changes, and failed tests
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- jabber:
|
|
notify-on-build-start: true
|
|
group-targets:
|
|
- "foo-room@conference-2-fooserver.foo.com"
|
|
individual-targets:
|
|
- "foo-user@conference-2-fooserver.foo.com"
|
|
strategy: all
|
|
message: summary-scm
|
|
"""
|
|
j = XML.SubElement(xml_parent, 'hudson.plugins.jabber.im.transport.'
|
|
'JabberPublisher')
|
|
t = XML.SubElement(j, 'targets')
|
|
if 'group-targets' in data:
|
|
for group in data['group-targets']:
|
|
gcimt = XML.SubElement(t, 'hudson.plugins.im.'
|
|
'GroupChatIMMessageTarget')
|
|
XML.SubElement(gcimt, 'name').text = group
|
|
XML.SubElement(gcimt, 'notificationOnly').text = 'false'
|
|
if 'individual-targets' in data:
|
|
for individual in data['individual-targets']:
|
|
dimt = XML.SubElement(t, 'hudson.plugins.im.'
|
|
'DefaultIMMessageTarget')
|
|
XML.SubElement(dimt, 'value').text = individual
|
|
strategy = data.get('strategy', 'all')
|
|
strategydict = {'all': 'ALL',
|
|
'failure': 'ANY_FAILURE',
|
|
'failure-fixed': 'FAILURE_AND_FIXED',
|
|
'change': 'STATECHANGE_ONLY'}
|
|
if strategy not in strategydict:
|
|
raise JenkinsJobsException("Strategy entered is not valid, must be " +
|
|
"one of: all, failure, failure-fixed, or "
|
|
"change")
|
|
XML.SubElement(j, 'strategy').text = strategydict[strategy]
|
|
XML.SubElement(j, 'notifyOnBuildStart').text = str(
|
|
data.get('notify-on-build-start', False)).lower()
|
|
XML.SubElement(j, 'notifySuspects').text = str(
|
|
data.get('notify-scm-committers', False)).lower()
|
|
XML.SubElement(j, 'notifyCulprits').text = str(
|
|
data.get('notify-scm-culprits', False)).lower()
|
|
XML.SubElement(j, 'notifyFixers').text = str(
|
|
data.get('notify-scm-fixers', False)).lower()
|
|
XML.SubElement(j, 'notifyUpstreamCommitters').text = str(
|
|
data.get('notify-upstream-committers', False)).lower()
|
|
message = data.get('message', 'summary-scm')
|
|
messagedict = {'summary-scm': 'DefaultBuildToChatNotifier',
|
|
'summary': 'SummaryOnlyBuildToChatNotifier',
|
|
'summary-build': 'BuildParametersBuildToChatNotifier',
|
|
'summary-scm-fail': 'PrintFailingTestsBuildToChatNotifier'}
|
|
if message not in messagedict:
|
|
raise JenkinsJobsException("Message entered is not valid, must be one "
|
|
"of: summary-scm, summary, summary-build "
|
|
"or summary-scm-fail")
|
|
XML.SubElement(j, 'buildToChatNotifier', {
|
|
'class': 'hudson.plugins.im.build_notify.' + messagedict[message]})
|
|
XML.SubElement(j, 'matrixMultiplier').text = 'ONLY_CONFIGURATIONS'
|
|
|
|
|
|
def workspace_cleanup(parser, xml_parent, data):
|
|
"""yaml: workspace-cleanup (post-build)
|
|
|
|
Requires the Jenkins `Workspace Cleanup Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Workspace+Cleanup+Plugin>`_
|
|
|
|
The pre-build workspace-cleanup is available as a wrapper.
|
|
|
|
:arg list include: list of files to be included
|
|
:arg list exclude: list of files to be excluded
|
|
:arg bool dirmatch: Apply pattern to directories too (default: false)
|
|
:arg list clean-if: clean depending on build status
|
|
|
|
:clean-if values:
|
|
* **success** (`bool`) (default: true)
|
|
* **unstable** (`bool`) (default: true)
|
|
* **failure** (`bool`) (default: true)
|
|
* **aborted** (`bool`) (default: true)
|
|
* **not-built** (`bool`) (default: true)
|
|
:arg bool fail-build: Fail the build if the cleanup fails (default: true)
|
|
:arg bool clean-parent: Cleanup matrix parent workspace (default: false)
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- workspace-cleanup:
|
|
include:
|
|
- "*.zip"
|
|
clean-if:
|
|
- success: true
|
|
- not-built: false
|
|
"""
|
|
|
|
p = XML.SubElement(xml_parent,
|
|
'hudson.plugins.ws__cleanup.WsCleanup')
|
|
p.set("plugin", "ws-cleanup@0.14")
|
|
if "include" in data or "exclude" in data:
|
|
patterns = XML.SubElement(p, 'patterns')
|
|
|
|
for inc in data.get("include", []):
|
|
ptrn = XML.SubElement(patterns, 'hudson.plugins.ws__cleanup.Pattern')
|
|
XML.SubElement(ptrn, 'pattern').text = inc
|
|
XML.SubElement(ptrn, 'type').text = "INCLUDE"
|
|
|
|
for exc in data.get("exclude", []):
|
|
ptrn = XML.SubElement(patterns, 'hudson.plugins.ws__cleanup.Pattern')
|
|
XML.SubElement(ptrn, 'pattern').text = exc
|
|
XML.SubElement(ptrn, 'type').text = "EXCLUDE"
|
|
|
|
XML.SubElement(p, 'deleteDirs').text = \
|
|
str(data.get("dirmatch", False)).lower()
|
|
XML.SubElement(p, 'cleanupMatrixParent').text = \
|
|
str(data.get("clean-parent", False)).lower()
|
|
|
|
mask = {'success': 'cleanWhenSuccess', 'unstable': 'cleanWhenUnstable',
|
|
'failure': 'cleanWhenFailure', 'not-built': 'cleanWhenNotBuilt',
|
|
'aborted': 'cleanWhenAborted'}
|
|
clean = data.get('clean-if', [])
|
|
cdict = dict()
|
|
for d in clean:
|
|
cdict.update(d)
|
|
for k, v in mask.iteritems():
|
|
XML.SubElement(p, v).text = str(cdict.pop(k, True)).lower()
|
|
|
|
if len(cdict) > 0:
|
|
raise ValueError('clean-if must be one of: %r' % list(mask.keys()))
|
|
|
|
if str(data.get("fail-build", False)).lower() == 'false':
|
|
XML.SubElement(p, 'notFailBuild').text = 'true'
|
|
else:
|
|
XML.SubElement(p, 'notFailBuild').text = 'false'
|
|
|
|
|
|
def maven_deploy(parser, xml_parent, data):
|
|
"""yaml: maven-deploy
|
|
Deploy artifacts to Maven repository.
|
|
|
|
:arg str id: Repository ID
|
|
:arg str url: Repository URL
|
|
:arg bool unique-version: Assign unique versions to snapshots
|
|
(default true)
|
|
:arg bool deploy-unstable: Deploy even if the build is unstable
|
|
(default false)
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- maven-deploy:
|
|
id: example
|
|
url: http://repo.example.com/maven2/
|
|
unique-version: true
|
|
deploy-unstable: false
|
|
"""
|
|
|
|
p = XML.SubElement(xml_parent, 'hudson.maven.RedeployPublisher')
|
|
if 'id' in data:
|
|
XML.SubElement(p, 'id').text = data['id']
|
|
XML.SubElement(p, 'url').text = data['url']
|
|
XML.SubElement(p, 'uniqueVersion').text = str(
|
|
data.get('unique-version', True)).lower()
|
|
XML.SubElement(p, 'evenIfUnstable').text = str(
|
|
data.get('deploy-unstable', False)).lower()
|
|
|
|
|
|
def text_finder(parser, xml_parent, data):
|
|
"""yaml: text-finder
|
|
This plugin lets you search keywords in the files you specified and
|
|
additionally check build status
|
|
|
|
Requires the Jenkins `Text-finder Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Text-finder+Plugin>`_
|
|
|
|
:arg str regexp: Specify a regular expression
|
|
:arg str fileset: Specify the path to search
|
|
:arg bool also-check-console-output:
|
|
Search the console output (default False)
|
|
:arg bool succeed-if-found:
|
|
Force a build to succeed if a string was found (default False)
|
|
:arg bool unstable-if-found:
|
|
Set build unstable instead of failing the build (default False)
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- text-finder:
|
|
regexp: "some string"
|
|
fileset: "file.txt"
|
|
also-check-console-output: true
|
|
succeed-if-found: false
|
|
unstable-if-found: false
|
|
"""
|
|
|
|
finder = XML.SubElement(xml_parent,
|
|
'hudson.plugins.textfinder.TextFinderPublisher')
|
|
if ('fileset' in data):
|
|
XML.SubElement(finder, 'fileSet').text = data['fileset']
|
|
XML.SubElement(finder, 'regexp').text = data['regexp']
|
|
check_output = str(data.get('also-check-console-output', False)).lower()
|
|
XML.SubElement(finder, 'alsoCheckConsoleOutput').text = check_output
|
|
succeed_if_found = str(data.get('succeed-if-found', False)).lower()
|
|
XML.SubElement(finder, 'succeedIfFound').text = succeed_if_found
|
|
unstable_if_found = str(data.get('unstable-if-found', False)).lower()
|
|
XML.SubElement(finder, 'unstableIfFound').text = unstable_if_found
|
|
|
|
|
|
def html_publisher(parser, xml_parent, data):
|
|
"""yaml: html-publisher
|
|
This plugin publishes HTML reports.
|
|
|
|
Requires the Jenkins `HTML Publisher Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/HTML+Publisher+Plugin>`_
|
|
|
|
:arg str name: Report name
|
|
:arg str dir: HTML directory to archive
|
|
:arg str files: Specify the pages to display
|
|
:arg bool keep-all: keep HTML reports for each past build (Default False)
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- html-publisher:
|
|
name: "some name"
|
|
dir: "path/"
|
|
files: "index.html"
|
|
keep-all: true
|
|
"""
|
|
|
|
reporter = XML.SubElement(xml_parent, 'htmlpublisher.HtmlPublisher')
|
|
targets = XML.SubElement(reporter, 'reportTargets')
|
|
ptarget = XML.SubElement(targets, 'htmlpublisher.HtmlPublisherTarget')
|
|
XML.SubElement(ptarget, 'reportName').text = data['name']
|
|
XML.SubElement(ptarget, 'reportDir').text = data['dir']
|
|
XML.SubElement(ptarget, 'reportFiles').text = data['files']
|
|
keep_all = str(data.get('keep-all', False)).lower()
|
|
XML.SubElement(ptarget, 'keepAll').text = keep_all
|
|
XML.SubElement(ptarget, 'wrapperName').text = "htmlpublisher-wrapper.html"
|
|
|
|
|
|
def tap(parser, xml_parent, data):
|
|
"""yaml: tap
|
|
Adds support to TAP test result files
|
|
|
|
Requires the Jenkins `TAP Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/TAP+Plugin>`_
|
|
|
|
:arg str results: TAP test result files
|
|
:arg bool fail-if-no-results: Fail if no result (default False)
|
|
:arg bool failed-tests-mark-build-as-failure:
|
|
Mark build as failure if test fails (default False)
|
|
:arg bool output-tap-to-console: Output tap to console (default True)
|
|
:arg bool enable-subtests: Enable subtests (Default True)
|
|
:arg bool discard-old-reports: Discard old reports (Default False)
|
|
:arg bool todo-is-failure: Handle TODO's as failures (Default True)
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- tap:
|
|
results: puiparts.tap
|
|
todo-is-failure: false
|
|
"""
|
|
|
|
tap = XML.SubElement(xml_parent, 'org.tap4j.plugin.TapPublisher')
|
|
|
|
XML.SubElement(tap, 'testResults').text = data['results']
|
|
|
|
XML.SubElement(tap, 'failIfNoResults').text = str(
|
|
data.get('fail-if-no-results', False)).lower()
|
|
|
|
XML.SubElement(tap, 'failedTestsMarkBuildAsFailure').text = str(
|
|
data.get('failed-tests-mark-build-as-failure', False)).lower()
|
|
|
|
XML.SubElement(tap, 'outputTapToConsole').text = str(
|
|
data.get('output-tap-to-console', True)).lower()
|
|
|
|
XML.SubElement(tap, 'enableSubtests').text = str(
|
|
data.get('enable-subtests', True)).lower()
|
|
|
|
XML.SubElement(tap, 'discardOldReports').text = str(
|
|
data.get('discard-old-reports', False)).lower()
|
|
|
|
XML.SubElement(tap, 'todoIsFailure').text = str(
|
|
data.get('todo-is-failure', True)).lower()
|
|
|
|
|
|
def post_tasks(parser, xml_parent, data):
|
|
"""yaml: post-tasks
|
|
Adds support to post build task plugin
|
|
|
|
Requires the Jenkins `Post Build Task plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Post+build+task>`_
|
|
|
|
:arg dict task: Post build task definition
|
|
:arg list task[matches]: list of matches when to run the task
|
|
:arg dict task[matches][*]: match definition
|
|
:arg str task[matches][*][log-text]: text to match against the log
|
|
:arg str task[matches][*][operator]: operator to apply with the next match
|
|
|
|
:task[matches][*][operator] values (default 'AND'):
|
|
* **AND**
|
|
* **OR**
|
|
|
|
:arg bool task[escalate-status]: Escalate the task status to the job
|
|
(default 'false')
|
|
:arg bool task[run-if-job-successful]: Run only if the job was successful
|
|
(default 'false')
|
|
:arg str task[script]: Shell script to run (default '')
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- post-tasks:
|
|
- matches:
|
|
- log-text: line to match
|
|
operator: AND
|
|
- log-text: line to match
|
|
operator: OR
|
|
- log-text: line to match
|
|
operator: AND
|
|
escalate-status: false
|
|
run-if-job-successful:false
|
|
script: |
|
|
echo "Here goes the task script"
|
|
"""
|
|
|
|
pb_xml = XML.SubElement(xml_parent,
|
|
'hudson.plugins.postbuildtask.PostbuildTask')
|
|
tasks_xml = XML.SubElement(pb_xml, 'tasks')
|
|
for task in data:
|
|
task_xml = XML.SubElement(
|
|
tasks_xml,
|
|
'hudson.plugins.postbuildtask.TaskProperties')
|
|
matches_xml = XML.SubElement(task_xml, 'logTexts')
|
|
for match in task.get('matches', []):
|
|
lt_xml = XML.SubElement(
|
|
matches_xml,
|
|
'hudson.plugins.postbuildtask.LogProperties')
|
|
XML.SubElement(lt_xml, 'logText').text = str(
|
|
match.get('log-text', ''))
|
|
XML.SubElement(lt_xml, 'operator').text = str(
|
|
match.get('operator', 'AND')).upper()
|
|
XML.SubElement(task_xml, 'EscalateStatus').text = str(
|
|
task.get('escalate-status', False)).lower()
|
|
XML.SubElement(task_xml, 'RunIfJobSuccessful').text = str(
|
|
task.get('run-if-job-successful', False)).lower()
|
|
XML.SubElement(task_xml, 'script').text = str(
|
|
task.get('script', ''))
|
|
|
|
|
|
def xml_summary(parser, xml_parent, data):
|
|
"""yaml: xml-summary
|
|
Adds support for the Summary Display Plugin
|
|
|
|
Requires the Jenkins `Summary Display Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Summary+Display+Plugin>`_
|
|
|
|
:arg str files: Files to parse (default '')
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- xml-summary:
|
|
files: '*_summary_report.xml'
|
|
"""
|
|
|
|
summary = XML.SubElement(xml_parent,
|
|
'hudson.plugins.summary__report.'
|
|
'ACIPluginPublisher')
|
|
XML.SubElement(summary, 'name').text = data['files']
|
|
|
|
|
|
def robot(parser, xml_parent, data):
|
|
"""yaml: robot
|
|
Adds support for the Robot Framework Plugin
|
|
|
|
Requires the Jenkins `Robot Framework Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Robot+Framework+Plugin>`_
|
|
|
|
:arg str output-path: Path to directory containing robot xml and html files
|
|
relative to build workspace. (default '')
|
|
:arg str log-file-link: Name of log or report file to be linked on jobs
|
|
front page (default '')
|
|
:arg str report-html: Name of the html file containing robot test report
|
|
(default 'report.html')
|
|
:arg str log-html: Name of the html file containing detailed robot test log
|
|
(default 'log.html')
|
|
:arg str output-xml: Name of the xml file containing robot output
|
|
(default 'output.xml')
|
|
:arg str pass-threshold: Minimum percentage of passed tests to consider
|
|
the build succesful (default 0.0)
|
|
:arg str unstable-threshold: Minimum percentage of passed test to
|
|
consider the build as not failed (default 0.0)
|
|
:arg bool only-critical: Take only critical tests into account when
|
|
checking the thresholds (default true)
|
|
:arg list other-files: list other files to archive (default '')
|
|
|
|
Example::
|
|
|
|
- publishers:
|
|
- robot:
|
|
output-path: reports/robot
|
|
log-file-link: report.html
|
|
report-html: report.html
|
|
log-html: log.html
|
|
output-xml: output.xml
|
|
pass-threshold: 80.0
|
|
unstable-threshold: 60.0
|
|
only-critical: false
|
|
other-files:
|
|
- extra-file1.html
|
|
- extra-file2.txt
|
|
"""
|
|
parent = XML.SubElement(xml_parent, 'hudson.plugins.robot.RobotPublisher')
|
|
XML.SubElement(parent, 'outputPath').text = data['output-path']
|
|
XML.SubElement(parent, 'logFileLink').text = str(
|
|
data.get('log-file-link', ''))
|
|
XML.SubElement(parent, 'reportFileName').text = str(
|
|
data.get('report-html', 'report.html'))
|
|
XML.SubElement(parent, 'logFileName').text = str(
|
|
data.get('log-html', 'log.html'))
|
|
XML.SubElement(parent, 'outputFileName').text = str(
|
|
data.get('output-xml', 'output.xml'))
|
|
XML.SubElement(parent, 'passThreshold').text = str(
|
|
data.get('pass-threshold', 0.0))
|
|
XML.SubElement(parent, 'unstableThreshold').text = str(
|
|
data.get('unstable-threshold', 0.0))
|
|
XML.SubElement(parent, 'onlyCritical').text = str(
|
|
data.get('only-critical', True)).lower()
|
|
other_files = XML.SubElement(parent, 'otherFiles')
|
|
for other_file in data['other-files']:
|
|
XML.SubElement(other_files, 'string').text = str(other_file)
|
|
|
|
|
|
def warnings(parser, xml_parent, data):
|
|
"""yaml: warnings
|
|
Generate trend report for compiler warnings in the console log or
|
|
in log files. Requires the Jenkins `Warnings Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Warnings+Plugin>`_
|
|
|
|
:arg list console-log-parsers: The parser to use to scan the console
|
|
log (default '')
|
|
:arg dict workspace-file-scanners:
|
|
|
|
:workspace-file-scanners:
|
|
* **file-pattern** (`str`) -- Fileset 'includes' setting that
|
|
specifies the files to scan for warnings
|
|
* **scanner** (`str`) -- The parser to use to scan the files
|
|
provided in workspace-file-pattern (default '')
|
|
:arg str files-to-include: Comma separated list of regular
|
|
expressions that specifies the files to include in the report
|
|
(based on their absolute filename). By default all files are
|
|
included
|
|
:arg str files-to-ignore: Comma separated list of regular expressions
|
|
that specifies the files to exclude from the report (based on their
|
|
absolute filename). (default '')
|
|
:arg bool run-always: By default, this plug-in runs only for stable or
|
|
unstable builds, but not for failed builds. Set to true if the
|
|
plug-in should run even for failed builds. (default false)
|
|
:arg bool detect-modules: Determines if Ant or Maven modules should be
|
|
detected for all files that contain warnings. Activating this
|
|
option may increase your build time since the detector scans
|
|
the whole workspace for 'build.xml' or 'pom.xml' files in order
|
|
to assign the correct module names. (default false)
|
|
:arg bool resolve-relative-paths: Determines if relative paths in
|
|
warnings should be resolved using a time expensive operation that
|
|
scans the whole workspace for matching files. Deactivate this
|
|
option if you encounter performance problems. (default false)
|
|
:arg int health-threshold-high: The upper threshold for the build
|
|
health. If left empty then no health report is created. If
|
|
the actual number of warnings is between the provided
|
|
thresholds then the build health is interpolated (default '')
|
|
:arg int health-threshold-low: The lower threshold for the build
|
|
health. See health-threshold-high. (default '')
|
|
:arg dict health-priorities: Determines which warning priorities
|
|
should be considered when evaluating the build health (default
|
|
all-priorities)
|
|
|
|
:health-priorities values:
|
|
* **priority-high** -- Only priority high
|
|
* **high-and-normal** -- Priorities high and normal
|
|
* **all-priorities** -- All priorities
|
|
:arg dict total-thresholds: If the number of total warnings is greater
|
|
than one of these thresholds then a build is considered as unstable
|
|
or failed, respectively. (default '')
|
|
|
|
:total-thresholds:
|
|
* **unstable** (`dict`)
|
|
:unstable: * **total-all** (`int`)
|
|
* **total-high** (`int`)
|
|
* **total-normal** (`int`)
|
|
* **total-low** (`int`)
|
|
* **failed** (`dict`)
|
|
:failed: * **total-all** (`int`)
|
|
* **total-high** (`int`)
|
|
* **total-normal** (`int`)
|
|
* **total-low** (`int`)
|
|
:arg dict new-thresholds: If the specified number of new warnings exceeds
|
|
one of these thresholds then a build is considered as unstable or
|
|
failed, respectively. (default '')
|
|
|
|
:new-thresholds:
|
|
* **unstable** (`dict`)
|
|
:unstable: * **new-all** (`int`)
|
|
* **new-high** (`int`)
|
|
* **new-normal** (`int`)
|
|
* **new-low** (`int`)
|
|
* **failed** (`dict`)
|
|
:failed: * **new-all** (`int`)
|
|
* **new-high** (`int`)
|
|
* **new-normal** (`int`)
|
|
* **new-high** (`int`)
|
|
:arg bool use-delta-for-new-warnings: If set then the number of new
|
|
warnings is calculated by subtracting the total number of warnings
|
|
of the current build from the reference build. This may lead to wrong
|
|
results if you have both fixed and new warnings in a build. If not set,
|
|
then the number of new warnings is calculated by an asymmetric set
|
|
difference of the warnings in the current and reference build. This
|
|
will find all new warnings even if the number of total warnings is
|
|
decreasing. However, sometimes false positives will be reported due
|
|
to minor changes in a warning (refactoring of variable of method
|
|
names, etc.) (default false)
|
|
:arg bool only-use-stable-builds-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 str default-encoding: Default encoding when parsing or showing files
|
|
Leave empty to use default encoding of platform (default '')
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- warnings:
|
|
console-log-parsers:
|
|
- FxCop
|
|
- CodeAnalysis
|
|
workspace-file-scanners:
|
|
- file-pattern: '**/*.out'
|
|
scanner: 'AcuCobol Compiler
|
|
- file-pattern: '**/*.warnings'
|
|
scanner: FxCop
|
|
files-to-include: '[a-zA-Z]\.java,[a-zA-Z]\.cpp'
|
|
files-to-ignore: '[a-zA-Z]\.html,[a-zA-Z]\.js'
|
|
run-always: true
|
|
detect-modules: true
|
|
resolve-relative-paths: true
|
|
health-threshold-high: 50
|
|
health-threshold-low: 25
|
|
health-priorities: high-and-normal
|
|
total-thresholds:
|
|
unstable:
|
|
total-all: 90
|
|
total-high: 90
|
|
total-normal: 40
|
|
total-low: 30
|
|
failed:
|
|
total-all: 100
|
|
total-high: 100
|
|
total-normal: 50
|
|
total-low: 40
|
|
new-thresholds:
|
|
unstable:
|
|
new-all: 100
|
|
new-high: 50
|
|
new-normal: 30
|
|
new-low: 10
|
|
failed:
|
|
new-all: 100
|
|
new-high: 60
|
|
new-normal: 50
|
|
new-low: 40
|
|
use-delta-for-new-warnings: true
|
|
only-use-stable-builds-as-reference: true
|
|
default-encoding: ISO-8859-9
|
|
"""
|
|
|
|
warnings = XML.SubElement(xml_parent,
|
|
'hudson.plugins.warnings.'
|
|
'WarningsPublisher')
|
|
console = XML.SubElement(warnings, 'consoleParsers')
|
|
for parser in data.get('console-log-parsers', []):
|
|
console_parser = XML.SubElement(console,
|
|
'hudson.plugins.warnings.'
|
|
'ConsoleParser')
|
|
XML.SubElement(console_parser, 'parserName').text = parser
|
|
workspace = XML.SubElement(warnings, 'parserConfigurations')
|
|
for wfs in data.get('workspace-file-scanners', []):
|
|
workspace_pattern = XML.SubElement(workspace,
|
|
'hudson.plugins.warnings.'
|
|
'ParserConfiguration')
|
|
XML.SubElement(workspace_pattern, 'pattern').text = \
|
|
wfs['file-pattern']
|
|
XML.SubElement(workspace_pattern, 'parserName').text = \
|
|
wfs['scanner']
|
|
warnings_to_include = data.get('files-to-include', '')
|
|
XML.SubElement(warnings, 'includePattern').text = warnings_to_include
|
|
warnings_to_ignore = data.get('files-to-ignore', '')
|
|
XML.SubElement(warnings, 'excludePattern').text = warnings_to_ignore
|
|
run_always = str(data.get('run-always', False)).lower()
|
|
XML.SubElement(warnings, 'canRunOnFailed').text = run_always
|
|
detect_modules = str(data.get('detect-modules', False)).lower()
|
|
XML.SubElement(warnings, 'shouldDetectModules').text = detect_modules
|
|
#Note the logic reversal (included here to match the GUI)
|
|
XML.SubElement(warnings, 'doNotResolveRelativePaths').text = \
|
|
str(not data.get('resolve-relative-paths', False)).lower()
|
|
health_threshold_high = str(data.get('health-threshold-high', ''))
|
|
XML.SubElement(warnings, 'healthy').text = health_threshold_high
|
|
health_threshold_low = str(data.get('health-threshold-low', ''))
|
|
XML.SubElement(warnings, 'unHealthy').text = health_threshold_low
|
|
prioritiesDict = {'priority-high': 'high',
|
|
'high-and-normal': 'normal',
|
|
'all-priorities': 'low'}
|
|
priority = data.get('health-priorities', 'all-priorities')
|
|
if priority not in prioritiesDict:
|
|
raise JenkinsJobsException("Health-Priority entered is not valid must "
|
|
"be one of: %s" %
|
|
",".join(prioritiesDict.keys()))
|
|
XML.SubElement(warnings, 'thresholdLimit').text = prioritiesDict[priority]
|
|
td = XML.SubElement(warnings, 'thresholds')
|
|
for base in ["total", "new"]:
|
|
thresholds = data.get("%s-thresholds" % base, {})
|
|
for status in ["unstable", "failed"]:
|
|
bystatus = thresholds.get(status, {})
|
|
for level in ["all", "high", "normal", "low"]:
|
|
val = str(bystatus.get("%s-%s" % (base, level), ''))
|
|
XML.SubElement(td, "%s%s%s" % (status,
|
|
base.capitalize(), level.capitalize())
|
|
).text = val
|
|
if data.get('new-thresholds'):
|
|
XML.SubElement(warnings, 'dontComputeNew').text = 'false'
|
|
delta = data.get('use-delta-for-new-warnings', False)
|
|
XML.SubElement(warnings, 'useDeltaValues').text = str(delta).lower()
|
|
use_stable_builds = data.get('only-use-stable-builds-as-reference',
|
|
False)
|
|
XML.SubElement(warnings, 'useStableBuildAsReference').text = str(
|
|
use_stable_builds).lower()
|
|
else:
|
|
XML.SubElement(warnings, 'dontComputeNew').text = 'true'
|
|
XML.SubElement(warnings, 'useStableBuildAsReference').text = 'false'
|
|
XML.SubElement(warnings, 'useDeltaValues').text = 'false'
|
|
encoding = data.get('default-encoding', '')
|
|
XML.SubElement(warnings, 'defaultEncoding').text = encoding
|
|
|
|
|
|
def sloccount(parser, xml_parent, data):
|
|
"""yaml: sloccount
|
|
Generates the trend report for SLOCCount
|
|
|
|
Requires the Jenkins `SLOCCount Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/SLOCCount+Plugin>`_
|
|
|
|
:arg str report-files: Setting that specifies the generated raw
|
|
SLOCCount report files.
|
|
Be sure not to include any non-report files into
|
|
this pattern. The report files must have been
|
|
generated by sloccount using the
|
|
"--wide --details" options.
|
|
(default: '\*\*/sloccount.sc')
|
|
:arg str charset: The character encoding to be used to read the SLOCCount
|
|
result files. (default: 'UTF-8')
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- sloccount:
|
|
report-files: sloccount.sc
|
|
charset: UTF-8
|
|
|
|
"""
|
|
top = XML.SubElement(xml_parent,
|
|
'hudson.plugins.sloccount.SloccountPublisher')
|
|
XML.SubElement(top, 'pattern').text = data.get('report-files',
|
|
'**/sloccount.sc')
|
|
XML.SubElement(top, 'encoding').text = data.get('charset', 'UTF-8')
|
|
|
|
|
|
def ircbot(parser, xml_parent, data):
|
|
"""yaml: ircbot
|
|
ircbot enables Jenkins to send build notifications via IRC and lets you
|
|
interact with Jenkins via an IRC bot.
|
|
|
|
Requires the Jenkins `IRC Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/IRC+Plugin>`_
|
|
|
|
:arg string strategy: When to send notifications
|
|
|
|
:strategy values:
|
|
* **all** always (default)
|
|
* **any-failure** on any failure_and_fixed
|
|
* **failure-and-fixed** on failure and fixes
|
|
* **new-failure-and-fixed** on new failure and fixes
|
|
* **statechange-only** only on state change
|
|
:arg bool notify-start: Whether to send notifications to channels when a
|
|
build starts
|
|
(default: false)
|
|
:arg bool notify-committers: Whether to send notifications to the users
|
|
that are suspected of having broken this build
|
|
(default: false)
|
|
:arg bool notify-culprits: Also send notifications to 'culprits' from
|
|
previous unstable/failed builds
|
|
(default: false)
|
|
:arg bool notify-upstream: Whether to send notifications to upstream
|
|
committers if no committers were found for a
|
|
broken build
|
|
(default: false)
|
|
:arg bool notify-fixers: Whether to send notifications to the users that
|
|
have fixed a broken build
|
|
(default: false)
|
|
:arg string message-type: Channel Notification Message.
|
|
|
|
:message-type values:
|
|
* **summary-scm** for summary and SCM changes (default)
|
|
* **summary** for summary only
|
|
* **summary-params** for summary and build parameters
|
|
* **summary-scm-fail** for summary, SCM changes, failures)
|
|
:arg list channels: list channels definitions
|
|
If empty, it takes channel from Jenkins configuration.
|
|
(default: empty)
|
|
WARNING: the IRC plugin requires the channel to be
|
|
configured in the system wide configuration or the jobs
|
|
will fail to emit notifications to the channel
|
|
|
|
:Channel: * **name** (`str`) Channel name
|
|
* **password** (`str`) Channel password (optional)
|
|
* **notify-only** (`bool`) Set to true if you want to
|
|
disallow bot commands (default: false)
|
|
:arg string matrix-notifier: notify for matrix projects
|
|
instant-messaging-plugin injects an additional
|
|
field in the configuration form whenever the
|
|
project is a multi-configuration project
|
|
|
|
:matrix-notifier values:
|
|
* **all**
|
|
* **only-configurations** (default)
|
|
* **only-parent**
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- ircbot:
|
|
strategy: all
|
|
notify-start: false
|
|
notify-committers: false
|
|
notify-culprits: false
|
|
notify-upstream: false
|
|
notify-fixers: false
|
|
message-type: summary-scm
|
|
channels:
|
|
- name: '#jenkins-channel1'
|
|
password: secrete
|
|
notify-only: false
|
|
- name: '#jenkins-channel2'
|
|
notify-only: true
|
|
matrix-notifier: only-configurations
|
|
|
|
"""
|
|
top = XML.SubElement(xml_parent, 'hudson.plugins.ircbot.IrcPublisher')
|
|
message_dict = {'summary-scm': 'DefaultBuildToChatNotifier',
|
|
'summary': 'SummaryOnlyBuildToChatNotifier',
|
|
'summary-params': 'BuildParametersBuildToChatNotifier',
|
|
'summary-scm-fail': 'PrintFailingTestsBuildToChatNotifier'}
|
|
message = data.get('message-type', 'summary-scm')
|
|
if message not in message_dict:
|
|
raise JenkinsJobsException("message-type entered is not valid, must "
|
|
"be one of: %s" %
|
|
", ".join(message_dict.keys()))
|
|
message = "hudson.plugins.im.build_notify." + message_dict.get(message)
|
|
XML.SubElement(top, 'buildToChatNotifier', attrib={'class': message})
|
|
strategy_dict = {'all': 'ALL',
|
|
'any-failure': 'ANY_FAILURE',
|
|
'failure-and-fixed': 'FAILURE_AND_FIXED',
|
|
'new-failure-and-fixed': 'NEW_FAILURE_AND_FIXED',
|
|
'statechange-only': 'STATECHANGE_ONLY'}
|
|
strategy = data.get('strategy', 'all')
|
|
if strategy not in strategy_dict:
|
|
raise JenkinsJobsException("strategy entered is not valid, must be "
|
|
"one of: %s" %
|
|
", ".join(strategy_dict.keys()))
|
|
XML.SubElement(top, 'strategy').text = strategy_dict.get(strategy)
|
|
targets = XML.SubElement(top, 'targets')
|
|
channels = data.get('channels', [])
|
|
for channel in channels:
|
|
sub = XML.SubElement(targets,
|
|
'hudson.plugins.im.GroupChatIMMessageTarget')
|
|
XML.SubElement(sub, 'name').text = channel.get('name')
|
|
XML.SubElement(sub, 'password').text = channel.get('password')
|
|
XML.SubElement(sub, 'notificationOnly').text = str(
|
|
channel.get('notify-only', False)).lower()
|
|
XML.SubElement(top, 'notifyOnBuildStart').text = str(
|
|
data.get('notify-start', False)).lower()
|
|
XML.SubElement(top, 'notifySuspects').text = str(
|
|
data.get('notify-committers', False)).lower()
|
|
XML.SubElement(top, 'notifyCulprits').text = str(
|
|
data.get('notify-culprits', False)).lower()
|
|
XML.SubElement(top, 'notifyFixers').text = str(
|
|
data.get('notify-fixers', False)).lower()
|
|
XML.SubElement(top, 'notifyUpstreamCommitters').text = str(
|
|
data.get('notify-upstream', False)).lower()
|
|
matrix_dict = {'all': 'ALL',
|
|
'only-configurations': 'ONLY_CONFIGURATIONS',
|
|
'only-parent': 'ONLY_PARENT'}
|
|
matrix = data.get('matrix-notifier', 'only_configurations')
|
|
if matrix not in matrix_dict:
|
|
raise JenkinsJobsException("matrix-notifier entered is not valid, "
|
|
"must be one of: %s" %
|
|
", ".join(matrix_dict.keys()))
|
|
XML.SubElement(top, 'matrixMultiplier').text = matrix_dict.get(matrix)
|
|
|
|
|
|
def plot(parser, xml_parent, data):
|
|
"""yaml: plot
|
|
Plot provides generic plotting (or graphing).
|
|
|
|
Requires the Jenkins `Plot Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Plot+Plugin>`_
|
|
|
|
:arg str title: title for the graph
|
|
(default: '')
|
|
:arg str yaxis: title of Y axis
|
|
:arg str group: name of the group to which the plot belongs
|
|
:arg int num-builds: number of builds to plot across
|
|
(default: plot all builds)
|
|
:arg str style: Specifies the graph style of the plot
|
|
Can be: area, bar, bar3d, line, line3d, stackedArea,
|
|
stackedbar, stackedbar3d, waterfall
|
|
(default: 'line')
|
|
:arg bool use-description: When false, the X-axis labels are formed
|
|
using build numbers and dates, and the
|
|
corresponding tooltips contain the build
|
|
descriptions. When enabled, the contents of
|
|
the labels and tooltips are swapped, with the
|
|
descriptions used as X-axis labels and the
|
|
build number and date used for tooltips.
|
|
(default: False)
|
|
:arg str csv-file-name: Use for choosing the file name in which the data
|
|
will be persisted. If none specified and random
|
|
name is generated as done in the Jenkins Plot
|
|
plugin.
|
|
(default: random generated .csv filename, same
|
|
behaviour as the Jenkins Plot plugin)
|
|
:arg list series: list data series definitions
|
|
|
|
:Serie: * **file** (`str`) : files to include
|
|
* **inclusion-flag** filtering mode for CSV files. Possible
|
|
values are:
|
|
|
|
* **off** (default)
|
|
* **include-by-string**
|
|
* **exclude-by-string**
|
|
* **include-by-column**
|
|
* **exclude-by-column**
|
|
|
|
* **exclude** (`str`) : exclude pattern for CSV file.
|
|
* **url** (`str`) : for 'csv' and 'xml' file types
|
|
used when you click on a point (default: empty)
|
|
* **display-table** (`bool`) : for 'csv' file type
|
|
if true, original CSV will be shown above plot (default: False)
|
|
* **label** (`str`) : used by 'properties' file type
|
|
Specifies the legend label for this data series.
|
|
(default: empty)
|
|
* **format** (`str`) : Type of file where we get datas.
|
|
Can be: properties, csv, xml
|
|
* **xpath-type** (`str`) : The result type of the expression must
|
|
be supplied due to limitations in the java.xml.xpath parsing.
|
|
The result can be: node, nodeset, boolean, string, or number.
|
|
Strings and numbers will be converted to double. Boolean will
|
|
be converted to 1 for true, and 0 for false. (default: 'node')
|
|
* **xpath** (`str`) : used by 'xml' file type
|
|
Xpath which selects the values that should be plotted.
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- plot:
|
|
- title: MyPlot
|
|
yaxis: Y
|
|
group: PlotGroup
|
|
num-builds: ''
|
|
style: line
|
|
use-description: false
|
|
series:
|
|
- file: graph-me-second.properties
|
|
label: MyLabel
|
|
format: properties
|
|
- file: graph-me-first.csv
|
|
url: 'http://srv1'
|
|
inclusion-flag: 'off'
|
|
display-table: true
|
|
format: csv
|
|
- title: MyPlot2
|
|
yaxis: Y
|
|
group: PlotGroup
|
|
style: line
|
|
use-description: false
|
|
series:
|
|
- file: graph-me-third.xml
|
|
url: 'http://srv2'
|
|
format: xml
|
|
xpath-type: 'node'
|
|
xpath: '/*'
|
|
|
|
"""
|
|
top = XML.SubElement(xml_parent, 'hudson.plugins.plot.PlotPublisher')
|
|
plots = XML.SubElement(top, 'plots')
|
|
format_dict = {'properties': 'hudson.plugins.plot.PropertiesSeries',
|
|
'csv': 'hudson.plugins.plot.CSVSeries',
|
|
'xml': 'hudson.plugins.plot.XMLSeries'}
|
|
xpath_dict = {'nodeset': 'NODESET', 'node': 'NODE', 'string': 'STRING',
|
|
'boolean': 'BOOLEAN', 'number': 'NUMBER'}
|
|
inclusion_dict = {'off': 'OFF',
|
|
'include-by-string': 'INCLUDE_BY_STRING',
|
|
'exclude-by-string': 'EXCLUDE_BY_STRING',
|
|
'include-by-column': 'INCLUDE_BY_COLUMN',
|
|
'exclude-by-column': 'EXCLUDE_BY_COLUMN'}
|
|
for plot in data:
|
|
plugin = XML.SubElement(plots, 'hudson.plugins.plot.Plot')
|
|
XML.SubElement(plugin, 'title').text = plot.get('title', '')
|
|
XML.SubElement(plugin, 'yaxis').text = plot['yaxis']
|
|
XML.SubElement(plugin, 'csvFileName').text = \
|
|
plot.get('csv-file-name', '%s.csv' % random.randrange(2 << 32))
|
|
topseries = XML.SubElement(plugin, 'series')
|
|
series = plot['series']
|
|
for serie in series:
|
|
format_data = serie.get('format')
|
|
if format_data not in format_dict:
|
|
raise JenkinsJobsException("format entered is not valid, must "
|
|
"be one of: %s" %
|
|
" , ".join(format_dict.keys()))
|
|
subserie = XML.SubElement(topseries, format_dict.get(format_data))
|
|
XML.SubElement(subserie, 'file').text = serie.get('file')
|
|
if format_data == 'properties':
|
|
XML.SubElement(subserie, 'label').text = serie.get('label', '')
|
|
if format_data == 'csv':
|
|
inclusion_flag = serie.get('inclusion-flag', 'off')
|
|
if inclusion_flag not in inclusion_dict:
|
|
raise JenkinsJobsException("Inclusion flag result entered "
|
|
"is not valid, must be one of: "
|
|
"%s"
|
|
% ", ".join(inclusion_dict))
|
|
XML.SubElement(subserie, 'inclusionFlag').text = \
|
|
inclusion_dict.get(inclusion_flag)
|
|
XML.SubElement(subserie, 'exclusionValues').text = \
|
|
serie.get('exclude', '')
|
|
XML.SubElement(subserie, 'url').text = serie.get('url', '')
|
|
XML.SubElement(subserie, 'displayTableFlag').text = \
|
|
str(plot.get('display-table', False)).lower()
|
|
if format_data == 'xml':
|
|
XML.SubElement(subserie, 'url').text = serie.get('url', '')
|
|
XML.SubElement(subserie, 'xpathString').text = \
|
|
serie.get('xpath')
|
|
xpathtype = serie.get('xpath-type', 'node')
|
|
if xpathtype not in xpath_dict:
|
|
raise JenkinsJobsException("XPath result entered is not "
|
|
"valid, must be one of: %s" %
|
|
", ".join(xpath_dict))
|
|
XML.SubElement(subserie, 'nodeTypeString').text = \
|
|
xpath_dict.get(xpathtype)
|
|
XML.SubElement(subserie, 'fileType').text = serie.get('format')
|
|
XML.SubElement(plugin, 'group').text = plot['group']
|
|
XML.SubElement(plugin, 'useDescr').text = \
|
|
str(plot.get('use-description', False)).lower()
|
|
XML.SubElement(plugin, 'numBuilds').text = plot.get('num-builds', '')
|
|
style_list = ['area', 'bar', 'bar3d', 'line', 'line3d', 'stackedArea',
|
|
'stackedbar', 'stackedbar3d', 'waterfall']
|
|
style = plot.get('style', 'line')
|
|
if style not in style_list:
|
|
raise JenkinsJobsException("style entered is not valid, must be "
|
|
"one of: %s" % ", ".join(style_list))
|
|
XML.SubElement(plugin, 'style').text = style
|
|
|
|
|
|
def git(parser, xml_parent, data):
|
|
"""yaml: git
|
|
This plugin will configure the Jenkins Git plugin to
|
|
push merge results, tags, and/or branches to
|
|
remote repositories after the job completes.
|
|
|
|
Requires the Jenkins `Git Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin>`_
|
|
|
|
:arg bool push-merge: push merges back to the origin specified in the
|
|
pre-build merge options (Default: False)
|
|
:arg bool push-only-if-success: Only push to remotes if the build succeeds
|
|
- otherwise, nothing will be pushed.
|
|
(Default: True)
|
|
:arg list tags: tags to push at the completion of the build
|
|
|
|
:tag: * **remote** (`str`) remote repo name to push to
|
|
(Default: 'origin')
|
|
* **name** (`str`) name of tag to push
|
|
* **message** (`str`) message content of the tag
|
|
* **create-tag** (`bool`) whether or not to create the tag
|
|
after the build, if this is False then the tag needs to
|
|
exist locally (Default: False)
|
|
* **update-tag** (`bool`) whether to overwrite a remote tag
|
|
or not (Default: False)
|
|
|
|
:arg list branches: branches to push at the completion of the build
|
|
|
|
:branch: * **remote** (`str`) remote repo name to push to
|
|
(Default: 'origin')
|
|
* **name** (`str`) name of remote branch to push to
|
|
|
|
:arg list notes: notes to push at the completion of the build
|
|
|
|
:note: * **remote** (`str`) remote repo name to push to
|
|
(Default: 'origin')
|
|
* **message** (`str`) content of the note
|
|
* **namespace** (`str`) namespace of the note
|
|
(Default: master)
|
|
* **replace-note** (`bool`) whether to overwrite a note or not
|
|
(Default: False)
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- git:
|
|
push-merge: true
|
|
push-only-if-success: false
|
|
tags:
|
|
- tag:
|
|
remote: tagremotename
|
|
name: tagname
|
|
message: "some tag message"
|
|
create-tag: true
|
|
update-tag: true
|
|
branches:
|
|
- branch:
|
|
remote: branchremotename
|
|
name: "some/branch"
|
|
notes:
|
|
- note:
|
|
remote: remotename
|
|
message: "some note to push"
|
|
namespace: commits
|
|
replace-note: true
|
|
|
|
"""
|
|
mappings = [('push-merge', 'pushMerge', False),
|
|
('push-only-if-success', 'pushOnlyIfSuccess', True)]
|
|
|
|
tag_mappings = [('remote', 'targetRepoName', 'origin'),
|
|
('name', 'tagName', None),
|
|
('message', 'tagMessage', ''),
|
|
('create-tag', 'createTag', False),
|
|
('update-tag', 'updateTag', False)]
|
|
|
|
branch_mappings = [('remote', 'targetRepoName', 'origin'),
|
|
('name', 'branchName', None)]
|
|
|
|
note_mappings = [('remote', 'targetRepoName', 'origin'),
|
|
('message', 'noteMsg', None),
|
|
('namespace', 'noteNamespace', 'master'),
|
|
('replace-note', 'noteReplace', False)]
|
|
|
|
def handle_entity_children(entity, entity_xml, child_mapping):
|
|
for prop in child_mapping:
|
|
opt, xmlopt, default_val = prop[:3]
|
|
val = entity.get(opt, default_val)
|
|
if val is None:
|
|
raise JenkinsJobsException('Required option missing: %s' % opt)
|
|
if type(val) == bool:
|
|
val = str(val).lower()
|
|
XML.SubElement(entity_xml, xmlopt).text = val
|
|
|
|
top = XML.SubElement(xml_parent, 'hudson.plugins.git.GitPublisher')
|
|
XML.SubElement(top, 'configVersion').text = '2'
|
|
handle_entity_children(data, top, mappings)
|
|
|
|
tags = data.get('tags', [])
|
|
if tags:
|
|
xml_tags = XML.SubElement(top, 'tagsToPush')
|
|
for tag in tags:
|
|
xml_tag = XML.SubElement(
|
|
xml_tags,
|
|
'hudson.plugins.git.GitPublisher_-TagToPush')
|
|
handle_entity_children(tag['tag'], xml_tag, tag_mappings)
|
|
|
|
branches = data.get('branches', [])
|
|
if branches:
|
|
xml_branches = XML.SubElement(top, 'branchesToPush')
|
|
for branch in branches:
|
|
xml_branch = XML.SubElement(
|
|
xml_branches,
|
|
'hudson.plugins.git.GitPublisher_-BranchToPush')
|
|
handle_entity_children(branch['branch'], xml_branch,
|
|
branch_mappings)
|
|
|
|
notes = data.get('notes', [])
|
|
if notes:
|
|
xml_notes = XML.SubElement(top, 'notesToPush')
|
|
for note in notes:
|
|
xml_note = XML.SubElement(
|
|
xml_notes,
|
|
'hudson.plugins.git.GitPublisher_-NoteToPush')
|
|
handle_entity_children(note['note'], xml_note, note_mappings)
|
|
|
|
|
|
def github_notifier(parser, xml_parent, data):
|
|
"""yaml: github-notifier
|
|
Set build status on Github commit.
|
|
Requires the Jenkins `Github Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/GitHub+Plugin>`_
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/github-notifier.yaml
|
|
"""
|
|
XML.SubElement(xml_parent,
|
|
'com.cloudbees.jenkins.GitHubCommitNotifier')
|
|
|
|
|
|
def build_publisher(parser, xml_parent, data):
|
|
"""yaml: build-publisher
|
|
This plugin allows records from one Jenkins to be published
|
|
on another Jenkins.
|
|
|
|
Requires the Jenkins `Build Publisher Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Build+Publisher+Plugin>`_
|
|
|
|
:arg str servers: Specify the servers where to publish
|
|
|
|
|
|
Example::
|
|
|
|
publishers:
|
|
- build-publisher:
|
|
name: servername
|
|
publish-unstable-builds: true
|
|
publish-failed-builds: true
|
|
days-to-keep: -1
|
|
num-to-keep: -1
|
|
artifact-days-to-keep: -1
|
|
artifact-num-to-keep: -1
|
|
|
|
"""
|
|
|
|
reporter = XML.SubElement(
|
|
xml_parent,
|
|
'hudson.plugins.build__publisher.BuildPublisher')
|
|
|
|
XML.SubElement(reporter, 'serverName').text = data['name']
|
|
XML.SubElement(reporter, 'publishUnstableBuilds').text = \
|
|
str(data.get('publish-unstable-builds', True)).lower()
|
|
XML.SubElement(reporter, 'publishFailedBuilds').text = \
|
|
str(data.get('publish-failed-builds', True)).lower()
|
|
|
|
logrotator = XML.SubElement(reporter, 'logRotator')
|
|
XML.SubElement(logrotator, 'daysToKeep').text = \
|
|
str(data.get('days-to-keep', -1))
|
|
XML.SubElement(logrotator, 'numToKeep').text = \
|
|
str(data.get('num-to-keep', -1))
|
|
XML.SubElement(logrotator, 'artifactDaysToKeep').text = \
|
|
str(data.get('artifact-days-to-keep', -1))
|
|
XML.SubElement(logrotator, 'artifactNumToKeep').text = \
|
|
str(data.get('artifact-num-to-keep', -1))
|
|
|
|
|
|
def stash(parser, xml_parent, data):
|
|
"""yaml: stash
|
|
This plugin will configure the Jenkins Stash Notifier plugin to
|
|
notify Atlassian Stash after job completes.
|
|
|
|
Requires the Jenkins `StashNotifier Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/StashNotifier+Plugin>`_
|
|
|
|
:arg string url: Base url of Stash Server (Default: "")
|
|
:arg string username: Username of Stash Server (Default: "")
|
|
:arg string password: Password of Stash Server (Default: "")
|
|
:arg bool ignore-ssl: Ignore unverified SSL certificate (Default: False)
|
|
:arg string commit-sha1: Commit SHA1 to notify (Default: "")
|
|
:arg bool include-build-number: Include build number in key
|
|
(Default: False)
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/stash001.yaml
|
|
"""
|
|
|
|
top = XML.SubElement(xml_parent,
|
|
'org.jenkinsci.plugins.stashNotifier.StashNotifier')
|
|
|
|
XML.SubElement(top, 'stashServerBaseUrl').text = data.get('url', '')
|
|
XML.SubElement(top, 'stashUserName').text = data.get('username', '')
|
|
XML.SubElement(top, 'stashUserPassword').text = data.get('password', '')
|
|
XML.SubElement(top, 'ignoreUnverifiedSSLPeer').text = str(
|
|
data.get('ignore-ssl', False)).lower()
|
|
XML.SubElement(top, 'commitSha1').text = data.get('commit-sha1', '')
|
|
XML.SubElement(top, 'includeBuildNumberInKey').text = str(
|
|
data.get('include-build-number', False)).lower()
|
|
|
|
|
|
def description_setter(parser, xml_parent, data):
|
|
"""yaml: description-setter
|
|
This plugin sets the description for each build,
|
|
based upon a RegEx test of the build log file.
|
|
|
|
Requires the Jenkins `Description Setter Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Description+Setter+Plugin>`_
|
|
|
|
:arg str regexp: A RegEx which is used to scan the build log file
|
|
:arg str regexp-for-failed: A RegEx which is used for failed builds
|
|
(optional)
|
|
:arg str description: The description to set on the build (optional)
|
|
:arg str description-for-failed: The description to set on
|
|
the failed builds (optional)
|
|
:arg bool set-for-matrix: Also set the description on
|
|
a multi-configuration build (Default False)
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/publishers/fixtures/description-setter.yaml
|
|
|
|
"""
|
|
|
|
descriptionsetter = XML.SubElement(
|
|
xml_parent,
|
|
'hudson.plugins.descriptionsetter.DescriptionSetterPublisher')
|
|
XML.SubElement(descriptionsetter, 'regexp').text = data.get('regexp', '')
|
|
XML.SubElement(descriptionsetter, 'regexpForFailed').text = \
|
|
data.get('regexp-for-failed', '')
|
|
if 'description' in data:
|
|
XML.SubElement(descriptionsetter, 'description').text = \
|
|
data['description']
|
|
if 'description-for-failed' in data:
|
|
XML.SubElement(descriptionsetter, 'descriptionForFailed').text = \
|
|
data['description-for-failed']
|
|
for_matrix = str(data.get('set-for-matrix', False)).lower()
|
|
XML.SubElement(descriptionsetter, 'setForMatrix').text = for_matrix
|
|
|
|
|
|
class Publishers(jenkins_jobs.modules.base.Base):
|
|
sequence = 70
|
|
|
|
component_type = 'publisher'
|
|
component_list_type = 'publishers'
|
|
|
|
def gen_xml(self, parser, xml_parent, data):
|
|
publishers = XML.SubElement(xml_parent, 'publishers')
|
|
|
|
for action in data.get('publishers', []):
|
|
self.registry.dispatch('publisher', parser, publishers, action)
|