Jenkins fails on periodic build with Dynamic Choice Parameter Groovy script - groovy

I'm trying to use the Dynamic Choice Parameter plugin to set up a parameterized build in Jenkins. The parameters should be the names of some directory's in a directory of the working directory of the job (i.e. /var/lib/jenkins/workspace/JobName/dirToScan/).
Making the items in the drop down menu can be done in this way:
def list = ['ls', "/path/to/dirToScan/"].execute().text.tokenize()
To reach the right directory, I need the name of the job since, as opposed to when a job is executed, the directory in which the this is done is not the /var/lib/jenkins/workspace/[Job Name]/ directory but the root dir /.
The Dynamic Choice Parameter plugin allows the execution of a Groovy script to fill the choice parameter. Using the answer provided here I was able to retrieve the job name. So my final code to build the drop-down menu in the parameterized build menu in Jenkins looks like this:
def build = Thread.currentThread().toString()
def regexp= ".+?/job/([^/]+)/.*"
def match = build =~ regexp
def jobName = match[0][1]
def list = ['ls', "/var/lib/jenkins/workspace/" << jobName << "/dirToScan"].execute().text.tokenize()
Clicking the Build with Parameters link in the Jenkins job opens the page with the drop-down menu (which I named Restore) and also the actual building works great!
But now comes my problem:
If set the job to be build periodically, the build fails with the following console output:
Started by timer
Building in workspace /var/lib/jenkins/workspace/JobName
FATAL: Null value not allowed as an environment variable: Restore
java.lang.IllegalArgumentException: Null value not allowed as an environment variable: Restore
at hudson.EnvVars.put(EnvVars.java:356)
at hudson.model.StringParameterValue.buildEnvironment(StringParameterValue.java:56)
at hudson.model.ParametersAction.buildEnvVars(ParametersAction.java:88)
at hudson.model.AbstractBuild.getEnvironment(AbstractBuild.java:929)
at hudson.plugins.mercurial.MercurialSCM.checkout(MercurialSCM.java:533)
at hudson.scm.SCM.checkout(SCM.java:484)
at hudson.model.AbstractProject.checkout(AbstractProject.java:1270)
at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:609)
at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:86)
at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:531)
at hudson.model.Run.execute(Run.java:1750)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
at hudson.model.ResourceController.execute(ResourceController.java:89)
at hudson.model.Executor.run(Executor.java:240)
Finished: FAILURE
This does not happen if I just populate the drop-down menu in a 'normal' way, e.g.: def list = ["Option 1", "Option 2", "Option 3"]
This might be a bug in the plugin, or Jenkins being unable to execute the Groovy code if it starts a job by itself. The problem only occurs with a periodic build, not if I start the build myself and it it independent of the chosen option in the drop-down menu. Does anyone have an idea on how to fix this?

Related

How to set a string name for pipeline build in jenkins

I am running jenkins on a linux machine.
I have a pipeline job in place, so each pipeline build shows build number in general. Instead of that is it possible to give string parameter to display on the UI ?
I have tried checking build parameter plugin, but in pipeline configuration i don't see option to inject the string parameter. And the documentation doesn't help.
You can set the build name by doing:
currentBuild.displayName = "#${currentBuild.number} Hello"
This will name the build #2 Hello for build number 2.
For my case, i had to add a line in my pipeline groovy script
node(Slave01) {
currentBuild.displayName = "${URL_Name}"
}
${URL_Name} = here is the parameter

Jenkins + Build Flow, how to pass a variable from one job to another

I have a build flow scenario similar to the documentation example: two jobs, one running after the other.
b = build("job1")
build("job2", param1: b.????)
My job1 is a shell script that builds a package out of a checked out git repositoy and prints out the version of the built package.
I need to extract the version from job1 (parse output??) and make it available somehow as a parameter to job2. How can this be achieved? Please note that I can't know the version before running job1.
The problem with simply using export in a shell script build step is that the exported variables disappear when the shell script exits, they are not propagated up to the job.
Use the EnvInject plugin to create environment variables in your build. If you
write out a properties file as part of your build, EnvInject can read the file and inject variables as a build step. A properties file has a simple KEY=VALUE format:
MY_BUILD_VERSION=some_parsed_value
Once you have an environment variable set in your job, in the Build Flow
plugin, you can extract the variable's value and use it in subsequent jobs:
def version = build.environment.get( "MY_BUILD_VERSION" )
out.println String.format("Parameters: version: %s", version)
build( "My Second Build", MY_BUILD_VERSION: version )
When you run job1 export the version with name as system property.
export appVersion="stringOfVersion-123"
Then it depend if you know how long is version (count of numbers or others characters). If you know it you can parse variable from end in second build as new variable and use it.
How parse string you can find in this question with nice examples.
If job2 always should get some information from job1 you could use approach without parameters. job1 could publish artifact with version and job2 will use that artifact (with Copy Artifact Plugin for example). With that approach job2 could be executed also as standalone job.
For anyone else coming upon this, another solution is to use a scriptler script, where you pass in the .properties file path, and the script will add the properties to the list of job variables:
Properties properties = new Properties()
FilePath workspace = build.getWorkspace()
FilePath sourceFile = workspace.child(path)
properties.load(sourceFile.read())
properties.each { key, value ->
key = key.replace(".", "_").toUpperCase()
Job.setVariable(build, key, value)
println "Created Variable: " + key + "=" + value
}
This will convert any periods to underscores, and capitalize all letters. Using a scriptler script ensures that you have a method that works independent of the "plugin soup" you are using.

