jenkins-job-builder/jenkins_jobs/modules/builders.py

341 lines
12 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
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
Example::
builders:
- copyartifact:
project: foo
filter: *.tar.gz
"""
t = XML.SubElement(xml_parent, 'hudson.plugins.copyartifact.CopyArtifact')
XML.SubElement(t, 'projectName').text = data["project"]
XML.SubElement(t, 'filter').text = data.get("filter", "")
XML.SubElement(t, 'target').text = data.get("target", "")
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 str ant-name: the name of the ant installation,
defaults to 'default' (optional)
Example specifying the build file too and several targets::
builders:
- ant:
targets: "debug test install"
buildfile: "build.xml"
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
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 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 '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')
propfile = data.get('properties-file', '')
XML.SubElement(info, 'propertiesFilePath').text = propfile
propcontent = data.get('properties-content', '')
XML.SubElement(info, 'propertiesContent').text = propcontent
def artifact_resolver(parser, xml_parent, data):
"""yaml: artifact-resolver
Allows 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'
class Builders(jenkins_jobs.modules.base.Base):
sequence = 60
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._dispatch('builder', 'builders',
parser, builders, builder)