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') {
}
}
}
Related
I'm trying to use a simple FreeStyleJob SCM , and set the credentialId UUID from build parameter. The problem is, it seems the credentials is not parsing the parameter correctly.
scm {
git {
remote {
github('\${MY_REPO_HANDLE}', 'ssh')
credentials('\${MY_REPO_CREDENTIALS}')
}
branch('\${MY_BRANCH}')
}
}
My MY_REPO_CREDENTIALS is a simple String parameter
stringParam {
name("MY_REPO_CREDENTIALS")
defaultValue("teste-credential")
}
Log:
Warning: CredentialId "${MY_REPO_CREDENTIALS}" could not be found.
UPDATE
This Jenkins Job is created by another Jenkins Job using DSL external. In resume, Job 1 whenn triggered will create the Job 2 on jenkins. When I try to use "$ (without \) the job will fail because this parameter doesn't exist on Job 1 context.
job config.xml:
<scm class="hudson.plugins.git.GitSCM">
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>git#github.com:${MY_REPO_HANDLE}.git</url>
<credentialsId>${MY_REPO_CREDENTIALS}</credentialsId>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>${MY_BRANCH}</name>
</hudson.plugins.git.BranchSpec>
</branches>
<configVersion>2</configVersion>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<gitTool>Default</gitTool>
<browser class="hudson.plugins.git.browser.GithubWeb">
<url>https://github.com/${MY_REPO_HANDLE}/</url>
</browser>
</scm>
The final solution was set the ssh agent before build, using wrapper:
wrappers {
sshAgent("\${MY_REPO_CREDENTIALS}")
}
keepDependencies(false)
scm {
git {
remote {
github("\${MY_REPO_HANDLE}", 'ssh')
}
branch("\${MY_BRANCH}")
}
}
You can switch to using " instead of ' so you can use the autofill feature:
scm {
git {
remote {
github("${MY_REPO_HANDLE}", 'ssh')
credentials("${MY_REPO_CREDENTIALS}")
}
branch("${MY_BRANCH}")
}
}
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.
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>
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')
I'd like to use Copy/Paste Detector in my Gradle build.
This is why I've decided to translate the following Ant task (which I've found here) into Gradle syntax:
<target name="cpd">
<taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />
<cpd minimumTokenCount="100" outputFile="/home/tom/cpd.txt">
<fileset dir="/home/tom/tmp/ant">
<include name="**/*.java"/>
</fileset>
</cpd>
</target>
This is how the translation looks currently:
check << {
ant.taskdef(name: 'cpd', classname: 'net.sourceforge.pmd.cpd.CPDTask', classpath: configurations.pmd.asPath)
ant.cpd(minimumTokenCount: '100', outputFile: file('build/reports/pmd/copyPasteDetector.txt').toURI().toString()) {
fileset(dir: 'src'){
include(name: '**.java')
}
}
}
Unfortunately calling gradle check yields an net.sourceforge.pmd.cpd.ReportException, the stacktrace is here.
How can I scan my source code with the Copy/Paste Detector using Gradle 1.9?
Thanks!
You can also use my gradle-cpd-plugin. See https://github.com/aaschmid/gradle-cpd-plugin for further informationen. Applying the cpd plugin automatically adds it the cpd as dependency of check task.
Note: I am not very happy with the name cpd for extension (see toolVersion) and task, suggestions welcome ;-)
Currently, it is version 0.1 but I am on it to switch from using CPD's ant task internally to directly call it. This will include support of all parameters etc. Here is a usage example:
apply plugin: 'cpd'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'de.aaschmid.gradle.plugins:gradle-cpd-plugin:0.1'
}
}
// optional - default is 5.1.0
cpd {
toolVersion = '5.0.5'
}
tasks.cpd {
reports {
text.enabled = true
xml.enabled = false
}
source = files('src/main/java')
}
Guys from gradle forums suggest that you use CPD in gradle like that:
task cpd(dependsOn: ':pmdSetup') {
// Combine all source sets
allSource = files {
allprojects.findAll { proj ->
proj.hasProperty("sourceSets")
}.collect { proj ->
proj.sourceSets.collect { ss ->
ss.java
}
}
}
// Declare this task's inputs and outputs.
inputs.files allSource
outDir = file("$buildDirName/cpd")
outputs.dir outDir
// outputs.files file("$outDir.path/cpd.xml")
doLast {
outDir.mkdirs()
// Keep a reference to the gradle project for use inside the
// ant closure, where "project" refers to the ant project.
gproj = project
ant {
cpd(minimumTokenCount: '100', format: 'xml',
outputFile: outDir.path + '/cpd.xml') {
fileset(dir: projectDir.getPath()) {
// Convert the gradle sourceSet to an ant
// fileset.
allSource.each { file ->
include(name: gproj.relativePath(file))
}
}
}
}
}
}
and, of course, apply plugin: 'pmd' before.
The definition of my outputFile caused the problem.
I adapted this build.gradle and I'm now happy with the following solution:
check << {
File outDir = new File('build/reports/pmd/')
// Make sure the output dir exists to prevent a ReportException
outDir.mkdirs()
ant.taskdef(name: 'cpd', classname: 'net.sourceforge.pmd.cpd.CPDTask',
classpath: configurations.pmd.asPath)
ant.cpd(minimumTokenCount: '100', format: 'text',
outputFile: new File(outDir , 'cpd.txt')) {
fileset(dir: "src/main/java") {
include(name: '**/*.java')
}
}
}
Thanks Andrey Regentov and Perryn Fowler for their input.