Jenkins using File Parameter with MultiJob Project

I am using the MultiJob Project in order to implement a process the runs every time there is a push to a certain Git branch.
How can I pass parameters between 2 different jobs (each job is located in a separate MultiJob Phase)
What i tried to do is:
Job A: (Run on the Master - windows)
echo 2 parameters into a new file (Called parameters.properties) that i placed in a shared location (not in the workspace of Job A)
so this file's contnet looks like:
currentBuild=2012-11-27_09-20-50
currentBranch=master
Job B: (Run on a Linux Slave)
The option of "This build is parametrized" is on.
Added "File Parameter" and only the file name as I also set a custom workspace to the shared location where the file is located.
The i have a shell script that tries to use this parametrs but it doesnt get it.
Please Assist,
Doron
The Solution:
in the MultiJob Main Project:
Set "This build is parametrized"
Add 2 Text Parameters (different names since the Job Build is based on Jenkins variable Build_Id which is changed and i want later to set the currentBuild to a constant value and not to a new one)
JobBuild
JobBranch
On each Job under each MultiJob Phase:
Add Predefined Parameters:
currentBuild=${JobBuild}
currentBranch=${JobBranch}
untick the "Current job parameters"
untick the Exposed SCM"

How to get specific information about the current build project in Jenkins with Groovy?

In Jenkins/Hudson, with the help of a Postbuild Groovy script, I would like to get one of the following:
an environment variable (e.g. current JOB_NAME, BUILD_NUMBER etc.)
the result of a specific build number of the current project
the build number of the last not successful build in the current project
At the moment I only found the following way, but it's rather limited:
def item = hudson.model.Hudson.instance.getItem("GroovyMultipleFailTest")
def build = item.getLastBuild()
build.getNumber()
Using Jenkins v2.17 this works for me:
echo "BUILD_NUMBER=${env.BUILD_NUMBER}"
${manager.build.getEnvironment(manager.listener)['BUILD_NUMBER'] }
Bo Persson had the best answer, but was a little short.
To access the environment variables from the build in the Groovy Postbuild, you can grab them from the build. This sample code is useful for dumping all of the BUILD's environment variables to the console:
manager.build.getEnvironment(manager.listener).each {
manager.listener.logger.println(it);
}
If you're using Groovy script within "Env Inject", you can get current build and current job by:
currentJob.getName()
currentBuild.toString()
an environment variable (e.g. current JOB_NAME, BUILD_NUMBER etc.)
String jobName = System.getenv('JOB_NAME')
The only way I got it to work for me was with build.properties.environment.BUILD_NUMBER
I tried various approaches in this article and others, and it looks like the only one put below and also build.properties.environment.BUILD_NUMBER (upvoted) are working for me in Jenkins Execute system Groovy Script build step groovy command type
EnvVars envVars = build.getEnvironment(listener)
def n = envVars.get('BUILD_NUMBER')

On a build of a Jenkins job, is it possible to change build parameters midway through?

We are using Jenkins to automate several of our build and test processes. For some of our process, the engineer starting the build needs to specify a parameter. But the range of possible and optimal values for that parameter change throughout the course of the day.
What I would like to do is let the engineer specify a value - if they know an optimal value - or leave it blank and have a value be calculated by an early build step. If the value is calculated, I would like the calculating build step to update the parameter value of the job. That way, all subsequent build steps don't have to worry about using the parameter or calculating it, they just use the parameter regardless.
It looks like the Groovy Script Plugin might be able to do this, but I can't see how I can SET the build parameters, just GET them.
Found the answer: use the EnvInject Plugin. One of the features is a build step that allows you to "inject" parameters into the build job from a settings file. I used one build step to create the settings file, then another build step to inject the new values. Then, all subsequent build steps and post-build operations used the new value.
Update with an example:
To add a new parameter (REPORT_FILE), based on existing one (JOB_NAME), inject a map with new or modified parameters in the Groovy Script box:
// Setting a map for new build parameters
def paramsMap = [:]
// Set REPORT_FILE based on JOB_NAME
def filename = JOB_NAME.replace(' ','_') + ".html"
paramsMap.put("REPORT_FILE", filename)
// Add or modify other parameters...
return paramsMap
Jenkins does have the ability to parameterize builds. For a string parameter, the developer can leave the field blank and then your build scripts can check to see if the env. variable for the parameter is set. If the env. var. is not set, the script can perform whatever calculation is needed (I don't think Jenkins has "pre-build steps") and pass it along. For a choice parameter the first line can be something like (Default), and again the build script can test its value and act accordingly.
Note on (Default)
I tried leaving the first line of the choice box blank, and Jenkins saved it correctly the first time; but when I came back to reconfigure the build Jenkins ran some kind of trim on options and the leading blank line was removed so I settled on (Default).
I hope this helps,
Zachary

Resources