Jenkins 2.0 Pipeline and Job DSL - jenkins

I have a Jenkins Pipeline Job which has this code :
import hudson.model.*
import hudson.util.*
import hudson.scm.*
import hudson.scm.SubversionChangeLogSet.LogEntry
stage 'Build'
node('master'){
svn 'http://mysvn/url'
def build = Thread.currentThread()?.executable
def changeSet= build.getChangeSet()
.
.
}
The code is with unchecked 'sandbox' (as it presented on the picture).
and I get this error :
groovy.lang.MissingPropertyException: No such property: executable for class: java.lang.Thread
I am not familiar with the syntax for Thread.currentThread()?.executable
what does the '?' operator means.
I google it and found out about jenkins job-dsl plugin and didn't find anything about this operator.
I also tried the Script Console Plugin at : http://localhost:8080/script
and I fail for the same reason.
Does Pipeline Plugin support the Jenkins DSL-JOB ? should I import something in order to make it work ?

Here is the related ticket and the answer from cloudbees.. Ping back from there:
def changeLogSets = currentBuild.rawBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
echo "${entry.commitId} by ${entry.author} on ${new Date(entry.timestamp)}: ${entry.msg}"
def files = new ArrayList(entry.affectedFiles)
for (int k = 0; k < files.size(); k++) {
def file = files[k]
echo " ${file.editType.name} ${file.path}"
}
}
}

It's a groovy operator, '?' is to prevent NullpointerExceptions. It does the following only if the first is not null.
The Sandbox feature is to prevent certain calls so anybody can add scripts without admin approval, but very limited...

def build = Thread.currentThread()?.executable
Firstly, the above sentence can be explained like this,
Thread.currentThread() will get the current running thread, in normal case, it will be a instance of Jenkins Executor class, there is a attribute inside this class,
/**
* {#link hudson.model.Queue.Executable} being executed right now, or null if the executor is idle.
*/
#GuardedBy("lock")
private Queue.Executable executable;
Jenkins AbstractBuild implement this interface, so it means you will actually get AbstractBuild instance back.
However, this sentence is not work for pipeline related jobs since pipe line project have different structure compared with old Jenkins jobs. It don't extend AbstractBuild class.
This is why your script is not working.
About your requirement, since there is no AbstrctBuild class, so a lot of methods are actually cannot be used, like the one you used.
No idea if there is a smart way to get the changset inside pipeline job, or maybe you need restructure your job to adapt pipeline plugin.
Br,
Tim

Related

Jenkins scripted pipeline - solution

I have a working pipeline as below however it's not working over the stages. Is there any solution to implement it into graphical mode I mean something like stage/steps in the pipeline?
def nodes = ['node1','node2', 'node3']
for (int i = 0; i < nodes.size(); i++) {
step1(nodes[i])
step2(nodes[i])
step3(nodes[i])
}
def step1(node) {
echo 'in function, calling job on node ' + node
}
def step2(node) {
echo 'in function, calling job on node ' + node
}
def step3(node) {
echo 'in function, calling job on node ' + node
}
This is a very basic functionality question.
Rather than repeating the information in existing resources like one woudl expect on SO, I'll just provide some links
Jenkins tutorial about how to achieve this: https://www.jenkins.io/doc/book/pipeline/#stage
Pipeline Step reference for "Stage" dsl command: https://www.jenkins.io/doc/pipeline/steps/pipeline-stage-step/
Please clarify your question after reading thru this material, if need be. Thanks.

How do you modify Jenkins configuration from a shared-library?

Jenkins allows us to grab a Singelton of the running instance with jenkins.get(). I'm trying to build a class in my shared-library that CRUD's the cloud providers. My code looks like this.
#NonCPS
def create(){
Jenkins jenkins = Jenkins.getInstance()
// logic to create cloud
jenkins.clouds.add(tmpCloud)
jenkins.save()
}
#NonCPS
def delete(){
Jenkins jenkins = Jenkins.getInstance()
def newlist = jenkins.clouds.findAll{ it.getDisplayName() != cloud }
if(newlist){
jenkins.clouds.clear()
}
for ( int i = 0; i < newlist.size; i++ ) {
jenkins.clouds.add(newlist[i])
}
jenkins.save()
}
If I run just the create() function the code works as expected, same if I run just the delete(), but if I run both in the same job like this.
cloud.create()
cloud.delete()
Then only the create will work, the delete wont error but it wont do anything either. Is it possible to reinitialize a singleton? I feel like that is what I need to do. I have tried saving the jenkins instance as a field of my class, but that leads to a hudson serializable error. I dont see a way to pass the jenkins singleton around because of CPS issues.

In Jenkins Delarative Pipeline, how to evaluate whether a specific directory is changed

The conditionals of Jenkins Declarative Pipeline is built around branches namely.
I would like to evaluate whether a specific folder is changed within any branch and then run the stages.
Something like:
stage {
when {
folderX changed
}
}
To give you a better idea of why I need this feature, let me elaborate.
The project I am working on exists out of a few modules (let's say micro services). Although every module can have its own branch or even repository, we have chosen to put them together in their own folders, so we can always keep everything clean in the master.
Our Jenkins pipleine has a stage for every module. However, we do not want to rebuild every module if nothing is changed in that folder.
I finally solved the problem by a script block which I found here:
when{ expression {
def changeLogSets = currentBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
def files = new ArrayList(entry.affectedFiles)
for (int k = 0; k < files.size(); k++) {
def file = files[k]
if(file.path.contains("FolderOfInterest")){
return true
}
}
}
}
return false
}
}
There are couple problems here:
The feature you're proposing does not exist. You could submit a ticket in the jenkins issue tracker for that.
Also, I think you're suggesting that you want to look at code changes across branches. This is not a standard use case for pipelines. Usually, you want to build a specific branch of a project (when it changes, for example), so you are going to feel moderate to intense pain trying to do what you're suggesting.
If you want to see what has changed on the current branch from within a Jenkisfile, you can use currentBuild.changeSets (docs). You could combine that with if statements and whatnot, within a script block if you want to use a declarative pipeline like you seem to be suggesting.
Keep at it and you'll figure it out. Good luck!

