Jenkins console script different results - jenkins

I am trying to get last successful build on multibranch pipeline job, and only what I came to is this
def str = Jenkins.instance.getAllItems() .findAll{ it instanceof Job }.collect{ it.getLastSuccessfulBuild() }.findAll{ it } .sort{ it.timestamp }.grep(~/iOS.*/).last().toString()
println str.substring(str.lastIndexOf('/') + 1).replace('%2F', '_').replace(' #', '_')
but unfortunately, this only works in script console of Jenkins, and throwing different results in pipeline, any guesses what could be wrong?
Jenkins version 2.176.1
I expect the output of:
feature_INC-777_77
But getting:
java.util.GregorianCalendar[time=1566913952011,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=7,WEEK_OF_YEAR=35,WEEK_OF_MONTH=5,DAY_OF_MONTH=27,DAY_OF_YEAR=239,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=52,SECOND=32,MILLISECOND=11,ZONE_OFFSET=10800000,DST_OFFSET=0]
For pipeline like:
import jenkins.model.*
import hudson.model.*
import jenkins.*
import hudson.*
def str = Jenkins.instance.getAllItems().findAll{ it instanceof Job }.collect{ it.getLastSuccessfulBuild() }.findAll{ it }.sort{it.timestamp}
println str
Can someone help with this, please?

ah this beautiful groovy + Jenkins combo...
put your statement into a method and add annotation on top #NonCPS
While I will be in trouble to get a clear full explanation, in short - jenkins push all the code in your scripted pipeline via super-complicated (as for me) set of CPS transforms - https://github.com/cloudbees/groovy-cps/ , which may or may not convert groovy API properly. Rule of thumb - when using closures - use #NonCPS annotation, otherwise you will have a ton of weird errors that are hard to debug.
more info:
https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches
https://github.com/jenkinsci/workflow-cps-plugin
What is the effect of #NonCPS in a Jenkins pipeline script

Related

Log messages are not showing up in groovy jenkins script

I'm in need to extend my jenkins scripts with logging functionality and tried to use java.util.logging for this purpose. The following snippet shows what I already did.
import java.util.logging.*
#NonCPS
def tryLogging() {
println("Start")
Logger logger = Logger.getLogger("Test")
logger.setLevel(Level.INFO);
logger.setUseParentHandlers(false);
ConsoleHandler handler = new java.util.logging.ConsoleHandler()
handler.setFormatter(new SimpleFormatter())
logger.addHandler(handler)
logger.info("Hello")
logger.severe("Severe")
println("End")
}
tryLogging()
My console log now says the following:
[Pipeline] Start of Pipeline
[Pipeline] echo
Start
[Pipeline] echo
End
There is really no visible log message and I don't know, what I'm doing wrong. Can anyone here explain me how to make the console log visible? I'm also unsure if I have to use this #NonCPS here?
[Pipeline] End of Pipeline
Finished: SUCCESS
ConsoleHandler prints to System.err. Modify your script to use
System.err.println("Start") and see if 'Start' still shows up in the console. If it doesn't then the problem is the ConsoleHandler is writing to a stream you can't see.
Another thing to change is that you'll want to ensure your named logger can't be garbage collected. Depending the Java version you are using the logger can be garbage collected and you can lose your attached handler.
I'm also unsure if I have to use this #NonCPS here?
What is #NonCPS annotation in Jenkins pipeline script has information that you might find helpful.

How to run groovy script to read build cause?

I am writing a first groovy script in the Jenkins, have an upstream job A which calls job B.
Being in job B I need to read GERRIT_CHANGE_NUMBER which triggered the job A.
In below e.g, how to get 28331 in the downstream job B?, its printed in the job B's console as below:
Started by upstream project some_up_project build number 100
originally caused by:
Triggered by Gerrit: https://gerrit-server.com/28331
I looked at this SO answer, but not sure how to do this in jenkins.
In job B, I did Add build step to add Execute system Groovy script section, then chose Groovy command in its dropdown, and in the Groovy Script area, added below for testing purpose, it gives error as unable to resolve class Run.cause ..., tried many other ways too and nothing worked.
import hudson.model.Run
for (cause in Run.getCauses()) {
if (cause instanceof Run.Cause.UserIdCause) {
println cause.getUserName()
}
}
there is no such class Run.Cause
start from something that works: hudson.model.Run
search for the documentation: hudson.model.Run.getCauses()
the method returns: List<Cause>
so, import this class into your code and use it:
import hudson.model.Cause
import hudson.model.Run
for (cause in Run.getCauses()) {
if (cause instanceof Cause.UserIdCause) {
println cause.getUserName()
}
}
Note: I have not tested the code. I just gave you an idea how to resolve an error.

Extract Jenkins pipeline from job when it's only defined in the Jenkins GUI

