Adding existing Jobs to a MultiJob - jenkins

The Jenkins Job DSL plugin (version 1.42) allows defining MultiJobs:
multiJob('MyMultiJob'){
steps{
phase('First')
phaseJob('JobA'){
#job configuration
}
}
}
}
Is it possible to define a job and add it to a MultiJob in separate steps like in the following example?
jobA = job('JobA')
multiJob('MyMultiJob'){
steps{
phase('First')
jobA
}
}
}
Being forced to define many different jobs inside the MultiJob definition seems complicated and adds a lot of complexity. Are there workarounds? Is it possible to move the definition of a phase job to a function outside the MultiJob definition?

You can do this
def j= {
parameters {
propertiesFile('my1.properties')
}
}
multiJob('example') {
steps {
phase('First') {
phaseJob('JobZ', j)
}
phase('Second') {
phaseJob('JobA', j)
phaseJob('JobB')
phaseJob('JobC')
}
}
}
Which you can use 'j'. The closure syntax outside the parameters is syntactic sugar and the method call assumes the closure is in fact the last parameter
Output from the job dsl playground
<com.tikal.jenkins.plugins.multijob.MultiJobProject plugin='jenkins-multijob-plugin#1.8'>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties></properties>
<scm class='hudson.scm.NullSCM'></scm>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers class='vector'></triggers>
<concurrentBuild>false</concurrentBuild>
<builders>
<com.tikal.jenkins.plugins.multijob.MultiJobBuilder>
<phaseName>Second</phaseName>
<continuationCondition>SUCCESSFUL</continuationCondition>
<phaseJobs>
<com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<jobName>JobZ</jobName>
<currParams>true</currParams>
<exposedSCM>true</exposedSCM>
<disableJob>false</disableJob>
<killPhaseOnJobResultCondition>FAILURE</killPhaseOnJobResultCondition>
<configs>
<hudson.plugins.parameterizedtrigger.FileBuildParameters>
<propertiesFile>my1.properties</propertiesFile>
<failTriggerOnMissing>false</failTriggerOnMissing>
</hudson.plugins.parameterizedtrigger.FileBuildParameters>
</configs>
</com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
</phaseJobs>
</com.tikal.jenkins.plugins.multijob.MultiJobBuilder>
<com.tikal.jenkins.plugins.multijob.MultiJobBuilder>
<phaseName>Third</phaseName>
<continuationCondition>SUCCESSFUL</continuationCondition>
<phaseJobs>
<com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<jobName>JobA</jobName>
<currParams>true</currParams>
<exposedSCM>true</exposedSCM>
<disableJob>false</disableJob>
<killPhaseOnJobResultCondition>FAILURE</killPhaseOnJobResultCondition>
<configs>
<hudson.plugins.parameterizedtrigger.FileBuildParameters>
<propertiesFile>my1.properties</propertiesFile>
<failTriggerOnMissing>false</failTriggerOnMissing>
</hudson.plugins.parameterizedtrigger.FileBuildParameters>
</configs>
</com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<jobName>JobB</jobName>
<currParams>true</currParams>
<exposedSCM>true</exposedSCM>
<disableJob>false</disableJob>
<killPhaseOnJobResultCondition>FAILURE</killPhaseOnJobResultCondition>
<configs class='java.util.Collections$EmptyList'></configs>
</com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
<jobName>JobC</jobName>
<currParams>true</currParams>
<exposedSCM>true</exposedSCM>
<disableJob>false</disableJob>
<killPhaseOnJobResultCondition>FAILURE</killPhaseOnJobResultCondition>
<configs class='java.util.Collections$EmptyList'></configs>
</com.tikal.jenkins.plugins.multijob.PhaseJobsConfig>
</phaseJobs>
</com.tikal.jenkins.plugins.multijob.MultiJobBuilder>
</builders>
<publishers></publishers>
<buildWrappers></buildWrappers>
</com.tikal.jenkins.plugins.multijob.MultiJobProject>

Related

Can I run parallel actions from a plain Groovy method in my Jenkins pipeline?

My Jenkins pipeline is specified in a declarative way. However, in the place I'd like to introduce a parallel step in, I'm forced down into plain Groovy methods:
def call(Map parameters) {
runFirstStep(parameters)
// add second step that runs in parallel to runFirstStep
}
Unexperienced as I am with Groovy and Jenkins, I hoped to make something simple like this work:
def call(Map parameters) {
parallel(
'First step': {
runFirstStep(parameters)
},
'Second step': {
runSecondStep(parameters)
}
)
}
However, this seems to mix up declarative and imperative code in an unsuited way and leads to cryptic NullPointerExceptions.
Is there another, feasible solution for this? Or is overriding the declarative part that surrounds this the only option to squeeze in another parallel step?
def call(Map parameters) {
def steps = [:]
steps['First step'] = {
node('master') {
runFirstStep(parameters)
}
}
steps['Second step'] = {
node('master') {
runSecondStep(parameters)
}
}
parallel steps.plus([failFast: true])
}