How to programmatically trigger a specific jenkins build managed via github-organization?

I am using the github-organization plugin to manage jenkins jobs from github but I discovered that Jenkins API does not report these builds.
In fact the API list the entire organization as a single job.
How can I build a specific repository and branch using the API?
To be clear, I am looking for some groovy code to add inside the Jenkinsfile
#!groovy
stage 'test-downstream'
node {
def job = build job: 'some-job'
}
Now, the problem is that Jenkins is seeing the entire organization as a single job!
If I use Jenkins API to retrieve the jobs, it will return only the organization, and not all the repositories and jobs inside it.
I suspect that's because the way this plugin was implemented and I suppose that I need to give some extra parameters in order to specify which repository and branch I want to build inside the organization.... building an organization does not make much sense.
The question is vague, but I am guessing “API” in this context means the REST API to trigger builds. You can use for example
curl -X POST -u user:apitoken http://jenkins/job/yourorg/job/yourrepo/job/master/build
The following code trigger job via System Groovy build step. Please note that system groovy always run on master so passing info from previous build steps might be tricky.
import jenkins.model.*
import hudson.model.*
import java.util.concurrent.*
def run_job(job_name) {
def currentBuild = Thread.currentThread().executable
def jenkins = jenkins.model.Jenkins.getInstance();
def job = jenkins.getItemByFullName(job_name);
if (job == null)
throw new hudson.AbortException("Cannot find job:" + job_name);
def params =[
new StringParameterValue('PARAMETER1', "invoke 1 param1"),
new StringParameterValue('PARAMETER2', ",invoke 1 param2")
]
def paramsAction = new ParametersAction(params)
def cause = new hudson.model.Cause.UpstreamCause(currentBuild)
def causeAction = new hudson.model.CauseAction(cause)
def future_build = job.scheduleBuild2(0,causeAction,paramsAction);
def running_build = future_build.waitForStart()
return running_build
}
run_job("runner1")

Access build parameters in Extended Choice Parameter - in promotion step?

When promoting a build, I want to expose some choices of how/what to promote. To do this properly, I need some info about the build which I am promoting, and I'd really like to use the Extended Choice Parameter to do this.
How can I access a build's parameters in an Extended Choice Parameter block in a build promotion step? For example, say the build I want to promote was built with a parameter myvar="1,2,5", and I want to let the build promoter select 1, 2, 5, or some combination. How can I access that particular build's myvar value, in an extended choice parameter, in a promotion process?
I can auto-populate these with available Git branches for a certain repo, with global environment variables, but I haven't seen the groovy magic I need to access info about the build I'm (about to) promote.
This was not obvious to me, but I found that environment variables such as PROMOTED_URL, PROMOTED_JOB_NAME, etc, were not available until the promotion steps were in progress. I need this information exposed when the promotion parameters are being populated via Extended Choice Parameter's Groovy Script fields. I accomplished it by peeking into the thread name:
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
def jenkins = Jenkins.instance
def thread = Thread.currentThread().toString()
def (jobName,buildNumber) = thread.replaceAll(/.*GET \/job\/(.*)\/promotion\/.*/, '$1').split('/')
def job = jenkins.getJob(jobName)
def build = job.getBuild(buildNumber)
return build.getBuildVariables()["SOME_BUILD_PARAM"]
What do I use this for? Say I can select certain targets to build but not others, when building. I want to be able to promote only some subset of those that were actually built, so the parameter can't just hold a default value. Pretty narrow edge-case, I'll grant, but sometimes it seems like my entire life, as far as Jenkins is concerned, is dealing with some edge-case or another. If there is a more elegant way, I am all ears!
building on the #courtlandj solution (with the latest hudson API):
import hudson.model.*
def paramToLookup = "SOME_BUILD_VARIABLE_NAME"
// you can of course parse the jobName from the currentThread
// but that is a case-by-case basis depending on how you name them
// build numbers are strictly numeric - and more predictable to parse with regex
def jobName = "some-jenkins-full-job-name"
int buildNumber = 0
// Similar approach to courtlandj to get THIS build number (of page being viewed):
def thisPromotionInfo = Thread.currentThread().toString()
// groovy regex that gets the promotion digits (\d)
def buildRegex = /.*\/(\d+)\/promotion\/.*/
def matcher = ( thisPromotionInfo =~ buildRegex )
if (matcher.matches()) {
buildNumber = matcher[0][1].toInteger()
} else {
return "unable to identify buildNumber in Extended Choice Parameter (see Jenkins Config)"
}
// borrowed slightly from here: https://wiki.jenkins-ci.org/display/JENKINS/Display+job+parameters
try {
def job = Hudson.instance.getItemByFullName(jobName)
def build = job.getBuildByNumber(buildNumber)
return build.getProperties()["buildVariableResolver"].resolve(paramToLookup).toString()
} catch(Exception ex) {
return ex.toString()
}
relevant links I borrowed from:
https://groups.google.com/forum/#!topic/jenkinsci-users/cHClVbjuSN4
http://groovy.jmiguel.eu/groovy.codehaus.org/Tutorial+5+-+Capturing+regex+groups.html
http://hudson-ci.org/javadoc/hudson/model/Hudson.html

Resources