I have any Jenkins jobs that are written directly into Jenkins pipeline script and not directly in the SCM as is best practice.
I have been tasked with grabbing these scripts and firstly creating a backup of them.
My preference is to script the collection using python something like the below:
from utils.args import parse_arguments
from jenkinsapi.jenkins import Jenkins
args = parse_arguments()
url = "http://jmaster:8080/"
master = Jenkins(url, username=args.username, password=args.password)
for job in master.get_jobs():
print(job[0])
if (job[1]._data["_class"] == "org.jenkinsci.plugins.workflow.job.WorkflowJob"):
print "doing work"
However this is where I get stuck as I cannot see the pipeline script is exposed ? Is it even exposed as a JSON parameter that I have access to ?
I've tried looking at the jenkins api data structure no luck.
I have tried to use the rest api directly in a browser but I couldn't find the right part.
Does anyone know if this is possible or am I just chasing a dream ?
Have you tried grabbing job's config.xml files? (from like http://jmaster:8080/jobs/myjob/config.xml)
There it looks like this:
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps#2.59">
<script>node { echo 'Hello World' }</script>
<sandbox>false</sandbox>
</definition>
Or maybe you can get the CpsFlowDefinition with groovy in your original code...

Mark Jenkins Pipeline as Promoted

Last I knew, Jenkins Pipelines did not support promotions, so to work around this, I created a job called "job-name-promotion" which would gather artifacts from the job I wanted to promote, and then mark the corresponding build as "Keep Forever." Is there a way to mark the build that was kept forever as "promoted" somehow? Preferably using one of the Stars that typically denote promotions? Or even better, is there a way to add Promotion Process steps to pipelines now?
Since it appears that pipelines still do not support promotions (as of 11/21/2017), I wrote a custom groovy script to iterate over all the jobs on the Jenkins server, locate the one we wish to promote and add a gold star to the corresponding build number:
import hudson.model.*
import jenkins.model.*
import org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildAction
def log = manager.listener.logger
build = Thread.currentThread().executable
String jobName = build.project.getName()
// note: these two variables are defined as parameters of the current job
def number = manager.build.buildVariables.get("NUMBER") as int
def buildJobName = manager.build.buildVariables.get("BUILD_JOB_NAME")
Jenkins jenkins = Jenkins.getInstance()
List<Job> projects = jenkins.getAllItems(Job.class)
for (Job project : projects) {
if (project.getName().equals("platform-lanai-pipeline")) {
log.println("Found it!")
Run usb = project.getBuildByNumber(number)
usb.getActions().add(GroovyPostbuildAction.createBadge('star-gold.png', ''))
}
}

Using the ez-template plugin for Jenkins through the Jenkins Job DSL doesn't apply the template after creation

I am working on automating the creation of Jenkins jobs by using the Jenkins Job DSL (Groovy). Right now, I am trying to automate the creation of a job that uses the ez-template plugin to use an already existing template and apply that to my newly created job. However, after I am done writing the necessary configuration:
job('foo') {
properties {
templateImplementationProperty {
exclusions(['ez-templates', 'job-params', 'disabled', 'description'])
syncAssignedLabel(true)
syncBuildTriggers(true)
syncDescription(false)
syncDisabled(false)
syncMatrixAxis(true)
syncOwnership(true)
syncScm(true)
syncSecurity(true)
templateJobName('template')
}
}
}
the job gets created alright... except the template is never applied until AFTER I manually hit the save button on the UI in the newly created job. Checking the config.xml of the created job I can see that the xml contains the configuration I specified, but it was never applied.
Looking at the ez-template code, I can see that this is due to the silentSave feature that was implemented in that plugin - it writes configuration to disk without triggering any save events.
I've tried methods available to the Jenkins API but I've had no success there. Any ideas on how I can apply my configuration?
Full disclosure: I'm a co-worker, and was able to help shredmasteryjm solve this. I figured it'd be best to put this out on the net for others.
The Groovy code needed to trigger template implementation contents to be updated is:
import hudson.model.*;
import jenkins.model.*;
import com.joelj.jenkins.eztemplates.utils.TemplateUtils;
import com.joelj.jenkins.eztemplates.TemplateImplementationProperty;
Jenkins j = Jenkins.getInstance()
Item job = j.getItemByFullName('foo')
TemplateImplementationProperty template = TemplateUtils.getTemplateImplementationProperty(job)
TemplateUtils.handleTemplateImplementationSaved(job, template)
This utilizes the EZ-Templates TemplateUtils class to trigger the actual save event, using the template that the job uses. Of note, if job 'foo' doesn't implement a template, then the 'template' variable will be null, causing this code to error. YMMV
In our case, we needed to also add in some useful information from another question: Access to build environment variables from a groovy script in a Jenkins build step ( Windows)
in order to utilize a parameterized job name. As such our completed script looks like this:
import hudson.model.*;
import jenkins.model.*;
import com.joelj.jenkins.eztemplates.utils.TemplateUtils;
import com.joelj.jenkins.eztemplates.TemplateImplementationProperty;
// get current thread / Executor
def thr = Thread.currentThread()
// get current build
def build = thr?.executable
def hardcoded_param = "parameter_job_name"
def resolver = build.buildVariableResolver
def hardcoded_param_value = resolver.resolve(hardcoded_param)
Jenkins j = Jenkins.getInstance()
Item job = j.getItemByFullName(hardcoded_param_value)
TemplateImplementationProperty template = TemplateUtils.getTemplateImplementationProperty(job)
TemplateUtils.handleTemplateImplementationSaved(job, template)
FYI ez-templates 1.3.0 now triggers off additional save events such that you do not need the above trick.

Resources