jenkins dsl job script: How to access environment variable, (which is injected via propertiesFile, ) in downstreamParameterized step

my dsl job script in brief
job('test') {
steps {
shell('echo VERSION=$VERSION > version.txt\n' +
'echo VERSION_SUFFIX=$VERSION_SUFFIX >> version.txt\n' +
'echo GROUP_ID=$GROUP_ID >> version.txt')
// EnvInject Plugin
environmentVariables {
propertiesFile('version.txt')
}
}
publishers {
postBuildScripts {
steps {
shell('echo ${VERSION}')
}
onlyIfBuildSucceeds(false)
onlyIfBuildFails(false)
}
downstreamParameterized {
trigger('next-job') {
parameters {
predefinedProp('relVersion', '${VERSION}')
}
}
}
}
}
I need $VERSION number to pass to the downstream job a parameter.
I tried, ${env.VERSION} and also tried many options, but i couldn't catch the VERSION . any help is appreciated, thanks in advance.
You can use the option Prepare an environment for the run which is executed before SCM.
Option Prepare an environment for the run is not belongs pre-build/ build /post build, but job properties.
There is no job DSL API supports to configure this option. But we can use configure block.
job('next-job') {
configure { project ->
project / 'properties' << 'EnvInjectJobProperty' {
info {
loadFilesFromMaster false
propertiesContent 'Branch=${relVersion}'
}
keepBuildVariables true
keepJenkinsSystemVariables true
overrideBuildParameters false
on true
}
} // end of configure block
scm {
git {
remote {
url("ssh://git#bitbucket.rl.git")
}
branches('${branch}')
}
} // end of scm
steps {}
publishers {}
}
Above job DSL can generate following xml as the content of seed job's config.xml
<project>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties>
<EnvInjectJobProperty>
<info>
<loadFilesFromMaster>false</loadFilesFromMaster>
<propertiesContent>Branch=${relVersion}</propertiesContent>
</info>
<keepBuildVariables>true</keepBuildVariables>
<keepJenkinsSystemVariables>true</keepJenkinsSystemVariables>
<overrideBuildParameters>false</overrideBuildParameters>
<on>true</on>
</EnvInjectJobProperty>
</properties>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers></triggers>
<concurrentBuild>false</concurrentBuild>
<builders></builders>
<publishers></publishers>
<buildWrappers></buildWrappers>
<scm class='hudson.plugins.git.GitSCM'>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>ssh://git#bitbucket.rl.git</url>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>${branch}</name>
</hudson.plugins.git.BranchSpec>
</branches>
<configVersion>2</configVersion>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<gitTool>Default</gitTool>
</scm>
</project>
You can try jod DSL on http://job-dsl.herokuapp.com/ to check generated xml from it as expect or not.

How to replace github branch inside jenkins job scm from parameter value

I have a jenkins job groovy script like below. I want the Github branch to be taken from the parameter value.
Groovy Script :
git_url = "git#github.deere.com:ABC/XYZ.git" jenkins_node = "master"
freeStyleJob('myjob') {
logRotator(numToKeep = 100)
parameters { stringParam("GIT_BRANCH", "master" , "master cert dev") }
label(jenkins_node)
scm {
git {
remote { url(git_url) }
branch($GIT_BRANCH)
extensions { }
}
}
You have to put $GIT_BRANCH variable into single quotes so it is not get parsed by job DSL script. Paste your script to this Job DSL playground app and you will get an exception:
javaposse.jobdsl.dsl.DslScriptException: (script, line 12) No such property: $GIT_BRANCH for class: javaposse.jobdsl.dsl.helpers.scm.GitContext
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:112)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader$_runScripts_closure1.doCall(AbstractDslScriptLoader.groovy:59)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
at javaposse.jobdsl.dsl.AbstractDslScriptLoader$runScripts$0.callCurrent(Unknown Source)
But if you add single quotes:
branch('$GIT_BRANCH')
then you will get your job XML file generated correctly:
<!-- 1. myjob -->
<project>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>GIT_BRANCH</name>
<defaultValue>master</defaultValue>
<description>master cert dev</description>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<canRoam>false</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers></triggers>
<concurrentBuild>false</concurrentBuild>
<builders></builders>
<publishers></publishers>
<buildWrappers></buildWrappers>
<logRotator>
<daysToKeep>100</daysToKeep>
<numToKeep>-1</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</logRotator>
<assignedNode>master</assignedNode>
<scm class='hudson.plugins.git.GitSCM'>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>git#github.deere.com:ABC/XYZ.git</url>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>$GIT_BRANCH</name>
</hudson.plugins.git.BranchSpec>
</branches>
<configVersion>2</configVersion>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<gitTool>Default</gitTool>
</scm>
</project>
Here is job DSL I used in the sandbox:
git_url = "git#github.deere.com:ABC/XYZ.git"
jenkins_node = "master"
freeStyleJob('myjob') {
logRotator(numToKeep = 100)
parameters {
stringParam("GIT_BRANCH", "master" , "master cert dev")
}
label(jenkins_node)
scm {
git {
remote { url(git_url) }
branch('$GIT_BRANCH')
extensions { }
}
}
}
Now when you run a job generated from this DSL it will ask you for GIT_BRANCH parameter and the value you pass will be used to set up the branch.

