I'm converting a Jenkins job from a manual configuration to DSL which means I'm attempting to create a DSL script which creates the job(s) as it is today.
The job is currently parameterized and one of the parameters is of the type "Build Selector for Copy Artifact". I can see in the job XML that it is the copyartifact plugin and specifically I need to use the BuildSelectorParameter.
However the Jenkins DSL API has no guidance on using this plugin to set a parameter - it only has help for using it to create a build step, which is not what I need.
I also can't find anything to do with this under the parameter options in the API.
I want to include something in the DSL seed script which will create a parameter in the generated job matching the one in the image.
parameter
If I need to use the configure block then any tips on that would be welcome to because for a beginner, the documentation on this is pretty useless.
I have found no other way to setup the build selector parameter but using the configure block. This is what I used to set it up:
freeStyleJob {
...
configure { project ->
def paramDefs = project / 'properties' / 'hudson.model.ParametersDefinitionProperty' / 'parameterDefinitions'
paramDefs << 'hudson.plugins.copyartifact.BuildSelectorParameter'(plugin: "copyartifact#1.38.1") {
name('BUILD_SELECTOR')
description('The build number to deploy')
defaultSelector(class: 'hudson.plugins.copyartifact.SpecificBuildSelector') {
buildNumber()
}
}
}
}
In order to reach that, I manually created a job with the build selector parameter. And then looked for the job's XML configuration under jenkins to look at the relevant part, in my case:
<project>
...
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
...
<hudson.plugins.copyartifact.BuildSelectorParameter plugin="copyartifact#1.38.1"
<name>BUILD_SELECTOR</name>
<description></description>
<defaultSelector class="hudson.plugins.copyartifact.SpecificBuildSelector">
<buildNumber></buildNumber>
</defaultSelector>
</hudson.plugins.copyartifact.BuildSelectorParameter>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
...
</project>
To replicate that using the configure clause you need to understand the following things:
The first argument to the configure clause is the job node.
Using the / operator will return a child of a node with the given node, if it doesn't exist gets created.
Using the << operator will append to the left-hand-side operand the node given as the right-hand-side operand.
When creating a node, you can give it the attributes in the constructor like: myNodeName(attrributeName: 'attributeValue')
You can pass a lambda to the new node and use it to populate its internal structure.
I have Jenkins version 1.6 (with copy artifact plugin) and you can do it in DSL like this:
job('my-job'){
steps{
copyArtifacts('job-id') {
includePatterns('artifact-name')
buildSelector { latestSuccessful(true) }
}
}
}
full example:
job('03-create-hive-table'){
steps{
copyArtifacts('seed-job-stash') {
includePatterns('jenkins-jobs/scripts/landing/hive/landing-table.sql')
buildSelector { latestSuccessful(true) }
}
copyArtifacts('02-prepare-landing-dir') {
includePatterns('jenkins-jobs/scripts/landing/shell/02-prepare-landing-dir.properties')
buildSelector { latestSuccessful(true) }
}
shell(readFileFromWorkspace('jenkins-jobs/scripts/landing/03-ps-create-hive-table.sh'))
}
wrappers {
environmentVariables {
env('QUEUE', 'default')
env('DB_NAME', 'table_name')
env('VERSION', '20161215')
}
credentialsBinding { file('KEYTAB', 'mycred') }
}
publishers{ archiveArtifacts('03-create-landing-hive-table.properties') }
}
I was wondering how one would do try/catch/throw type exception handling in a puppet manifest. Here's how I wish puppet would work ...
class simple {
unless ( package { 'simple': ensure => present } ) {
file { '/tmp/simple.txt':
content => template( 'simple/simple.erb' ),
}
}
}
Thanks
I don't think there is an exception handling in a programmatic way you would like in Puppet. If you declare a resource, it is expected that puppet brings your machine to that state (installed package) and if not, it will fail automatically.
One thing that you can do (and I don't recommend) and that is not "puppet way" is following:
Create custom facter (not custom function since it is executed on puppet master and you want this ruby code to be executed on puppet agent)
Since it is plain ruby code in facter, you can have exception handling and all programmatic things. You can install package as unix command from puppet code and have some logic which will, if not installed retrieve some value as fact
You would use this fact value and based on it you would determine if you want to create file or not
Also, if easier, you can write bash script which will do this logic and execute it from puppet using exec resource
Hope it helps.
I'm trying to configure the Graphite integration plugin for my jobs using Jenkins Job DSL. My block looks like this:
coreJobs = [my jobs here]
coreJobs.each{ a ->
// some extra job config here
job("$a") {
project / 'publishers' / 'org.jenkinsci.plugins.graphiteIntegrator.GraphitePublisher' {
selectedIp '192.123.1.456'
metrics {
'org.jenkinsci.plugins.graphiteIntegrator.Metric' {
queueName ".${a}.BuildFailed"
name 'BUILD_FAILED'
}
}
}
}
}
Without this graphite declaration it loops through, creating jobs using the jobs declared in $a. But because the graphite dsl requires a "name" parameter the DSL generator just ignores the jobs declared in $a and creates a job called "BUILD_FAILED" !!
So my question is how can I stop the DSL plugin trying to use the "name" parameter as a job name?
Some additional info, I don't think BUILD_FAILED should be a string. I think it's an object but I'm not sure how I would use that here or if it requires different syntax.
Thanks
After Reading the Documentation again I found an example of a conflicting element:
https://github.com/jenkinsci/job-dsl-plugin/wiki/The-Configure-Block
The doc suggests using the ‘delegate variable'. So my Code now uses:
delegate.name('BUILD_FAILED')
This now means my jobs are created with the right names and no 'BUILD_FAILED' job is generated.
I was thinking of using a Groovy script for my build job in Jenkins because I have some conditions to check for that might need access to Jenkins API.
Is it possible to find out who or what triggered the build from a Groovy script? Either an SCM change, another project or user. I have just begun reading a little about Groovy and the Jenkins API.
I want to check for the following conditions and build accordingly. Some Pseudocode:
def buildTrigger JenkinsAPI.thisBuild.Trigger
if (buildTrigger == scm) {
execute build_with_automake
def new_version = check_git_and_look_up_tag_for_version
if (new_version) {
execute git tag new_release_candidate
publish release_candidate
}
} else if (buildTrigger == "Build other projects") {
execute build_with_automake
}
The project should build on every SCM change, but only tag and publish if version has been increased. It should also build when a build has been triggered by another project.
I have something similar - I wanted to get the user who triggered the build, this is my code:
for (cause in bld.getCauses()) {
if (cause instanceof Cause.UserIdCause) {
return cause.getUserName()
}
}
(bld is subtype of Run)
So, you can get the causes for your build, and check for their type.
See the different types at Cause javadoc http://javadoc.jenkins-ci.org/hudson/model/Cause.html
Is it possible to load an external groovy script into the groovy post build plugin instead of pasting the script content into each job? We have approximately 200 jobs so updating them all is rather time consuming. I know that I could write a script to update the config files directly (as in this post: Add Jenkins Groovy Postbuild step to all jobs), but these jobs run 24x7 so finding a window when I can restart Jenkins or reload the config is problematic.
Thanks!
Just put the following in the "Groovy script:" field:
evaluate(new File("... groovy script file name ..."));
Also, you might want to go even further.
What if script name or path changes?
Using Template plugin you can create a single "template" job, define call to groovy script (above line) in there, and in all jobs that need it add post-build action called "Use publishers from another project" referencing this template project.
Update: This is what really solved it for me: https://issues.jenkins-ci.org/browse/JENKINS-21480
"I am able to do just that by doing the following. Enter these lines in lieu of the script in the "Groovy script" box:"
// Delegate to an external script
// The filename must match the class name
import JenkinsPostBuild
def postBuild = new JenkinsPostBuild(manager)
postBuild.run()
"Then in the "Additional groovy classpath" box enter the path to that file."
We do it in the following fashion.
We have a file c:\somepath\MyScriptLibClass.groovy (accessible for Jenkins) which contains code of a groovy class MyScriptLibClass. The class contains a number of functions designed to act like static methods (to be mixed in later).
We include this functions writing the following statement in the beginning of sytem groovy and postbuild groovy steps:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
This could look a bit ugly but you need to write it only once for script. You could include more than one script and also use inheritance between library classes.
Here you see that all methods from the library class are mixed in the current script. So if your class looks like:
class MyScriptLibClass {
def setBuildName( String str ){
binding?.variables['manager'].build.displayName = str
}
}
in Groovy Postbuild you could write just:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
setBuildName( 'My Greatest Build' )
and it will change your current build's name.
There are also other ways to load external groovy classes and it is not necessary to use mixing in. For instance you can take a look here Compiling and using Groovy classes from Java at runtime?
How did I solve this:
Create file $JENKINS_HOME/scripts/PostbuildActions.groovy with following content:
public class PostbuildActions {
void setBuildName(Object manager, String str ){
binding?.variables['manager'].build.displayName = str
}
}
In this case in Groovy Postbuild you could write:
File script = new File("${manager.envVars['JENKINS_HOME']}/scripts/PostbuildActions.groovy")
Object actions = new GroovyClassLoader(getClass().getClassLoader()).parseClass(script).newInstance();
actions.setBuildName(manager, 'My Greatest Build');
If you wish to have the Groovy script in your Code Repository, and loaded onto the Build / Test Slave in the workspace, then you need to be aware that Groovy Postbuild runs on the Master.
For us, the master is a Unix Server, while the Build/Test Slaves are Windows PCs on the local network. As a result, prior to using the script, we must open a channel from the master to the Slave, and use a FilePath to the file.
The following worked for us:
// Get an Instance of the Build object, and from there
// the channel from the Master to the Workspace
build = Thread.currentThread().executable
channel = build.workspace.channel;
// Open a FilePath to the script
fp = new FilePath(channel, build.workspace.toString() + "<relative path to the script in Unix notation>")
// Some have suggested that the "Not NULL" check is redundant
// I've kept it for completeness
if(fp != null)
{
// 'Evaluate' requires a string, so read the file contents to a String
script = fp.readToString();
// Execute the script
evaluate(script);
}
I've just faced with the same task and tried to use #Blaskovicz approach.
Unfortunately it does not work for me, but I find upgraded code here (Zach Auclair)
Publish here with minor changes:
postbuild task
//imports
import hudson.model.*
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import java.io.File;
// define git file
def postBuildFile = manager.build.getEnvVars()["WORKSPACE"] + "/Jenkins/SimpleTaskPostBuildReporter.GROOVY"
def file = new File(postBuildFile)
// load custom class from file
Class groovy = this.class.classLoader.parseClass(file);
// create custom object
GroovyObject groovyObj = (GroovyObject) groovy.newInstance(manager);
// do report
groovyObj.report();
postbuild class file in git repo (SimpleTaskPostBuildReporter.GROOVY)
class SimpleTaskPostBuildReporter {
def manager
public SimpleTaskPostBuildReporter(Object manager){
if(manager == null) {
throw new RuntimeException("Manager object can't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}
I haven't tried this exactly.
You could try the Jenkins Job DSL plugin which allows you to rebuild jobs from within jenkins using a Groovy DSL and supports post build groovy steps directly from the wiki
Groovy Postbuild
Executes Groovy scripts after a build.
groovyPostBuild(String script, Behavior behavior = Behavior.DoNothing)
Arguments:
script The Groovy script to execute after the build. See the plugin's
page for details on what can be done. behavior optional. If the script
fails, allows you to set mark the build as failed, unstable, or do
nothing. The behavior argument uses an enum, which currently has three
values: DoNothing, MarkUnstable, and MarkFailed.
Examples:
This example will run a groovy script that prints hello, world and if
that fails, it won't affect the build's status:
groovyPostBuild('println "hello, world"') This example will run a
groovy script, and if that fails will mark the build as failed:
groovyPostBuild('// some groovy script', Behavior.MarkFailed) This example
will run a groovy script, and if that fails will mark the
build as unstable:
groovyPostBuild('// some groovy script', Behavior.MarkUnstable) (Since 1.19)
There is a facility to use a template job (this is the bit I haven't tried) which could be the job itself so you only need to add the post build step. If you don't use a template you need to recode the whole project.
My approach is to have a script to regenerate or create all jobs from scratch just so I don't have to apply the same upgrade multiple times. Regenerated jobs keep their build history
I was able to get the following to work (I also posted on this jira issue).
in my postbuild task
this.class.classLoader.parseClass("/home/jenkins/GitlabPostbuildReporter.groovy")
GitlabPostbuildReporter.newInstance(manager).report()
in my file on disk at /home/jenkins/GitlabPostbuildReporter.groovy
class GitlabPostbuildReporter {
def manager
public GitlabPostbuildReporter(manager){
if(manager == null) {
throw new RuntimeException("Manager object musn't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}