What is jenkins job builder
Jenkins job builder is extreme good tool to manage your jenkins CI jobs, it takes simple description from YAML files, and use them to configure jenkins.
#set free style job
#job-template.yml
- job:
name: testjob
project-type: freestyle
defaults: global
disabled: false
display-name: 'Fancy job name'
concurrent: true
quiet-period: 5
workspace: /srv/build-area/job-name
block-downstream: false
block-upstream: false
Then put your jenkins access into jenkins.ini file
[jenkins]
user=USERNAME
password=USER_TOKEN
url=JENKINS_URL
ignore_cache=IGNORE_CACHE_FLAG
Based on the job configuration above, you just need to type command
$ jenkins-jobs --conf jenkins.ini update job-template.yaml
Then your job testjob is created in your jenkins server.
The project is created by openstack-infrastructure team, it is used to manage the openstack environment, fairly good.
How it works
There is no magic behind it, jenkins-jobs just convert the job-template.yaml to jenkins XML request file, and use jenkins remote API to send create request.
Try to do below to understand this.
$ jenkins-jobs test job-template.yaml -o .
Then xml file testjob is created, see
<?xml version="1.0" ?>
<project>
<actions/>
<description>
<!-- Managed by Jenkins Job Builder --></description>
<keepDependencies>false</keepDependencies>
<disabled>false</disabled>
<displayName>Fancy job name</displayName>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<concurrentBuild>true</concurrentBuild>
<customWorkspace>/srv/build-area/job-name</customWorkspace>
<quietPeriod>5</quietPeriod>
<canRoam>true</canRoam>
<properties/>
<scm class="hudson.scm.NullSCM"/>
<builders/>
<publishers/>
<buildWrappers/>
</project>
Now you can use curl command to send the request (testjob) directly !!
$ curl --user USER:PASS -H "Content-Type: text/xml" -s --data "@testjob" "http://jenkins-server/createItem?name=testjob"
How to recreate your jenkins job
Looks great, finally you need think about how to re-create your jenkins job, it is also simple, just download the config.xml
$ curl --user USER:PASS http://jenkins-server/testjob/config.xml
Or open the configuration page in broswer *http://jenkins-server/testjob/configure* and map from YAML file.
You need to read jenkins job builder’s guideline to know the map, generate it had level Macro like builders, which is connected to the real python builders module to do transformation from YAML to XML.
What you stated in YAML file like
-job:
name: test_job
builders:
- shell: "make test"
it will be converted to
<builders>
<hudson.tasks.Shell>
<command>make test</command></hudson.tasks.Shell>
</builders>
How to extend
Greatly to see jenkins job builder already had lots of default modules to support your normal jenkins jobs, but there is exceptions like some none popular jenkins plugins or your own plugins.
Then it is time to extend the module, the existing document: Extending is not clear enough, I will use example to show how it works, code is in github jenkins-buddy project
ArtifactDeployer Plugin is used as example, this plugin is the popular plugin to deploy the artifacts to other folder.
Artifact Deploy Plugin
And I want to have .YAML like below
*#artifactdeploy.yaml*
- job:
name: test-job
publishers:
- artifactdeployer:
includes: 'buddy-*.tar.gz'
remote: '/project/buddy'
write codes to transform
Now I need to download the existing jobs to see how XML looks like, using curl above, I got it like
<publishers>
...
<org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerPublisher plugin="artifactdeployer@0.27">
<entries>
<org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerEntry>
<includes>buddy-*.tar.gz</includes>
<basedir></basedir>
<excludes></excludes>
<remote>/project/buddy</remote>
<flatten>false</flatten>
<deleteRemote>false</deleteRemote>
<deleteRemoteArtifacts>false</deleteRemoteArtifacts>
<deleteRemoteArtifactsByScript>false</deleteRemoteArtifactsByScript>
<failNoFilesDeploy>false</failNoFilesDeploy>
</org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerEntry>
</entries>
<deployEvenBuildFail>false</deployEvenBuildFail>
</org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerPublisher>
..
</publishers>
It belongs the section publishers So I write the jenkins_buddy/modules/publishers.py module to add one function artifactdeployer:
def artifactdeployer(parser, xml_parent, data):
logger = logging.getLogger("%s:artifactdeployer" % __name__)
artifactdeployer = XML.SubElement(xml_parent, 'org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerPublisher')
entries = XML.SubElement(artifactdeployer, 'entries')
entry = XML.SubElement(entries, 'org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerEntry')
print data
XML.SubElement(entry, 'includes').text = data['includes']
XML.SubElement(entry, 'remote').text = data['remote']
It is the core part handling convert.
Hook into jenkins-job builder
Now you need hook this script into jenkins-jobs builder, thank for the entry_points in python, it can be used for this.
Create the plugin related script and structure, add new entry_point in setup.py
#setup.py in jenkins-buddy
entry_points={
'jenkins_jobs.publishers': [
'artifactdeployer=jenkins_buddy.modules.publishers:artifactdeployer',
],
}
it tells jenkins-jobs if you meet new keyword artifactdeployer in publishers, please let me jenkins_buddy.modules.publishers:artifactdeployer to handle.
Verify it
Build the pip package local and install it
$ python setup.py sdist
$ pip install dist/jenkins-buddy-0.0.5.zip
And verify the new job, Bingo, it works.
$ jenkins-jobs test artifactdeploy.yaml -o .
###Make it more complete by checking jenkins plugin java code
Maybe you noticed, it is hack solution, since I skipped some parameter converting and guess what the XML will look like, if you want to make it more complete, we need to check the java codes directly.
src/main/java/org/jenkinsci/plugins/artifactdeployer/ArtifactDeployerPublisher.java is the class we need to take care.
@DataBoundConstructor
public ArtifactDeployerPublisher(List<ArtifactDeployerEntry> deployedArtifact, boolean deployEvenBuildFail) {
this.entries = deployedArtifact;
this.deployEvenBuildFail = deployEvenBuildFail;
if (this.entries == null)
this.entries = Collections.emptyList();
}
It is directly mapping from XML into internal data, if you need know more, learn how to develop jenkins plugin.