Reuse maven step in Jenkins Job DSL

I am using the Job DSL to define a job that requires multiple maven steps to be run. This is an example:
def mavenInst = 'maven-3x'
job('test') {
steps{
maven {
mavenInstallation(mavenInst)
goals('fuu')
}
maven {
mavenInstallation(mavenInst)
goals('bar')
}
// more steps of the same form.
maven {
mavenInstallation(mavenInst)
goals('fuu bar')
}
}
}
So, much of code is repeated quite often.
Is it possible to extract the respective parts of the job description and call them from within the Job DSL? I imagine something like this:
def mavenInst = 'maven-3x'
job('test') {
steps{
myCustomStep('fuu')
myCustomStep('bar')
// more steps of the same form.
myCustomStep('fuu bar')
}
}
This would result in significantly less code and would be easier to change in the future.
I have read that the steps need some sort of context but I can not figure out how to do it. I tried to extract the block into a configure closure as this:
def fuubar = { it ->
mavenInstallation(mavenInst)
goals('fuu bar')
}
But when I call the element with configure fuubar, nothing is shown in the resulting job configure.xml.
Any help would be appreciated.
I would think you can do this
job('test') {
steps {
maven {
mavenInstallation('maven-3x')
goals('fuu')
goals('bar')
goals('fuu bar')
}
}
}
based on the excellent help
and also in the dsl playground
which gives you this
<!-- 1. test -->
<project>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties></properties>
<scm class='hudson.scm.NullSCM'></scm>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers class='vector'></triggers>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Maven>
<targets>fuu bar fuu bar</targets>
<mavenName>maven-3x</mavenName>
<jvmOptions></jvmOptions>
<usePrivateRepository>false</usePrivateRepository>
</hudson.tasks.Maven>
</builders>
<publishers></publishers>
<buildWrappers></buildWrappers>
</project>
EDIT
Rereading your question it seems this is an example.
The above could also be written
def goal_names = ['fuu', 'bar', 'fuu bar']
job('test') {
steps {
maven {
mavenInstallation('maven-3x')
goal_names.each { goal ->
goals(goal)
}
}
}
}
EDIT 2 to use separate steps
def goal_names = ['fuu', 'bar', 'fuu bar']
job('test') {
steps {
goal_names.each { goal ->
maven {
mavenInstallation('maven-3x')
goals(goal)
}
}
}
}
XML
<!-- 1. test -->
<project>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties></properties>
<scm class='hudson.scm.NullSCM'></scm>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers class='vector'></triggers>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Maven>
<targets>fuu</targets>
<mavenName>maven-3x</mavenName>
<jvmOptions></jvmOptions>
<usePrivateRepository>false</usePrivateRepository>
</hudson.tasks.Maven>
<hudson.tasks.Maven>
<targets>bar</targets>
<mavenName>maven-3x</mavenName>
<jvmOptions></jvmOptions>
<usePrivateRepository>false</usePrivateRepository>
</hudson.tasks.Maven>
<hudson.tasks.Maven>
<targets>fuu bar</targets>
<mavenName>maven-3x</mavenName>
<jvmOptions></jvmOptions>
<usePrivateRepository>false</usePrivateRepository>
</hudson.tasks.Maven>
</builders>
<publishers></publishers>
<buildWrappers></buildWrappers>
</project>
I managed to tackle that since I got similar issue and I wanted to have reusable methods with customization. I am not sure whether it is possible to encapsulate multiples steps in a method but you can encapsulate closure like this:
Closure runInLatestInstallation(String moduleName, String mavenGoals) {
return {
rootPOM("${moduleName}/pom.xml")
goals(mavenGoals)
mavenInstallation('Latest')
}
}
and you can call it like this:
maven runInLatestInstallation(moduleName, 'versions:update-parent')

Jenkins Job DSL: how to build particular node in Configure block?

