054b57145f
Done to enable private repository for jobs making it more safe to run concurrent maven builds and for allowing to control javavm and other maven settings for maven build. Includes moving doc example for maven-target as a test fixture. Change-Id: Ic34958e9bf1008fbc71c45da85208ac1fda7aeb4
1035 lines
42 KiB
Python
1035 lines
42 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.
|
|
|
|
|
|
"""
|
|
Builders define actions that the Jenkins job should execute. Examples
|
|
include shell scripts or maven targets. The ``builders`` attribute in
|
|
the :ref:`Job` definition accepts a list of builders to invoke. They
|
|
may be components defined below, locally defined macros (using the top
|
|
level definition of ``builder:``, or locally defined components found
|
|
via the ``jenkins_jobs.builders`` entry point.
|
|
|
|
**Component**: builders
|
|
:Macro: builder
|
|
:Entry Point: jenkins_jobs.builders
|
|
|
|
Example::
|
|
|
|
job:
|
|
name: test_job
|
|
|
|
builders:
|
|
- shell: "make test"
|
|
|
|
"""
|
|
|
|
|
|
import xml.etree.ElementTree as XML
|
|
import jenkins_jobs.modules.base
|
|
from jenkins_jobs.errors import JenkinsJobsException
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def shell(parser, xml_parent, data):
|
|
"""yaml: shell
|
|
Execute a shell command.
|
|
|
|
:Parameter: the shell command to execute
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- shell: "make test"
|
|
|
|
"""
|
|
shell = XML.SubElement(xml_parent, 'hudson.tasks.Shell')
|
|
XML.SubElement(shell, 'command').text = data
|
|
|
|
|
|
def copyartifact(parser, xml_parent, data):
|
|
"""yaml: copyartifact
|
|
|
|
Copy artifact from another project. Requires the Jenkins `Copy Artifact
|
|
plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Copy+Artifact+Plugin>`_
|
|
|
|
:arg str project: Project to copy from
|
|
:arg str filter: what files to copy
|
|
:arg str target: Target base directory for copy, blank means use workspace
|
|
:arg bool flatten: Flatten directories (default: false)
|
|
:arg bool optional: If the artifact is missing (for any reason) and
|
|
optional is true, the build won't fail because of this builder
|
|
(default: false)
|
|
:arg str which-build: which build to get artifacts from
|
|
(optional, default last-successful)
|
|
:arg str build-number: specifies the build number to get when
|
|
when specific-build is specified as which-build
|
|
:arg str permalink: specifies the permalink to get when
|
|
permalink is specified as which-build
|
|
:arg bool stable: specifies to get only last stable build when
|
|
last-successful is specified as which-build
|
|
:arg bool fallback-to-last-successful: specifies to fallback to
|
|
last successful build when upstream-build is specified as which-build
|
|
:arg string param: specifies to use a build parameter to get the build when
|
|
build-param is specified as which-build
|
|
:arg string parameter-filters: Filter matching jobs based on these
|
|
parameters (optional)
|
|
:which-build values:
|
|
* **last-successful**
|
|
* **specific-build**
|
|
* **last-saved**
|
|
* **upstream-build**
|
|
* **permalink**
|
|
* **workspace-latest**
|
|
* **build-param**
|
|
:permalink values:
|
|
* **last**
|
|
* **last-stable**
|
|
* **last-successful**
|
|
* **last-failed**
|
|
* **last-unstable**
|
|
* **last-unsuccessful**
|
|
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- copyartifact:
|
|
project: foo
|
|
filter: *.tar.gz
|
|
target: /home/foo
|
|
which-build: specific-build
|
|
build-number: 123
|
|
optional: true
|
|
flatten: true
|
|
parameter-filters: PUBLISH=true
|
|
"""
|
|
t = XML.SubElement(xml_parent, 'hudson.plugins.copyartifact.CopyArtifact')
|
|
# Warning: this only works with copy artifact version 1.26+,
|
|
# for copy artifact version 1.25- the 'projectName' element needs
|
|
# to be used instead of 'project'
|
|
XML.SubElement(t, 'project').text = data["project"]
|
|
XML.SubElement(t, 'filter').text = data.get("filter", "")
|
|
XML.SubElement(t, 'target').text = data.get("target", "")
|
|
flatten = data.get("flatten", False)
|
|
XML.SubElement(t, 'flatten').text = str(flatten).lower()
|
|
optional = data.get('optional', False)
|
|
XML.SubElement(t, 'optional').text = str(optional).lower()
|
|
XML.SubElement(t, 'parameters').text = data.get("parameter-filters", "")
|
|
select = data.get('which-build', 'last-successful')
|
|
selectdict = {'last-successful': 'StatusBuildSelector',
|
|
'specific-build': 'SpecificBuildSelector',
|
|
'last-saved': 'SavedBuildSelector',
|
|
'upstream-build': 'TriggeredBuildSelector',
|
|
'permalink': 'PermalinkBuildSelector',
|
|
'workspace-latest': 'WorkspaceSelector',
|
|
'build-param': 'ParameterizedBuildSelector'}
|
|
if select not in selectdict:
|
|
raise JenkinsJobsException("which-build entered is not valid must be "
|
|
"one of: last-successful, specific-build, "
|
|
"last-saved, upstream-build, permalink, "
|
|
"workspace-latest, or build-param")
|
|
permalink = data.get('permalink', 'last')
|
|
permalinkdict = {'last': 'lastBuild',
|
|
'last-stable': 'lastStableBuild',
|
|
'last-successful': 'lastSuccessfulBuild',
|
|
'last-failed': 'lastFailedBuild',
|
|
'last-unstable': 'lastUnstableBuild',
|
|
'last-unsuccessful': 'lastUnsuccessfulBuild'}
|
|
if permalink not in permalinkdict:
|
|
raise JenkinsJobsException("permalink entered is not valid must be "
|
|
"one of: last, last-stable, "
|
|
"last-successful, last-failed, "
|
|
"last-unstable, or last-unsuccessful")
|
|
selector = XML.SubElement(t, 'selector',
|
|
{'class': 'hudson.plugins.copyartifact.' +
|
|
selectdict[select]})
|
|
if select == 'specific-build':
|
|
XML.SubElement(selector, 'buildNumber').text = data['build-number']
|
|
if select == 'last-successful':
|
|
XML.SubElement(selector, 'stable').text = str(
|
|
data.get('stable', False)).lower()
|
|
if select == 'upstream-build':
|
|
XML.SubElement(selector, 'fallbackToLastSuccessful').text = str(
|
|
data.get('fallback-to-last-successful', False)).lower()
|
|
if select == 'permalink':
|
|
XML.SubElement(selector, 'id').text = permalinkdict[permalink]
|
|
if select == 'build-param':
|
|
XML.SubElement(selector, 'parameterName').text = data['param']
|
|
|
|
|
|
def ant(parser, xml_parent, data):
|
|
"""yaml: ant
|
|
Execute an ant target. Requires the Jenkins `Ant Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Ant+Plugin>`_
|
|
|
|
To setup this builder you can either reference the list of targets
|
|
or use named parameters. Below is a description of both forms:
|
|
|
|
*1) Listing targets:*
|
|
|
|
After the ant directive, simply pass as argument a space separated list
|
|
of targets to build.
|
|
|
|
:Parameter: space separated list of Ant targets
|
|
:arg str ant-name: the name of the ant installation,
|
|
defaults to 'default' (optional)
|
|
|
|
Example to call two Ant targets::
|
|
|
|
builders:
|
|
- ant: "target1 target2"
|
|
ant-name: "Standard Ant"
|
|
|
|
The build file would be whatever the Jenkins Ant Plugin is set to use
|
|
per default (i.e build.xml in the workspace root).
|
|
|
|
*2) Using named parameters:*
|
|
|
|
:arg str targets: the space separated list of ANT targets.
|
|
:arg str buildfile: the path to the ANT build file.
|
|
:arg list properties: Passed to ant script using -Dkey=value (optional)
|
|
:arg str ant-name: the name of the ant installation,
|
|
defaults to 'default' (optional)
|
|
:arg str java-opts: java options for ant, can have multiples,
|
|
must be in quotes (optional)
|
|
|
|
|
|
Example specifying the build file too and several targets::
|
|
|
|
builders:
|
|
- ant:
|
|
targets: "debug test install"
|
|
buildfile: "build.xml"
|
|
properties:
|
|
builddir: "/tmp/"
|
|
failonerror: true
|
|
java-opts:
|
|
- "-ea"
|
|
- "-Xmx512m"
|
|
ant-name: "Standard Ant"
|
|
|
|
"""
|
|
ant = XML.SubElement(xml_parent, 'hudson.tasks.Ant')
|
|
|
|
if type(data) is str:
|
|
# Support for short form: -ant: "target"
|
|
data = {'targets': data}
|
|
for setting, value in data.iteritems():
|
|
if setting == 'targets':
|
|
targets = XML.SubElement(ant, 'targets')
|
|
targets.text = value
|
|
if setting == 'buildfile':
|
|
buildfile = XML.SubElement(ant, 'buildFile')
|
|
buildfile.text = value
|
|
if setting == 'properties':
|
|
properties = data['properties']
|
|
prop_string = ''
|
|
for prop, val in properties.items():
|
|
prop_string += "%s=%s\n" % (prop, val)
|
|
prop_element = XML.SubElement(ant, 'properties')
|
|
prop_element.text = prop_string
|
|
if setting == 'java-opts':
|
|
javaopts = data['java-opts']
|
|
jopt_string = ' '.join(javaopts)
|
|
jopt_element = XML.SubElement(ant, 'antOpts')
|
|
jopt_element.text = jopt_string
|
|
|
|
XML.SubElement(ant, 'antName').text = data.get('ant-name', 'default')
|
|
|
|
|
|
def trigger_builds(parser, xml_parent, data):
|
|
"""yaml: trigger-builds
|
|
Trigger builds of other jobs.
|
|
Requires the Jenkins `Parameterized Trigger Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/
|
|
Parameterized+Trigger+Plugin>`_
|
|
|
|
:arg str project: the Jenkins project to trigger
|
|
:arg str predefined-parameters:
|
|
key/value pairs to be passed to the job (optional)
|
|
:arg bool current-parameters: Whether to include the
|
|
parameters passed to the current build to the
|
|
triggered job.
|
|
:arg bool svn-revision: Whether to pass the svn revision
|
|
to the triggered job
|
|
:arg bool block: whether to wait for the triggered jobs
|
|
to finish or not (default false)
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- trigger-builds:
|
|
- project: "build_started"
|
|
predefined-parameters:
|
|
FOO="bar"
|
|
block: true
|
|
|
|
"""
|
|
tbuilder = XML.SubElement(xml_parent,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'TriggerBuilder')
|
|
configs = XML.SubElement(tbuilder, 'configs')
|
|
for project_def in data:
|
|
if 'project' not in project_def or project_def['project'] == '':
|
|
logger.debug("No project specified - skipping trigger-build")
|
|
continue
|
|
tconfig = XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'BlockableBuildTriggerConfig')
|
|
tconfigs = XML.SubElement(tconfig, 'configs')
|
|
if(project_def.get('current-parameters')):
|
|
XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'CurrentBuildParameters')
|
|
if(project_def.get('svn-revision')):
|
|
XML.SubElement(tconfigs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'SubversionRevisionBuildParameters')
|
|
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(len(list(tconfigs)) == 0):
|
|
tconfigs.set('class', 'java.util.Collections$EmptyList')
|
|
projects = XML.SubElement(tconfig, 'projects')
|
|
projects.text = project_def['project']
|
|
condition = XML.SubElement(tconfig, 'condition')
|
|
condition.text = 'ALWAYS'
|
|
trigger_with_no_params = XML.SubElement(tconfig,
|
|
'triggerWithNoParameters')
|
|
trigger_with_no_params.text = 'false'
|
|
build_all_nodes_with_label = XML.SubElement(tconfig,
|
|
'buildAllNodesWithLabel')
|
|
build_all_nodes_with_label.text = 'false'
|
|
block = project_def.get('block', False)
|
|
if(block):
|
|
block = XML.SubElement(tconfig, 'block')
|
|
bsft = XML.SubElement(block, 'buildStepFailureThreshold')
|
|
XML.SubElement(bsft, 'name').text = 'FAILURE'
|
|
XML.SubElement(bsft, 'ordinal').text = '2'
|
|
XML.SubElement(bsft, 'color').text = 'RED'
|
|
ut = XML.SubElement(block, 'unstableThreshold')
|
|
XML.SubElement(ut, 'name').text = 'UNSTABLE'
|
|
XML.SubElement(ut, 'ordinal').text = '1'
|
|
XML.SubElement(ut, 'color').text = 'Yellow'
|
|
ft = XML.SubElement(block, 'failureThreshold')
|
|
XML.SubElement(ft, 'name').text = 'FAILURE'
|
|
XML.SubElement(ft, 'ordinal').text = '2'
|
|
XML.SubElement(ft, 'color').text = 'RED'
|
|
# If configs is empty, remove the entire tbuilder tree.
|
|
if(len(configs) == 0):
|
|
logger.debug("Pruning empty TriggerBuilder tree.")
|
|
xml_parent.remove(tbuilder)
|
|
|
|
|
|
def builders_from(parser, xml_parent, data):
|
|
"""yaml: builders-from
|
|
Use builders from another project.
|
|
Requires the Jenkins `Template Project Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Template+Project+Plugin>`_
|
|
|
|
:arg str projectName: the name of the other project
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- builders-from:
|
|
- project: "base-build"
|
|
"""
|
|
pbs = XML.SubElement(xml_parent,
|
|
'hudson.plugins.templateproject.ProxyBuilder')
|
|
XML.SubElement(pbs, 'projectName').text = data
|
|
|
|
|
|
def inject(parser, xml_parent, data):
|
|
"""yaml: inject
|
|
Inject an environment for the job.
|
|
Requires the Jenkins `EnvInject Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin>`_
|
|
|
|
:arg str properties-file: the name of the property file (optional)
|
|
:arg str properties-content: the properties content (optional)
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- inject:
|
|
properties-file: example.prop
|
|
properties-content: EXAMPLE=foo-bar
|
|
"""
|
|
eib = XML.SubElement(xml_parent, 'EnvInjectBuilder')
|
|
info = XML.SubElement(eib, 'info')
|
|
jenkins_jobs.modules.base.add_nonblank_xml_subelement(
|
|
info, 'propertiesFilePath', data.get('properties-file'))
|
|
jenkins_jobs.modules.base.add_nonblank_xml_subelement(
|
|
info, 'propertiesContent', data.get('properties-content'))
|
|
|
|
|
|
def artifact_resolver(parser, xml_parent, data):
|
|
"""yaml: artifact-resolver
|
|
Allows one to resolve artifacts from a maven repository like nexus
|
|
(without having maven installed)
|
|
Requires the Jenkins `Repository Connector Plugin
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Repository+Connector+Plugin>`_
|
|
|
|
:arg bool fail-on-error: Whether to fail the build on error (default false)
|
|
:arg bool repository-logging: Enable repository logging (default false)
|
|
:arg str target-directory: Where to resolve artifacts to
|
|
:arg list artifacts: list of artifacts to resolve
|
|
|
|
:Artifact: * **group-id** (`str`) -- Group ID of the artifact
|
|
* **artifact-id** (`str`) -- Artifact ID of the artifact
|
|
* **version** (`str`) -- Version of the artifact
|
|
* **classifier** (`str`) -- Classifier of the artifact
|
|
(default '')
|
|
* **extension** (`str`) -- Extension of the artifact
|
|
(default 'jar')
|
|
* **target-file-name** (`str`) -- What to name the artifact
|
|
(default '')
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- artifact-resolver:
|
|
fail-on-error: true
|
|
repository-logging: true
|
|
target-directory: foo
|
|
artifacts:
|
|
- group-id: commons-logging
|
|
artifact-id: commons-logging
|
|
version: 1.1
|
|
classifier: src
|
|
extension: jar
|
|
target-file-name: comm-log.jar
|
|
- group-id: commons-lang
|
|
artifact-id: commons-lang
|
|
version: 1.2
|
|
"""
|
|
ar = XML.SubElement(xml_parent,
|
|
'org.jvnet.hudson.plugins.repositoryconnector.'
|
|
'ArtifactResolver')
|
|
XML.SubElement(ar, 'targetDirectory').text = data['target-directory']
|
|
artifacttop = XML.SubElement(ar, 'artifacts')
|
|
artifacts = data['artifacts']
|
|
for artifact in artifacts:
|
|
rcartifact = XML.SubElement(artifacttop,
|
|
'org.jvnet.hudson.plugins.'
|
|
'repositoryconnector.Artifact')
|
|
XML.SubElement(rcartifact, 'groupId').text = artifact['group-id']
|
|
XML.SubElement(rcartifact, 'artifactId').text = artifact['artifact-id']
|
|
XML.SubElement(rcartifact, 'classifier').text = artifact.get(
|
|
'classifier', '')
|
|
XML.SubElement(rcartifact, 'version').text = artifact['version']
|
|
XML.SubElement(rcartifact, 'extension').text = artifact.get(
|
|
'extension', 'jar')
|
|
XML.SubElement(rcartifact, 'targetFileName').text = artifact.get(
|
|
'target-file-name', '')
|
|
XML.SubElement(ar, 'failOnError').text = str(data.get(
|
|
'fail-on-error', False)).lower()
|
|
XML.SubElement(ar, 'enableRepoLogging').text = str(data.get(
|
|
'repository-logging', False)).lower()
|
|
XML.SubElement(ar, 'snapshotUpdatePolicy').text = 'never'
|
|
XML.SubElement(ar, 'releaseUpdatePolicy').text = 'never'
|
|
XML.SubElement(ar, 'snapshotChecksumPolicy').text = 'warn'
|
|
XML.SubElement(ar, 'releaseChecksumPolicy').text = 'warn'
|
|
|
|
|
|
def gradle(parser, xml_parent, data):
|
|
"""yaml: gradle
|
|
Execute gradle tasks. Requires the Jenkins `Gradle Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Gradle+Plugin>`_
|
|
|
|
:arg str tasks: List of tasks to execute
|
|
:arg str gradle-name: Use a custom gradle name (optional)
|
|
:arg bool wrapper: use gradle wrapper (default false)
|
|
:arg bool executable: make gradlew executable (default false)
|
|
:arg list switches: Switches for gradle, can have multiples
|
|
:arg bool use-root-dir: Whether to run the gradle script from the
|
|
top level directory or from a different location (default false)
|
|
:arg str root-build-script-dir: If your workspace has the
|
|
top-level build.gradle in somewhere other than the module
|
|
root directory, specify the path (relative to the module
|
|
root) here, such as ${workspace}/parent/ instead of just
|
|
${workspace}.
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- gradle:
|
|
gradle-name: "gradle-1.2"
|
|
wrapper: true
|
|
executable: true
|
|
use-root-dir: true
|
|
root-build-script-dir: ${workspace}/tests
|
|
switches:
|
|
- "-g /foo/bar/.gradle"
|
|
- "-PmavenUserName=foobar"
|
|
tasks: |
|
|
init
|
|
build
|
|
tests
|
|
"""
|
|
gradle = XML.SubElement(xml_parent, 'hudson.plugins.gradle.Gradle')
|
|
XML.SubElement(gradle, 'description').text = ''
|
|
XML.SubElement(gradle, 'tasks').text = data['tasks']
|
|
XML.SubElement(gradle, 'buildFile').text = ''
|
|
XML.SubElement(gradle, 'rootBuildScriptDir').text = data.get(
|
|
'root-build-script-dir', '')
|
|
XML.SubElement(gradle, 'gradleName').text = data.get(
|
|
'gradle-name', '')
|
|
XML.SubElement(gradle, 'useWrapper').text = str(data.get(
|
|
'wrapper', False)).lower()
|
|
XML.SubElement(gradle, 'makeExecutable').text = str(data.get(
|
|
'executable', False)).lower()
|
|
switch_string = '\n'.join(data.get('switches', []))
|
|
XML.SubElement(gradle, 'switches').text = switch_string
|
|
XML.SubElement(gradle, 'fromRootBuildScriptDir').text = str(data.get(
|
|
'use-root-dir', False)).lower()
|
|
|
|
|
|
def batch(parser, xml_parent, data):
|
|
"""yaml: batch
|
|
Execute a batch command.
|
|
|
|
:Parameter: the batch command to execute
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- batch: "foo/foo.bat"
|
|
|
|
"""
|
|
batch = XML.SubElement(xml_parent, 'hudson.tasks.BatchFile')
|
|
XML.SubElement(batch, 'command').text = data
|
|
|
|
|
|
def msbuild(parser, xml_parent, data):
|
|
"""yaml: msbuild
|
|
Build .NET project using msbuild. Requires the `Jenkins MSBuild Plugin
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/MSBuild+Plugin>`_.
|
|
|
|
:arg str msbuild-version: which msbuild configured in Jenkins to use
|
|
(optional)
|
|
:arg str solution-file: location of the solution file to build
|
|
:arg str extra-parameters: extra parameters to pass to msbuild (optional)
|
|
:arg bool pass-build-variables: should build variables be passed
|
|
to msbuild (defaults to true)
|
|
:arg bool continue-on-build-failure: should the build continue if
|
|
msbuild returns an error (defaults to false)
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- msbuild:
|
|
solution-file: "MySolution.sln"
|
|
msbuild-version: "msbuild-4.0"
|
|
extra-parameters: "/maxcpucount:4"
|
|
pass-build-variables: False
|
|
continue-on-build-failure: True
|
|
|
|
"""
|
|
msbuilder = XML.SubElement(xml_parent,
|
|
'hudson.plugins.msbuild.MsBuildBuilder')
|
|
XML.SubElement(msbuilder, 'msBuildName').text = data.get('msbuild-version',
|
|
'(Default)')
|
|
XML.SubElement(msbuilder, 'msBuildFile').text = data['solution-file']
|
|
XML.SubElement(msbuilder, 'cmdLineArgs').text = \
|
|
data.get('extra-parameters', '')
|
|
XML.SubElement(msbuilder, 'buildVariablesAsProperties').text = \
|
|
str(data.get('pass-build-variables', True)).lower()
|
|
XML.SubElement(msbuilder, 'continueOnBuildFailure').text = \
|
|
str(data.get('continue-on-build-failure', False)).lower()
|
|
|
|
|
|
def create_builders(parser, step):
|
|
dummy_parent = XML.Element("dummy")
|
|
parser.registry.dispatch('builder', parser, dummy_parent, step)
|
|
return list(dummy_parent)
|
|
|
|
|
|
def conditional_step(parser, xml_parent, data):
|
|
"""yaml: conditional-step
|
|
Conditionaly execute some build steps. Requires the Jenkins `Conditional
|
|
BuildStep Plugin`_.
|
|
|
|
Depending on the number of declared steps, a `Conditional step (single)`
|
|
or a `Conditional steps (multiple)` is created in Jenkins.
|
|
|
|
:arg str condition-kind: Condition kind that must be verified before the
|
|
steps are executed. Valid values and their additional attributes are
|
|
described in the conditions_ table.
|
|
:arg str on-evaluation-failure: What should be the outcome of the build
|
|
if the evaluation of the condition fails. Possible values are `fail`,
|
|
`mark-unstable`, `run-and-mark-unstable`, `run` and `dont-run`.
|
|
Default is `fail`.
|
|
:arg list steps: List of steps to run if the condition is verified. Items
|
|
in the list can be any builder known by Jenkins Job Builder.
|
|
|
|
.. _conditions:
|
|
|
|
================== ====================================================
|
|
Condition kind Description
|
|
================== ====================================================
|
|
always Condition is always verified
|
|
never Condition is never verified
|
|
boolean-expression Run the step if the expression expends to a
|
|
representation of true
|
|
|
|
:condition-expression: Expression to expand
|
|
current-status Run the build step if the current build status is
|
|
within the configured range
|
|
|
|
:condition-worst: Worst status
|
|
:condition-best: Best status
|
|
shell Run the step if the shell command succeed
|
|
|
|
:condition-command: Shell command to execute
|
|
windows-shell Similar to shell, except that commands will be
|
|
executed by cmd, under Windows
|
|
|
|
:condition-command: Command to execute
|
|
file-exists Run the step if a file exists
|
|
|
|
:condition-filename: Check existence of this file
|
|
:condition-basedir: If condition-filename is
|
|
relative, it will be considered relative to
|
|
either `workspace`, `artifact-directory`,
|
|
or `jenkins-home`. Default is `workspace`.
|
|
================== ====================================================
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- conditional-step:
|
|
condition-kind: boolean-expression
|
|
condition-expression: "${ENV,var=IS_STABLE_BRANCH}"
|
|
on-evaluation-failure: mark-unstable
|
|
steps:
|
|
- shell: "echo Making extra checks"
|
|
|
|
.. _Conditional BuildStep Plugin: https://wiki.jenkins-ci.org/display/
|
|
JENKINS/Conditional+BuildStep+Plugin
|
|
"""
|
|
|
|
def build_condition(cdata):
|
|
kind = cdata['condition-kind']
|
|
ctag = XML.SubElement(root_tag, condition_tag)
|
|
if kind == "always":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.core.AlwaysRun')
|
|
elif kind == "never":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.core.NeverRun')
|
|
elif kind == "boolean-expression":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.core.'
|
|
'BooleanCondition')
|
|
XML.SubElement(ctag, "token").text = cdata['condition-expression']
|
|
elif kind == "current-status":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.core.'
|
|
'StatusCondition')
|
|
wr = XML.SubElement(ctag, 'worstResult')
|
|
XML.SubElement(wr, "name").text = cdata['condition-worst']
|
|
br = XML.SubElement(ctag, 'bestResult')
|
|
XML.SubElement(br, "name").text = cdata['condition-best']
|
|
elif kind == "shell":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.contributed.'
|
|
'ShellCondition')
|
|
XML.SubElement(ctag, "command").text = cdata['condition-command']
|
|
elif kind == "windows-shell":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.contributed.'
|
|
'BatchFileCondition')
|
|
XML.SubElement(ctag, "command").text = cdata['condition-command']
|
|
elif kind == "file-exists":
|
|
ctag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.core.'
|
|
'FileExistsCondition')
|
|
XML.SubElement(ctag, "file").text = cdata['condition-filename']
|
|
basedir = cdata.get('condition-basedir', 'workspace')
|
|
basedir_tag = XML.SubElement(ctag, "baseDir")
|
|
if "workspace" == basedir:
|
|
basedir_tag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.common.'
|
|
'BaseDirectory$Workspace')
|
|
elif "artifact-directory" == basedir:
|
|
basedir_tag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.common.'
|
|
'BaseDirectory$ArtifactsDir')
|
|
elif "jenkins-home" == basedir:
|
|
basedir_tag.set('class',
|
|
'org.jenkins_ci.plugins.run_condition.common.'
|
|
'BaseDirectory$JenkinsHome')
|
|
|
|
def build_step(parent, step):
|
|
for edited_node in create_builders(parser, step):
|
|
if not has_multiple_steps:
|
|
edited_node.set('class', edited_node.tag)
|
|
edited_node.tag = 'buildStep'
|
|
parent.append(edited_node)
|
|
|
|
cond_builder_tag = 'org.jenkinsci.plugins.conditionalbuildstep.' \
|
|
'singlestep.SingleConditionalBuilder'
|
|
cond_builders_tag = 'org.jenkinsci.plugins.conditionalbuildstep.' \
|
|
'ConditionalBuilder'
|
|
steps = data['steps']
|
|
has_multiple_steps = len(steps) > 1
|
|
|
|
if has_multiple_steps:
|
|
root_tag = XML.SubElement(xml_parent, cond_builders_tag)
|
|
steps_parent = XML.SubElement(root_tag, "conditionalbuilders")
|
|
condition_tag = "runCondition"
|
|
else:
|
|
root_tag = XML.SubElement(xml_parent, cond_builder_tag)
|
|
steps_parent = root_tag
|
|
condition_tag = "condition"
|
|
|
|
build_condition(data)
|
|
evaluation_classes_pkg = 'org.jenkins_ci.plugins.run_condition'
|
|
evaluation_classes = {
|
|
'fail': evaluation_classes_pkg + '.BuildStepRunner$Fail',
|
|
'mark-unstable': evaluation_classes_pkg + '.BuildStepRunner$Unstable',
|
|
'run-and-mark-unstable': evaluation_classes_pkg +
|
|
'.BuildStepRunner$RunUnstable',
|
|
'run': evaluation_classes_pkg + '.BuildStepRunner$Run',
|
|
'dont-run': evaluation_classes_pkg + '.BuildStepRunner$DontRun',
|
|
}
|
|
evaluation_class = evaluation_classes[data.get('on-evaluation-failure',
|
|
'fail')]
|
|
XML.SubElement(root_tag, "runner").set('class',
|
|
evaluation_class)
|
|
for step in steps:
|
|
build_step(steps_parent, step)
|
|
|
|
|
|
def maven_target(parser, xml_parent, data):
|
|
"""yaml: maven-target
|
|
Execute top-level Maven targets
|
|
|
|
:arg str goals: Goals to execute
|
|
:arg str properties: Properties for maven, can have multiples
|
|
:arg str pom: Location of pom.xml (defaults to pom.xml)
|
|
:arg bool private-repository: Use private maven repository for this
|
|
job (defaults to false)
|
|
:arg str maven-version: Installation of maven which should be used
|
|
(optional)
|
|
:arg str java-opts: java options for maven, can have multiples,
|
|
must be in quotes (optional)
|
|
:arg str settings: Path to use as user settings.xml (optional)
|
|
:arg str global-settings: Path to use as global settings.xml (optional)
|
|
|
|
Example:
|
|
|
|
.. literalinclude:: ../../tests/builders/fixtures/maven-target-doc.yaml
|
|
"""
|
|
maven = XML.SubElement(xml_parent, 'hudson.tasks.Maven')
|
|
XML.SubElement(maven, 'targets').text = data['goals']
|
|
prop_string = '\n'.join(data.get('properties', []))
|
|
XML.SubElement(maven, 'properties').text = prop_string
|
|
if 'maven-version' in data:
|
|
XML.SubElement(maven, 'mavenName').text = str(data['maven-version'])
|
|
if 'pom' in data:
|
|
XML.SubElement(maven, 'pom').text = str(data['pom'])
|
|
use_private = str(data.get('private-repository', False)).lower()
|
|
XML.SubElement(maven, 'usePrivateRepository').text = use_private
|
|
if 'java-opts' in data:
|
|
javaoptions = ' '.join(data.get('java-opts', []))
|
|
XML.SubElement(maven, 'jvmOptions').text = javaoptions
|
|
if 'settings' in data:
|
|
settings = XML.SubElement(maven, 'settings',
|
|
{'class':
|
|
'jenkins.mvn.FilePathSettingsProvider'})
|
|
XML.SubElement(settings, 'path').text = data.get('settings')
|
|
else:
|
|
XML.SubElement(maven, 'settings',
|
|
{'class':
|
|
'jenkins.mvn.DefaultSettingsProvider'})
|
|
if 'global-settings' in data:
|
|
provider = 'jenkins.mvn.FilePathGlobalSettingsProvider'
|
|
global_settings = XML.SubElement(maven, 'globalSettings',
|
|
{'class': provider})
|
|
XML.SubElement(global_settings, 'path').text = data.get(
|
|
'global-settings')
|
|
else:
|
|
XML.SubElement(maven, 'globalSettings',
|
|
{'class':
|
|
'jenkins.mvn.DefaultGlobalSettingsProvider'})
|
|
|
|
|
|
def multijob(parser, xml_parent, data):
|
|
"""yaml: multijob
|
|
Define a multijob phase. Requires the Jenkins `Multijob Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Multijob+Plugin>`_
|
|
|
|
This builder may only be used in \
|
|
:py:class:`jenkins_jobs.modules.project_multijob.MultiJob` projects.
|
|
|
|
:arg str name: MultiJob phase name
|
|
:arg str condition: when to trigger the other job (default 'SUCCESSFUL')
|
|
:arg list projects: list of projects to include in the MultiJob phase
|
|
|
|
:Project: * **name** (`str`) -- Project name
|
|
* **current-parameters** (`bool`) -- Pass current build
|
|
parameters to the other job (default false)
|
|
* **node-label-name** (`str`) -- Define a list of nodes
|
|
on which the job should be allowed to be executed on.
|
|
Requires NodeLabel Parameter Plugin (optional)
|
|
* **node-label** (`str`) -- Define a label
|
|
of 'Restrict where this project can be run' on the fly.
|
|
Requires NodeLabel Parameter Plugin (optional)
|
|
* **git-revision** (`bool`) -- Pass current git-revision
|
|
to the other job (default false)
|
|
* **property-file** (`str`) -- Pass properties from file
|
|
to the other job (optional)
|
|
* **predefined-parameters** (`str`) -- Pass predefined
|
|
parameters to the other job (optional)
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- multijob:
|
|
name: PhaseOne
|
|
condition: SUCCESSFUL
|
|
projects:
|
|
- name: PhaseOneJobA
|
|
current-parameters: true
|
|
node-label-name: "vm_name"
|
|
node-label: "agent-${BUILD_NUMBER}"
|
|
git-revision: true
|
|
- name: PhaseOneJobB
|
|
current-parameters: true
|
|
property-file: build.props
|
|
- multijob:
|
|
name: PhaseTwo
|
|
condition: UNSTABLE
|
|
projects:
|
|
- name: PhaseTwoJobA
|
|
current-parameters: true
|
|
predefined-parameters: foo=bar
|
|
- name: PhaseTwoJobB
|
|
current-parameters: false
|
|
|
|
|
|
"""
|
|
builder = XML.SubElement(xml_parent, 'com.tikal.jenkins.plugins.multijob.'
|
|
'MultiJobBuilder')
|
|
XML.SubElement(builder, 'phaseName').text = data['name']
|
|
|
|
condition = data.get('condition', 'SUCCESSFUL')
|
|
XML.SubElement(builder, 'continuationCondition').text = condition
|
|
|
|
phaseJobs = XML.SubElement(builder, 'phaseJobs')
|
|
|
|
for project in data.get('projects', []):
|
|
phaseJob = XML.SubElement(phaseJobs, 'com.tikal.jenkins.plugins.'
|
|
'multijob.PhaseJobsConfig')
|
|
|
|
XML.SubElement(phaseJob, 'jobName').text = project['name']
|
|
|
|
# Pass through the current build params
|
|
currParams = str(project.get('current-parameters', False)).lower()
|
|
XML.SubElement(phaseJob, 'currParams').text = currParams
|
|
|
|
# Pass through other params
|
|
configs = XML.SubElement(phaseJob, 'configs')
|
|
|
|
nodeLabelName = project.get('node-label-name')
|
|
nodeLabel = project.get('node-label')
|
|
if (nodeLabelName and nodeLabel):
|
|
node = XML.SubElement(
|
|
configs, 'org.jvnet.jenkins.plugins.nodelabelparameter.'
|
|
'parameterizedtrigger.NodeLabelBuildParameter')
|
|
XML.SubElement(node, 'name').text = nodeLabelName
|
|
XML.SubElement(node, 'nodeLabel').text = nodeLabel
|
|
|
|
# Git Revision
|
|
if project.get('git-revision', False):
|
|
param = XML.SubElement(configs,
|
|
'hudson.plugins.git.'
|
|
'GitRevisionBuildParameters')
|
|
combine = XML.SubElement(param, 'combineQueuedCommits')
|
|
combine.text = 'false'
|
|
|
|
# Properties File
|
|
properties_file = project.get('property-file', False)
|
|
if properties_file:
|
|
param = XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'FileBuildParameters')
|
|
|
|
propertiesFile = XML.SubElement(param, 'propertiesFile')
|
|
propertiesFile.text = properties_file
|
|
|
|
failOnMissing = XML.SubElement(param, 'failTriggerOnMissing')
|
|
failOnMissing.text = 'true'
|
|
|
|
# Predefined Parameters
|
|
predefined_parameters = project.get('predefined-parameters', False)
|
|
if predefined_parameters:
|
|
param = XML.SubElement(configs,
|
|
'hudson.plugins.parameterizedtrigger.'
|
|
'PredefinedBuildParameters')
|
|
properties = XML.SubElement(param, 'properties')
|
|
properties.text = predefined_parameters
|
|
|
|
|
|
def grails(parser, xml_parent, data):
|
|
"""yaml: grails
|
|
Execute a grails build step. Requires the `Jenkins Grails Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/Grails+Plugin>`_
|
|
|
|
:arg bool use-wrapper: Use a grails wrapper (default false)
|
|
:arg str name: Select a grails installation to use (optional)
|
|
:arg bool force-upgrade: Run 'grails upgrade --non-interactive'
|
|
first (default false)
|
|
:arg bool non-interactive: append --non-interactive to all build targets
|
|
(default false)
|
|
:arg str targets: Specify target(s) to run separated by spaces
|
|
:arg str server-port: Specify a value for the server.port system
|
|
property (optional)
|
|
:arg str work-dir: Specify a value for the grails.work.dir system
|
|
property (optional)
|
|
:arg str project-dir: Specify a value for the grails.project.work.dir
|
|
system property (optional)
|
|
:arg str base-dir: Specify a path to the root of the Grails
|
|
project (optional)
|
|
:arg str properties: Additional system properties to set (optional)
|
|
:arg bool plain-output: append --plain-output to all build targets
|
|
(default false)
|
|
:arg bool stack-trace: append --stack-trace to all build targets
|
|
(default false)
|
|
:arg bool verbose: append --verbose to all build targets
|
|
(default false)
|
|
:arg bool refresh-dependencies: append --refresh-dependencies to all
|
|
build targets (default false)
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- grails:
|
|
use-wrapper: "true"
|
|
name: "grails-2.2.2"
|
|
force-upgrade: "true"
|
|
non-interactive: "true"
|
|
targets: "war ear"
|
|
server-port: "8003"
|
|
work-dir: "./grails-work"
|
|
project-dir: "./project-work"
|
|
base-dir: "./grails/project"
|
|
properties: "program.name=foo"
|
|
plain-output: "true"
|
|
stack-trace: "true"
|
|
verbose: "true"
|
|
refresh-dependencies: "true"
|
|
|
|
|
|
"""
|
|
grails = XML.SubElement(xml_parent, 'com.g2one.hudson.grails.'
|
|
'GrailsBuilder')
|
|
XML.SubElement(grails, 'targets').text = data['targets']
|
|
XML.SubElement(grails, 'name').text = data.get(
|
|
'name', '(Default)')
|
|
XML.SubElement(grails, 'grailsWorkDir').text = data.get(
|
|
'work-dir', '')
|
|
XML.SubElement(grails, 'projectWorkDir').text = data.get(
|
|
'project-dir', '')
|
|
XML.SubElement(grails, 'projectBaseDir').text = data.get(
|
|
'base-dir', '')
|
|
XML.SubElement(grails, 'serverPort').text = data.get(
|
|
'server-port', '')
|
|
XML.SubElement(grails, 'properties').text = data.get(
|
|
'properties', '')
|
|
XML.SubElement(grails, 'forceUpgrade').text = str(
|
|
data.get('force-upgrade', False)).lower()
|
|
XML.SubElement(grails, 'nonInteractive').text = str(
|
|
data.get('non-interactive', False)).lower()
|
|
XML.SubElement(grails, 'useWrapper').text = str(
|
|
data.get('use-wrapper', False)).lower()
|
|
XML.SubElement(grails, 'plainOutput').text = str(
|
|
data.get('plain-output', False)).lower()
|
|
XML.SubElement(grails, 'stackTrace').text = str(
|
|
data.get('stack-trace', False)).lower()
|
|
XML.SubElement(grails, 'verbose').text = str(
|
|
data.get('verbose', False)).lower()
|
|
XML.SubElement(grails, 'refreshDependencies').text = str(
|
|
data.get('refresh-dependencies', False)).lower()
|
|
|
|
|
|
def sbt(parser, xml_parent, data):
|
|
"""yaml: sbt
|
|
Execute a sbt build step. Requires the Jenkins `Sbt Plugin.
|
|
<https://wiki.jenkins-ci.org/display/JENKINS/sbt+plugin>`_
|
|
|
|
:arg str name: Select a sbt installation to use. If no name is
|
|
provided, the first in the list of defined SBT
|
|
builders will be used. (default to first in list)
|
|
:arg str jvm-flags: Parameters to pass to the JVM (default '')
|
|
:arg str actions: Select the sbt tasks to execute (default '')
|
|
:arg str sbt-flags: Add flags to SBT launcher
|
|
(default '-Dsbt.log.noformat=true')
|
|
:arg str subdir-path: Path relative to workspace to run sbt in (default '')
|
|
|
|
Example::
|
|
|
|
builders:
|
|
- sbt:
|
|
name: "default"
|
|
actions: "clean package"
|
|
jvm-flags: "-Xmx8G"
|
|
|
|
"""
|
|
sbt = XML.SubElement(xml_parent, 'org.jvnet.hudson.plugins.'
|
|
'SbtPluginBuilder')
|
|
XML.SubElement(sbt, 'name').text = data.get(
|
|
'name', '')
|
|
XML.SubElement(sbt, 'jvmFlags').text = data.get(
|
|
'jvm-flags', '')
|
|
XML.SubElement(sbt, 'sbtFlags').text = data.get(
|
|
'sbt-flags', '-Dsbt.log.noformat=true')
|
|
XML.SubElement(sbt, 'actions').text = data.get(
|
|
'actions', '')
|
|
XML.SubElement(sbt, 'subdirPath').text = data.get(
|
|
'subdir-path', '')
|
|
|
|
|
|
class Builders(jenkins_jobs.modules.base.Base):
|
|
sequence = 60
|
|
|
|
component_type = 'builder'
|
|
component_list_type = 'builders'
|
|
|
|
def gen_xml(self, parser, xml_parent, data):
|
|
|
|
for alias in ['prebuilders', 'builders', 'postbuilders']:
|
|
if alias in data:
|
|
builders = XML.SubElement(xml_parent, alias)
|
|
for builder in data[alias]:
|
|
self.registry.dispatch('builder', parser, builders,
|
|
builder)
|
|
|
|
# Make sure freestyle projects always have a <builders> entry
|
|
# or Jenkins v1.472 (at least) will NPE.
|
|
project_type = data.get('project-type', 'freestyle')
|
|
if project_type in ('freestyle', 'matrix') and 'builders' not in data:
|
|
XML.SubElement(xml_parent, 'builders')
|