The particular thing I want is to prevent some steps from execution in Flexible Publish section. I use a condition of strings (not) matching and I don't want something to be executed after check fails.
Being configured manually, expected step looks like this:
Expected postbuild step
As I have not found an appropriate method in Jenkins Jobs DSL API I've tried to reproduce it using the Configure block. The reference says that I can use 'project' for root element of the job and 'node' for particular node to append a child to them. It says also that new nodes won't be created again if pointed nodes exist. So here's my config:
job("flexible_condition") {
publishers {
flexiblePublish {
configure { node ->
node / publishers /
'org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher' << 'runner'(class:
'org.jenkins_ci.plugins.run_condition.BuildStepRunner$DontRun')
}
condition {
not { stringsMatch('string_placeholder', '', false) }
}
publisher {
debianPackage('common') {
commitMessage('new feature')
}
}
publisher {
git {
pushOnlyIfSuccess(true)
branch('origin', 'master')
}
}
}
}
}
In spite of the reference desirable xml aren't generated in my jenkins neither in the Playground. I've got nodes duplicated instead and it seems that 'node' is interpreted as 'project' and is always put to the root.
<!-- 1. flexible_condition -->
<project>
<actions></actions>
<description></description>
<keepDependencies>false</keepDependencies>
<properties></properties>
<scm class='hudson.scm.NullSCM'></scm>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers class='vector'></triggers>
<concurrentBuild>false</concurrentBuild>
<builders></builders>
<publishers>
<org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
<runner class='org.jenkins_ci.plugins.run_condition.BuildStepRunner$DontRun'></runner>
</org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
<org.jenkins__ci.plugins.flexible__publish.FlexiblePublisher>
<publishers>
<org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
<condition class='org.jenkins_ci.plugins.run_condition.logic.Not'>
<condition class='org.jenkins_ci.plugins.run_condition.core.StringsMatchCondition'>
<arg1>string_placeholder</arg1>
<arg2></arg2>
<ignoreCase>false</ignoreCase>
</condition>
</condition>
<publisherList>
<ru.yandex.jenkins.plugins.debuilder.DebianPackagePublisher>
<repoId>common</repoId>
<commitMessage>new feature</commitMessage>
<commitChanges>true</commitChanges>
</ru.yandex.jenkins.plugins.debuilder.DebianPackagePublisher>
<hudson.plugins.git.GitPublisher>
<configVersion>2</configVersion>
<pushMerge>false</pushMerge>
<pushOnlyIfSuccess>true</pushOnlyIfSuccess>
<forcePush>false</forcePush>
<tagsToPush></tagsToPush>
<branchesToPush>
<hudson.plugins.git.GitPublisher_-BranchToPush>
<targetRepoName>origin</targetRepoName>
<branchName>master</branchName>
</hudson.plugins.git.GitPublisher_-BranchToPush>
</branchesToPush>
</hudson.plugins.git.GitPublisher>
</publisherList>
<runner class='org.jenkins_ci.plugins.run_condition.BuildStepRunner$Fail'></runner>
</org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
</publishers>
</org.jenkins__ci.plugins.flexible__publish.FlexiblePublisher>
</publishers>
<buildWrappers></buildWrappers>
</project>
I've been checking this example in the Playground via Job DSL version 1.40 but 1.39 in my jenkins gives the same result.
What am doing wrong?
Thank you.
UPD I've put the configure block below as SevenEleven suggested and it almost helped. The runner node is on the right place now but is still duplicated.
<publishers>
<org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
<condition .../>
<publisherList>
...
</publisherList>
<runner class='org.jenkins_ci.plugins.run_condition.BuildStepRunner$Fail'></runner>
<runner class='org.jenkins_ci.plugins.run_condition.BuildStepRunner$DontRun'></runner>
</org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher>
</publishers>
UPD 2 Although there are two different lines in the xml, the newer runner replaces the default one in generated job. So I've got the expected result. Thanks.
UPD 3. Yay! Found out that now one can simply use JobDSL syntax and it works.
publishers {
flexiblePublish {
conditionalAction {
condition {
not { stringsMatch('string_placeholder', '', false) }
}
publishers {
debianPackage('common') {
commitMessage('Automatic Commit')
}
git {
pushOnlyIfSuccess(true)
branch('origin', '$GIT_BRANCH')
}
}
runner('DontRun')
}
}
}
To edit the configuration, you have to place the configure-block below, not inside the publishers configuration:
job("flexible_condition") {
publishers {
flexiblePublish {
//...
}
}
configure {
it / publishers / 'org.jenkins__ci.plugins.flexible__publish.FlexiblePublisher' / publishers / 'org.jenkins__ci.plugins.flexible__publish.ConditionalPublisher' / 'runner'(class:'org.jenkins_ci.plugins.run_condition.BuildStepRunner$DontRun') {
}
}
}

Resources